From 50c2b2938904c95e5ed5ee045885fc05dba23e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Sun, 20 Feb 2005 15:02:48 +0000 Subject: [PATCH] Import from Wine svn path=/trunk/; revision=13686 --- reactos/tools/widl/Makefile.in | 51 + reactos/tools/widl/hash.c | 621 +++++++ reactos/tools/widl/hash.h | 33 + reactos/tools/widl/header.c | 855 ++++++++++ reactos/tools/widl/header.h | 44 + reactos/tools/widl/parser.h | 41 + reactos/tools/widl/parser.l | 442 +++++ reactos/tools/widl/parser.y | 1362 +++++++++++++++ reactos/tools/widl/proxy.c | 1057 ++++++++++++ reactos/tools/widl/proxy.h | 26 + reactos/tools/widl/typelib.c | 274 +++ reactos/tools/widl/typelib.h | 92 + reactos/tools/widl/typelib_struct.h | 598 +++++++ reactos/tools/widl/utils.c | 197 +++ reactos/tools/widl/utils.h | 45 + reactos/tools/widl/widl.c | 305 ++++ reactos/tools/widl/widl.h | 57 + reactos/tools/widl/widl.man | 71 + reactos/tools/widl/widltypes.h | 258 +++ reactos/tools/widl/write_msft.c | 2403 +++++++++++++++++++++++++++ 20 files changed, 8832 insertions(+) create mode 100644 reactos/tools/widl/Makefile.in create mode 100644 reactos/tools/widl/hash.c create mode 100644 reactos/tools/widl/hash.h create mode 100644 reactos/tools/widl/header.c create mode 100644 reactos/tools/widl/header.h create mode 100644 reactos/tools/widl/parser.h create mode 100644 reactos/tools/widl/parser.l create mode 100644 reactos/tools/widl/parser.y create mode 100644 reactos/tools/widl/proxy.c create mode 100644 reactos/tools/widl/proxy.h create mode 100644 reactos/tools/widl/typelib.c create mode 100644 reactos/tools/widl/typelib.h create mode 100644 reactos/tools/widl/typelib_struct.h create mode 100644 reactos/tools/widl/utils.c create mode 100644 reactos/tools/widl/utils.h create mode 100644 reactos/tools/widl/widl.c create mode 100644 reactos/tools/widl/widl.h create mode 100644 reactos/tools/widl/widl.man create mode 100644 reactos/tools/widl/widltypes.h create mode 100644 reactos/tools/widl/write_msft.c diff --git a/reactos/tools/widl/Makefile.in b/reactos/tools/widl/Makefile.in new file mode 100644 index 00000000000..df682580cd7 --- /dev/null +++ b/reactos/tools/widl/Makefile.in @@ -0,0 +1,51 @@ +TOPSRCDIR = @top_srcdir@ +TOPOBJDIR = ../.. +SRCDIR = @srcdir@ +VPATH = @srcdir@ +LEXOPT = -Cf #-w -b +YACCOPT = #-v +EXEEXT = @EXEEXT@ + +PROGRAMS = widl$(EXEEXT) +MODULE = none + +C_SRCS = \ + hash.c \ + header.c \ + proxy.c \ + typelib.c \ + utils.c \ + widl.c \ + write_msft.c + +EXTRA_SRCS = parser.y parser.l +EXTRA_OBJS = y.tab.o @LEX_OUTPUT_ROOT@.o + +all: $(PROGRAMS) + +@MAKE_RULES@ + +widl$(EXEEXT): $(OBJS) $(LIBDIR)/wpp/libwpp.a + $(CC) $(CFLAGS) -o $@ $(OBJS) -L$(LIBDIR) -lwpp -lwine_port $(LEXLIB) $(LDFLAGS) + +y.tab.c y.tab.h: parser.y + $(YACC) $(YACCOPT) -d -t $(SRCDIR)/parser.y + +# hack to allow parallel make +y.tab.h: y.tab.c +y.tab.o: y.tab.h + +@LEX_OUTPUT_ROOT@.c: parser.l + $(LEX) $(LEXOPT) -d -8 $(SRCDIR)/parser.l + +@LEX_OUTPUT_ROOT@.o: y.tab.h + +install:: $(PROGRAMS) + $(MKINSTALLDIRS) $(bindir) $(mandir)/man$(prog_manext) + $(INSTALL_PROGRAM) widl$(EXEEXT) $(bindir)/widl$(EXEEXT) + $(INSTALL_DATA) $(SRCDIR)/widl.man $(mandir)/man$(prog_manext)/widl.$(prog_manext) + +uninstall:: + $(RM) $(bindir)/widl$(EXEEXT) $(mandir)/man$(prog_manext)/widl.$(prog_manext) + +### Dependencies: diff --git a/reactos/tools/widl/hash.c b/reactos/tools/widl/hash.c new file mode 100644 index 00000000000..aeaff068fa5 --- /dev/null +++ b/reactos/tools/widl/hash.c @@ -0,0 +1,621 @@ +/* + * Oleaut32 hash functions + * + * Copyright 1999 Corel Corporation + * Copyright 2001-2003 Jon Griffiths + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" + +#include "hash.h" + +static const unsigned char Lookup_16[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + + /* Windows */ + 0x7F, 0x7F, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x8C, + 0x7F, 0x7F, 0x7F, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x7F, 0x7F, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x55, 0xDE, 0x55, + + /* Mac */ + 0x41, 0x41, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0x41, 0x4F, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x41, 0x4F, 0xBD, 0x41, 0x4F, 0xC0, + 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x41, 0x41, 0x4F, + 0xCE, 0xCE, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x55, 0x55, 0xDA, + 0xDB, 0xDC, 0xDD, 0x3F, 0x3F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x41, 0x45, 0x41, + 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F, 0x3F, 0x4F, 0x55, 0x55, 0x55, + 0x49, 0x7F, 0xF7, 0x7F, 0xF9, 0xFA, 0xFB, 0x3F, 0xFD, 0xFE, 0x7F +}; + +static const unsigned char Lookup_32[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + + /* Windows */ + 0x7F, 0x7F, 0x82, 0x7F, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x53, + 0x54, 0x5A, 0x5A, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x7F, 0x99, + 0x53, 0x9B, 0x53, 0x54, 0x5A, 0x5A, 0xA0, 0x7F, 0xA2, 0x4C, 0xA4, 0x41, 0xA6, + 0xA7, 0xA8, 0xA9, 0x53, 0xAB, 0xAC, 0x96, 0xAE, 0x5A, 0xB0, 0xB1, 0xB2, 0x4C, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x41, 0x53, 0xBB, 0x4C, 0xBD, 0x4C, 0x5A, 0x52, + 0x41, 0x41, 0x41, 0x41, 0x4C, 0x43, 0x43, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, + 0x49, 0x44, 0xD0, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x52, 0x55, 0x55, + 0x55, 0x55, 0x59, 0x54, 0xDF, 0x52, 0x41, 0x41, 0x41, 0x41, 0x4C, 0x43, 0x43, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x44, 0xD0, 0x4E, 0x4E, 0x4F, 0x4F, + 0x4F, 0x4F, 0xF7, 0x52, 0x55, 0x55, 0x55, 0x55, 0x59, 0x54, 0xFF, + + /* Mac */ + 0x41, 0x41, 0x41, 0x45, 0x41, 0x4F, 0x55, 0x41, 0x41, 0x43, 0x41, 0x43, 0x43, + 0x43, 0x45, 0x5A, 0x5A, 0x44, 0x49, 0x44, 0x45, 0x45, 0x45, 0x4F, 0x45, 0x4F, + 0x4F, 0x4F, 0x55, 0x45, 0x45, 0x55, 0xA0, 0xA1, 0x45, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0x45, 0xAC, 0xAD, 0x47, 0x49, 0x49, 0x49, 0xB2, 0xB3, + 0x49, 0x4B, 0xB6, 0xB7, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4C, 0x4E, 0x4E, + 0x4E, 0xC2, 0xC3, 0x4E, 0x4E, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0x4E, 0x4F, 0x4F, + 0x4F, 0x4F, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x4F, 0x52, 0x52, + 0x52, 0xDC, 0xDD, 0x52, 0x52, 0x52, 0x53, 0xE2, 0xE3, 0x53, 0x53, 0x53, 0x41, + 0x54, 0x54, 0x49, 0x5A, 0x5A, 0x55, 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x59, 0x59, 0x4B, 0x5A, 0x4C, 0x4C, 0x47, 0xFF +}; + +static const unsigned char Lookup_48[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + + /* Windows */ + 0x7F, 0x7F, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x7F, 0x89, 0x53, 0x8B, 0x8C, + 0x7F, 0x7F, 0x7F, 0x7F, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x96, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x7F, 0x7F, 0x59, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x59, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0x55, 0x59, 0xDE, 0x59, + + /* Mac */ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, + 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAB, 0xAD, 0xAE, 0xAE, 0xB0, 0xB1, 0xB2, 0xB3, + 0xA7, 0xB5, 0xB6, 0xB7, 0xB8, 0xB8, 0xBA, 0xBA, 0xBC, 0xBC, 0xBE, 0xBE, 0xB7, + 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCB, 0xCD, + 0xCD, 0xC1, 0xD0, 0xD0, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD8, 0xDA, + 0xDA, 0xDC, 0xDD, 0xDD, 0x9F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F +}; + +static const unsigned char Lookup_64[128 * 3] = { + /* Common */ + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* Mac */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x96, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0x55, 0x55, 0xDE, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char Lookup_80[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + + /* Mac */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, +}; + +static const unsigned char Lookup_112[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x00, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x56, 0x58, 0x55, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + + /* Mac */ + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, +}; + +static const unsigned char Lookup_128[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + +/* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x00, 0x8B, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x00, 0x99, + 0x00, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x00, 0xAB, 0xAC, 0x2D, 0xAE, 0x2D, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xBA, + 0xA2, 0xC2, 0xC3, 0xC4, 0xB8, 0xC6, 0xB9, 0xC8, 0xBA, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xBC, 0xD0, 0xD1, 0x00, 0xD3, 0xD4, 0xBE, 0xD6, 0xD7, 0xD8, 0xBF, 0xBA, + 0xBE, 0xA2, 0xB8, 0xB9, 0xBA, 0xBE, 0xA2, 0xC2, 0xC3, 0xC4, 0xB8, 0xC6, 0xB9, + 0xC8, 0xBA, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xBC, 0xD0, 0xD1, 0xD3, 0xD3, 0xD4, + 0xBE, 0xD6, 0xD7, 0xD8, 0xBF, 0xBA, 0xBE, 0xBC, 0xBE, 0xBF, 0x00, + + /* Mac */ + 0x41, 0x31, 0x32, 0x45, 0x33, 0x4F, 0x55, 0x87, 0x41, 0x41, 0x41, 0x00, 0x8C, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x92, 0x93, 0x49, 0x49, 0x96, 0x97, 0x98, 0x4F, + 0x4F, 0x9B, 0x3F, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xAB, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xB0, + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0x09, 0xBD, 0xCC, 0xB0, + 0xB6, 0xCF, 0x2D, 0x2D, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xB8, 0xAB, 0xC3, 0xBD, + 0xB6, 0xB8, 0xAB, 0xC3, 0xBF, 0xBD, 0xB0, 0xB5, 0xBE, 0xA2, 0xB6, 0xBC, 0xA1, + 0xB8, 0xAB, 0xA5, 0xBA, 0xA4, 0xBB, 0xC1, 0xC3, 0xA6, 0xBF, 0xC4, 0xAA, 0xC6, + 0xA3, 0xBF, 0xAA, 0xCC, 0xBD, 0xB7, 0xAB, 0xBD, 0xAB, 0xBD, 0x3F, +}; + +static const unsigned char Lookup_144[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + +/* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0xDA, + 0x55, 0x55, 0xDD, 0xDE, 0xDF, 0x41, 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, + 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, + 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0xDA, 0x55, 0x55, 0xDD, 0xDE, 0x59, + + /* Mac */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0xDA, + 0x55, 0x55, 0xDD, 0xDE, 0xDF, 0x41, 0xC1, 0x41, 0x41, 0x41, 0x41, 0xC6, 0x43, + 0x45, 0xC9, 0x45, 0x45, 0x49, 0xCD, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0xD3, 0x4F, + 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0xDA, 0x55, 0x55, 0xDD, 0xDE, 0x59, +}; + +static const unsigned char Lookup_160[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + +/* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0xD6, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0xDC, 0xDD, 0xDE, 0x59, + + /* Mac */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0x4F, 0x55, 0x55, + 0x55, 0xDC, 0xDD, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0xC6, 0xC7, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0xD0, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0xD6, 0xF7, 0x4F, 0x55, 0x55, 0x55, 0xDC, 0xDD, 0xDE, 0x59, +}; + +static const unsigned char Lookup_176[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x00, + + /* Windows */ + 0x00, 0x00, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x00, 0x89, 0x53, 0x8B, 0x8C, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x2D, 0x2D, 0x98, 0x99, + 0x53, 0x9B, 0x8C, 0x00, 0x00, 0x59, 0x09, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0x41, 0xAB, 0xAC, 0x2D, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0x4F, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0x41, + 0x41, 0x41, 0x41, 0xC4, 0xC5, 0xC4, 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, + 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, 0x4F, 0xD6, 0xD7, 0xD6, 0x55, 0x55, + 0x55, 0x59, 0x59, 0xDE, 0xDF, 0x41, 0x41, 0x41, 0x41, 0xC4, 0xC5, 0xC4, 0x43, + 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x44, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0xD6, 0xF7, 0xD6, 0x55, 0x55, 0x55, 0x59, 0x59, 0xDE, 0x59, + + /* Mac */ + 0x80, 0x81, 0x43, 0x45, 0x4E, 0x85, 0x59, 0x41, 0x41, 0x41, 0x80, 0x41, 0x81, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, + 0x85, 0x4F, 0x55, 0x55, 0x55, 0x59, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0x80, 0x85, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0x41, 0x4F, 0xBD, 0x80, 0x85, 0xC0, + 0xC1, 0xC2, 0xC3, 0x46, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0x09, 0x41, 0x41, 0x4F, + 0xCE, 0xCE, 0x2D, 0x2D, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0x59, 0x59, 0xDA, + 0xDB, 0xDC, 0xDD, 0x3F, 0x3F, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0x41, 0x45, 0x41, + 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4F, 0x4F, 0x3F, 0x4F, 0x55, 0x55, 0x55, + 0x49, 0x00, 0xF7, 0x00, 0xF9, 0xFA, 0xFB, 0x3F, 0xFD, 0xFE, 0x00 +}; + +static const unsigned char Lookup_208[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x80, 0x81, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x5E, 0x89, 0x8A, 0x8B, 0x8C, + 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0x9B, 0x8C, 0x9D, 0x00, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC7, 0xC8, 0xC9, 0xC9, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0x00, 0xDD, 0xDE, 0xDF, 0x41, 0xE1, 0x41, 0xE3, 0xE4, 0xE5, 0xE6, 0x43, + 0x45, 0x45, 0x45, 0x45, 0xEC, 0xEC, 0x49, 0x49, 0xF0, 0xF1, 0xF2, 0xF3, 0x4F, + 0xF5, 0xF6, 0xF7, 0xF8, 0x55, 0xFA, 0x55, 0x55, 0x00, 0x00, 0xFF, + + /* Mac */ + 0x41, 0x81, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x8B, 0x8C, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x93, 0x49, 0x49, 0x4E, 0x4F, 0x98, 0x4F, + 0x4F, 0x9B, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC1, 0xC1, 0xC1, 0xC1, 0xC7, 0xC8, 0xC9, 0xC9, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x00, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xE9, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, + 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, +}; + +static const unsigned char Lookup_224[128 * 3] = { + /* Common */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, + 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, + 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, + 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, + 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + +/* Windows */ + 0x80, 0x81, 0x82, 0x46, 0x84, 0x85, 0x86, 0x87, 0x5E, 0x89, 0x8A, 0x8B, 0x8C, + 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0x32, 0x33, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0x31, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEA, 0xEC, 0xED, 0xED, 0xEF, 0xEF, 0xF1, 0xF2, 0xF3, 0xF3, + 0xF5, 0xF5, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0x00, 0x00, 0xFF, + + /* Mac */ + 0x41, 0x41, 0x43, 0x45, 0x4E, 0x4F, 0x55, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x43, 0x45, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49, 0x4E, 0x4F, 0x4F, 0x4F, + 0x4F, 0x4F, 0x55, 0x55, 0x55, 0x55, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEA, 0xEC, 0xED, 0xED, 0xEF, 0xEF, 0xF1, 0xF2, 0xF3, 0xF3, + 0xF5, 0xF5, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, +}; + +/*********************************************************************** + * lhash_val_of_name_sys + * + * Copy of oleaut32.LHashValOfNameSysA + * Produce a string hash value. + * + * PARAMS + * skind [I] Type of the system. + * lcid [I] Locale id for the hash. + * lpStr [I] String to hash. + * + * RETURNS + * Success: The hash value of the string. + * Failure: 0, if lpStr is NULL. + * + * NOTES + * This function produces a two part hash: The high word is based on + * skind and lcid, while the low word is based on a repeated string + * hash of skind/str. + */ +unsigned long lhash_val_of_name_sys( syskind_t skind, LCID lcid, LPCSTR lpStr) +{ + ULONG nOffset, nMask = skind == SYS_MAC ? 1 : 0; + ULONG nHiWord, nLoWord = 0x0deadbee; + const unsigned char *str = (const unsigned char *)lpStr, *pnLookup = NULL; + + if (!str) + return 0; + + switch (PRIMARYLANGID(LANGIDFROMLCID(lcid))) + { + default: + fprintf(stderr, "Unknown lcid %lx, treating as latin-based, please report\n", lcid); + /* .. Fall Through .. */ + case LANG_AFRIKAANS: case LANG_ALBANIAN: case LANG_ARMENIAN: + case LANG_ASSAMESE: case LANG_AZERI: case LANG_BASQUE: + case LANG_BELARUSIAN: case LANG_BENGALI: case LANG_BULGARIAN: + case LANG_CATALAN: case LANG_DANISH: case LANG_DIVEHI: + case LANG_DUTCH: case LANG_ENGLISH: case LANG_ESTONIAN: + case LANG_FAEROESE: case LANG_FINNISH: case LANG_FRENCH: + case LANG_GALICIAN: case LANG_GEORGIAN: case LANG_GERMAN: + case LANG_GUJARATI: case LANG_HINDI: case LANG_INDONESIAN: + case LANG_ITALIAN: case LANG_KANNADA: case LANG_KASHMIRI: + case LANG_KAZAK: case LANG_KONKANI: case LANG_KYRGYZ: + case LANG_LATVIAN: case LANG_LITHUANIAN: case LANG_MACEDONIAN: + case LANG_MALAY: case LANG_MALAYALAM: case LANG_MANIPURI: + case LANG_MARATHI: case LANG_MONGOLIAN: case LANG_NEPALI: + case LANG_ORIYA: case LANG_PORTUGUESE: case LANG_PUNJABI: + case LANG_ROMANIAN: case LANG_SANSKRIT: case LANG_SERBIAN: + case LANG_SINDHI: case LANG_SLOVENIAN: case LANG_SWAHILI: + case LANG_SWEDISH: case LANG_SYRIAC: case LANG_TAMIL: + case LANG_TATAR: case LANG_TELUGU: case LANG_THAI: + case LANG_UKRAINIAN: case LANG_URDU: case LANG_UZBEK: + case LANG_VIETNAMESE: case LANG_GAELIC: case LANG_MALTESE: + case LANG_MAORI: case LANG_RHAETO_ROMANCE: + case LANG_SAAMI: case LANG_SORBIAN: case LANG_SUTU: + case LANG_TSONGA: case LANG_TSWANA: case LANG_VENDA: + case LANG_XHOSA: case LANG_ZULU: case LANG_ESPERANTO: + case LANG_WALON: case LANG_CORNISH: case LANG_WELSH: + case LANG_BRETON: + nOffset = 16; + pnLookup = Lookup_16; + break; + case LANG_CZECH: case LANG_HUNGARIAN: case LANG_POLISH: + case LANG_SLOVAK: case LANG_SPANISH: + nOffset = 32; + pnLookup = Lookup_32; + break; + case LANG_HEBREW: + nOffset = 48; + pnLookup = Lookup_48; + break; + case LANG_JAPANESE: + nOffset = 64; + pnLookup = Lookup_64; + break; + case LANG_KOREAN: + nOffset = 80; + pnLookup = Lookup_80; + break; + case LANG_CHINESE: + nOffset = 112; + pnLookup = Lookup_112; + break; + case LANG_GREEK: + nOffset = 128; + pnLookup = Lookup_128; + break; + case LANG_ICELANDIC: + nOffset = 144; + pnLookup = Lookup_144; + break; + case LANG_TURKISH: + nOffset = 160; + pnLookup = Lookup_160; + break; + case LANG_NORWEGIAN: + if (SUBLANGID(LANGIDFROMLCID(lcid)) == SUBLANG_NORWEGIAN_NYNORSK) + { + nOffset = 176; + pnLookup = Lookup_176; + } + else + { + nOffset = 16; + pnLookup = Lookup_16; + } + break; + case LANG_ARABIC: + case LANG_FARSI: + nOffset = 208; + pnLookup = Lookup_208; + break; + case LANG_RUSSIAN: + nOffset = 224; + pnLookup = Lookup_224; + break; + } + + nHiWord = (nOffset | nMask) << 16; + + while (*str) + { + ULONG newLoWord = 0, i; + + /* Cumulative prime multiplication (*37) with modulo 2^32 wrap-around */ + for (i = 0; i < 37; i++) + newLoWord += nLoWord; + + nLoWord = newLoWord + pnLookup[*str > 0x7f && nMask ? *str + 0x80 : *str]; + str++; + } + /* Constrain to a prime modulo and sizeof(WORD) */ + nLoWord = (nLoWord % 65599) & 0xffff; + + return nHiWord | nLoWord; +} diff --git a/reactos/tools/widl/hash.h b/reactos/tools/widl/hash.h new file mode 100644 index 00000000000..de91849ebc6 --- /dev/null +++ b/reactos/tools/widl/hash.h @@ -0,0 +1,33 @@ +/* + * Hash definitions + * + * Copyright 2005 Huw Davies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __WIDL_HASH_H +#define __WIDL_HASH_H + +typedef enum tag_syskind_t { + SYS_WIN16 = 0, + SYS_WIN32, + SYS_MAC +} syskind_t; + +extern unsigned long lhash_val_of_name_sys( syskind_t skind, LCID lcid, LPCSTR lpStr); + +#endif diff --git a/reactos/tools/widl/header.c b/reactos/tools/widl/header.c new file mode 100644 index 00000000000..67ea841dbdb --- /dev/null +++ b/reactos/tools/widl/header.c @@ -0,0 +1,855 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#include "windef.h" +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" + +static int indentation = 0; + +static void indent(int delta) +{ + int c; + if (delta < 0) indentation += delta; + for (c=0; c 0) indentation += delta; +} + +int is_attr(attr_t *a, enum attr_type t) +{ + while (a) { + if (a->type == t) return 1; + a = NEXT_LINK(a); + } + return 0; +} + +void *get_attrp(attr_t *a, enum attr_type t) +{ + while (a) { + if (a->type == t) return a->u.pval; + a = NEXT_LINK(a); + } + return NULL; +} + +unsigned long get_attrv(attr_t *a, enum attr_type t) +{ + while (a) { + if (a->type == t) return a->u.ival; + a = NEXT_LINK(a); + } + return 0; +} + +int is_void(type_t *t, var_t *v) +{ + if (v && v->ptr_level) return 0; + if (!t->type && !t->ref) return 1; + return 0; +} + +static void write_pident(FILE *h, var_t *v) +{ + int c; + for (c=0; cptr_level; c++) { + fprintf(h, "*"); + } + if (v->name) fprintf(h, "%s", v->name); +} + +void write_name(FILE *h, var_t *v) +{ + if (is_attr( v->attrs, ATTR_PROPGET )) + fprintf(h, "get_" ); + else if (is_attr( v->attrs, ATTR_PROPPUT )) + fprintf(h, "put_" ); + fprintf(h, "%s", v->name); +} + +char* get_name(var_t *v) +{ + return v->name; +} + +static void write_array(FILE *h, expr_t *v, int field) +{ + if (!v) return; + while (NEXT_LINK(v)) v = NEXT_LINK(v); + fprintf(h, "["); + while (v) { + if (v->is_const) + fprintf(h, "%ld", v->cval); /* statically sized array */ + else + if (field) fprintf(h, "1"); /* dynamically sized array */ + if (PREV_LINK(v)) + fprintf(h, ", "); + v = PREV_LINK(v); + } + fprintf(h, "]"); +} + +static void write_field(FILE *h, var_t *v) +{ + if (!v) return; + if (v->type) { + indent(0); + write_type(h, v->type, NULL, v->tname); + if (get_name(v)) { + fprintf(h, " "); + write_pident(h, v); + } + else { + /* not all C/C++ compilers support anonymous structs and unions */ + switch (v->type->type) { + case RPC_FC_STRUCT: + case RPC_FC_CVSTRUCT: + case RPC_FC_CPSTRUCT: + case RPC_FC_CSTRUCT: + case RPC_FC_PSTRUCT: + case RPC_FC_BOGUS_STRUCT: + case RPC_FC_ENCAPSULATED_UNION: + fprintf(h, " DUMMYSTRUCTNAME"); + break; + case RPC_FC_NON_ENCAPSULATED_UNION: + fprintf(h, " DUMMYUNIONNAME"); + break; + default: + /* ? */ + break; + } + } + write_array(h, v->array, 1); + fprintf(h, ";\n"); + } +} + +static void write_fields(FILE *h, var_t *v) +{ + var_t *first = v; + if (!v) return; + while (NEXT_LINK(v)) v = NEXT_LINK(v); + while (v) { + write_field(h, v); + if (v == first) break; + v = PREV_LINK(v); + } +} + +static void write_enums(FILE *h, var_t *v) +{ + if (!v) return; + while (NEXT_LINK(v)) v = NEXT_LINK(v); + while (v) { + if (get_name(v)) { + indent(0); + write_name(h, v); + if (v->eval) { + fprintf(h, " = "); + write_expr(h, v->eval); + } + } + if (PREV_LINK(v)) + fprintf(h, ",\n"); + v = PREV_LINK(v); + } + fprintf(h, "\n"); +} + +void write_type(FILE *h, type_t *t, var_t *v, char *n) +{ + int c; + + if (n) fprintf(h, "%s", n); + else { + if (t->is_const) fprintf(h, "const "); + if (t->type) { + if (t->sign > 0) fprintf(h, "signed "); + else if (t->sign < 0) fprintf(h, "unsigned "); + switch (t->type) { + case RPC_FC_BYTE: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "byte"); + break; + case RPC_FC_CHAR: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "char"); + break; + case RPC_FC_WCHAR: + fprintf(h, "wchar_t"); + break; + case RPC_FC_USHORT: + case RPC_FC_SHORT: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "short"); + break; + case RPC_FC_ULONG: + case RPC_FC_LONG: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "long"); + break; + case RPC_FC_HYPER: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "hyper"); + break; + case RPC_FC_FLOAT: + fprintf(h, "float"); + break; + case RPC_FC_DOUBLE: + fprintf(h, "double"); + break; + case RPC_FC_ENUM16: + case RPC_FC_ENUM32: + if (t->defined && !t->written) { + if (t->name) fprintf(h, "enum %s {\n", t->name); + else fprintf(h, "enum {\n"); + t->written = TRUE; + indentation++; + write_enums(h, t->fields); + indent(-1); + fprintf(h, "}"); + } + else fprintf(h, "enum %s", t->name); + break; + case RPC_FC_ERROR_STATUS_T: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "error_status_t"); + break; + case RPC_FC_BIND_PRIMITIVE: + if (t->ref) fprintf(h, t->ref->name); + else fprintf(h, "handle_t"); + break; + case RPC_FC_STRUCT: + case RPC_FC_CVSTRUCT: + case RPC_FC_CPSTRUCT: + case RPC_FC_CSTRUCT: + case RPC_FC_PSTRUCT: + case RPC_FC_BOGUS_STRUCT: + case RPC_FC_ENCAPSULATED_UNION: + if (t->defined && !t->written) { + if (t->name) fprintf(h, "struct %s {\n", t->name); + else fprintf(h, "struct {\n"); + t->written = TRUE; + indentation++; + write_fields(h, t->fields); + indent(-1); + fprintf(h, "}"); + } + else fprintf(h, "struct %s", t->name); + break; + case RPC_FC_NON_ENCAPSULATED_UNION: + if (t->defined && !t->written) { + if (t->name) fprintf(h, "union %s {\n", t->name); + else fprintf(h, "union {\n"); + t->written = TRUE; + indentation++; + write_fields(h, t->fields); + indent(-1); + fprintf(h, "}"); + } + else fprintf(h, "union %s", t->name); + break; + default: + fprintf(h, "(unknown-type:%d)", t->type); + } + } + else { + if (t->ref) { + write_type(h, t->ref, NULL, t->name); + } + else fprintf(h, "void"); + } + } + if (v) { + for (c=0; cptr_level; c++) { + fprintf(h, "*"); + } + } +} + +void write_typedef(type_t *type, var_t *names) +{ + char *tname = names->tname; + var_t *lname; + while (NEXT_LINK(names)) names = NEXT_LINK(names); + lname = names; + fprintf(header, "typedef "); + write_type(header, type, NULL, tname); + fprintf(header, " "); + while (names) { + write_pident(header, names); + if (PREV_LINK(names)) + fprintf(header, ", "); + names = PREV_LINK(names); + } + fprintf(header, ";\n"); + + if (get_attrp(type->attrs, ATTR_WIREMARSHAL)) { + names = lname; + while (names) { + char *name = get_name(names); + fprintf(header, "unsigned long __RPC_USER %s_UserSize (unsigned long *, unsigned long, %s *);\n", name, name); + fprintf(header, "unsigned char * __RPC_USER %s_UserMarshal (unsigned long *, unsigned char *, %s *);\n", name, name); + fprintf(header, "unsigned char * __RPC_USER %s_UserUnmarshal(unsigned long *, unsigned char *, %s *);\n", name, name); + fprintf(header, "void __RPC_USER %s_UserFree (unsigned long *, %s *);\n", name, name); + if (PREV_LINK(names)) + fprintf(header, ", "); + names = PREV_LINK(names); + } + } + + fprintf(header, "\n"); +} + +static void do_write_expr(FILE *h, expr_t *e, int p) +{ + switch (e->type) { + case EXPR_VOID: + break; + case EXPR_NUM: + fprintf(h, "%ld", e->u.lval); + break; + case EXPR_HEXNUM: + fprintf(h, "0x%lx", e->u.lval); + break; + case EXPR_IDENTIFIER: + fprintf(h, "%s", e->u.sval); + break; + case EXPR_NEG: + fprintf(h, "-"); + do_write_expr(h, e->ref, 1); + break; + case EXPR_NOT: + fprintf(h, "~"); + do_write_expr(h, e->ref, 1); + break; + case EXPR_PPTR: + fprintf(h, "*"); + do_write_expr(h, e->ref, 1); + break; + case EXPR_CAST: + fprintf(h, "("); + write_type(h, e->u.tref->ref, NULL, e->u.tref->name); + fprintf(h, ")"); + do_write_expr(h, e->ref, 1); + break; + case EXPR_SIZEOF: + fprintf(h, "sizeof("); + write_type(h, e->u.tref->ref, NULL, e->u.tref->name); + fprintf(h, ")"); + break; + case EXPR_SHL: + case EXPR_SHR: + case EXPR_MUL: + case EXPR_DIV: + case EXPR_ADD: + case EXPR_SUB: + case EXPR_AND: + case EXPR_OR: + if (p) fprintf(h, "("); + do_write_expr(h, e->ref, 1); + switch (e->type) { + case EXPR_SHL: fprintf(h, " << "); break; + case EXPR_SHR: fprintf(h, " >> "); break; + case EXPR_MUL: fprintf(h, " * "); break; + case EXPR_DIV: fprintf(h, " / "); break; + case EXPR_ADD: fprintf(h, " + "); break; + case EXPR_SUB: fprintf(h, " - "); break; + case EXPR_AND: fprintf(h, " & "); break; + case EXPR_OR: fprintf(h, " | "); break; + default: break; + } + do_write_expr(h, e->u.ext, 1); + if (p) fprintf(h, ")"); + break; + case EXPR_COND: + if (p) fprintf(h, "("); + do_write_expr(h, e->ref, 1); + fprintf(h, " ? "); + do_write_expr(h, e->u.ext, 1); + fprintf(h, " : "); + do_write_expr(h, e->ext2, 1); + if (p) fprintf(h, ")"); + break; + } +} + +void write_expr(FILE *h, expr_t *e) +{ + do_write_expr(h, e, 0); +} + +void write_constdef(var_t *v) +{ + fprintf(header, "#define %s (", get_name(v)); + write_expr(header, v->eval); + fprintf(header, ")\n\n"); +} + +void write_externdef(var_t *v) +{ + fprintf(header, "extern const "); + write_type(header, v->type, NULL, v->tname); + if (get_name(v)) { + fprintf(header, " "); + write_pident(header, v); + } + fprintf(header, ";\n\n"); +} + +/********** INTERFACES **********/ + +int is_object(attr_t *a) +{ + while (a) { + if (a->type == ATTR_OBJECT || a->type == ATTR_ODL) return 1; + a = NEXT_LINK(a); + } + return 0; +} + +int is_local(attr_t *a) +{ + return is_attr(a, ATTR_LOCAL); +} + +var_t *is_callas(attr_t *a) +{ + return get_attrp(a, ATTR_CALLAS); +} + +static int write_method_macro(type_t *iface, char *name) +{ + int idx; + func_t *cur = iface->funcs; + + if (iface->ref) idx = write_method_macro(iface->ref, name); + else idx = 0; + + if (!cur) return idx; + while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); + + fprintf(header, "/*** %s methods ***/\n", iface->name); + while (cur) { + var_t *def = cur->def; + if (!is_callas(def->attrs)) { + var_t *arg = cur->args; + int argc = 0; + int c; + while (arg) { + arg = NEXT_LINK(arg); + argc++; + } + + fprintf(header, "#define %s_", name); + write_name(header,def); + fprintf(header, "(p"); + for (c=0; clpVtbl->"); + write_name(header, def); + fprintf(header, "(p"); + for (c=0; cidx == -1) cur->idx = idx; + else if (cur->idx != idx) yyerror("BUG: method index mismatch in write_method_macro"); + idx++; + } + cur = PREV_LINK(cur); + } + return idx; +} + +void write_args(FILE *h, var_t *arg, char *name, int method, int do_indent) +{ + int count = 0; + if (arg) { + while (NEXT_LINK(arg)) + arg = NEXT_LINK(arg); + } + if (do_indent) + { + if (h == header) { + indentation++; + indent(0); + } else fprintf(h, " "); + } + if (method == 1) { + fprintf(h, "%s* This", name); + count++; + } + while (arg) { + if (count) { + if (do_indent) + { + fprintf(h, ",\n"); + if (h == header) indent(0); + else fprintf(h, " "); + } + else fprintf(h, ","); + } + write_type(h, arg->type, arg, arg->tname); + if (arg->args) + { + fprintf(h, " (STDMETHODCALLTYPE *"); + write_name(h,arg); + fprintf(h, ")("); + write_args(h, arg->args, NULL, 0, FALSE); + fprintf(h, ")"); + } + else + { + fprintf(h, " "); + write_name(h, arg); + } + write_array(h, arg->array, 0); + arg = PREV_LINK(arg); + count++; + } + if (do_indent && h == header) indentation--; +} + +static void write_cpp_method_def(type_t *iface) +{ + func_t *cur = iface->funcs; + + if (!cur) return; + while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); + while (cur) { + var_t *def = cur->def; + if (!is_callas(def->attrs)) { + indent(0); + fprintf(header, "virtual "); + write_type(header, def->type, def, def->tname); + fprintf(header, " STDMETHODCALLTYPE "); + write_name(header, def); + fprintf(header, "(\n"); + write_args(header, cur->args, iface->name, 2, TRUE); + fprintf(header, ") = 0;\n"); + fprintf(header, "\n"); + } + cur = PREV_LINK(cur); + } +} + +static void do_write_c_method_def(type_t *iface, char *name) +{ + func_t *cur = iface->funcs; + + if (iface->ref) do_write_c_method_def(iface->ref, name); + + if (!cur) return; + while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); + indent(0); + fprintf(header, "/*** %s methods ***/\n", iface->name); + while (cur) { + var_t *def = cur->def; + if (!is_callas(def->attrs)) { + indent(0); + write_type(header, def->type, def, def->tname); + fprintf(header, " (STDMETHODCALLTYPE *"); + write_name(header, def); + fprintf(header, ")(\n"); + write_args(header, cur->args, name, 1, TRUE); + fprintf(header, ");\n"); + fprintf(header, "\n"); + } + cur = PREV_LINK(cur); + } +} + +static void write_c_method_def(type_t *iface) +{ + do_write_c_method_def(iface, iface->name); +} + +static void write_c_disp_method_def(type_t *iface) +{ + do_write_c_method_def(iface->ref, iface->name); +} + +static void write_method_proto(type_t *iface) +{ + func_t *cur = iface->funcs; + + if (!cur) return; + while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); + while (cur) { + var_t *def = cur->def; + var_t *cas = is_callas(def->attrs); + if (!is_local(def->attrs)) { + /* proxy prototype */ + write_type(header, def->type, def, def->tname); + fprintf(header, " CALLBACK %s_", iface->name); + write_name(header, def); + fprintf(header, "_Proxy(\n"); + write_args(header, cur->args, iface->name, 1, TRUE); + fprintf(header, ");\n"); + /* stub prototype */ + fprintf(header, "void __RPC_STUB %s_", iface->name); + write_name(header,def); + fprintf(header, "_Stub(\n"); + fprintf(header, " struct IRpcStubBuffer* This,\n"); + fprintf(header, " struct IRpcChannelBuffer* pRpcChannelBuffer,\n"); + fprintf(header, " PRPC_MESSAGE pRpcMessage,\n"); + fprintf(header, " DWORD* pdwStubPhase);\n"); + } + if (cas) { + func_t *m = iface->funcs; + while (m && strcmp(get_name(m->def), cas->name)) + m = NEXT_LINK(m); + if (m) { + var_t *mdef = m->def; + /* proxy prototype - use local prototype */ + write_type(header, mdef->type, mdef, mdef->tname); + fprintf(header, " CALLBACK %s_", iface->name); + write_name(header, mdef); + fprintf(header, "_Proxy(\n"); + write_args(header, m->args, iface->name, 1, TRUE); + fprintf(header, ");\n"); + /* stub prototype - use remotable prototype */ + write_type(header, def->type, def, def->tname); + fprintf(header, " __RPC_STUB %s_", iface->name); + write_name(header, mdef); + fprintf(header, "_Stub(\n"); + write_args(header, cur->args, iface->name, 1, TRUE); + fprintf(header, ");\n"); + } + else { + yywarning("invalid call_as attribute (%s -> %s)\n", get_name(def), cas->name); + } + } + + cur = PREV_LINK(cur); + } +} + +static void write_function_proto(type_t *iface) +{ + func_t *cur = iface->funcs; + while (NEXT_LINK(cur)) cur = NEXT_LINK(cur); + while (cur) { + var_t *def = cur->def; + /* FIXME: do we need to handle call_as? */ + write_type(header, def->type, def, def->tname); + fprintf(header, " "); + write_name(header, def); + fprintf(header, "(\n"); + write_args(header, cur->args, iface->name, 0, TRUE); + fprintf(header, ");\n"); + + cur = PREV_LINK(cur); + } +} + +void write_forward(type_t *iface) +{ + /* C/C++ forwards should only be written for object interfaces, so if we + * have a full definition we only write one if we find [object] among the + * attributes - however, if we don't have a full definition at this point + * (i.e. this is an IDL forward), then we also assume that it is an object + * interface, since non-object interfaces shouldn't need forwards */ + if ((!iface->defined || is_object(iface->attrs) || is_attr(iface->attrs, ATTR_DISPINTERFACE)) + && !iface->written) { + fprintf(header,"#ifndef __%s_FWD_DEFINED__\n", iface->name); + fprintf(header,"#define __%s_FWD_DEFINED__\n", iface->name); + fprintf(header, "typedef struct %s %s;\n", iface->name, iface->name); + fprintf(header, "#endif\n\n" ); + iface->written = TRUE; + } +} + +void write_guid(const char *guid_prefix, const char *name, UUID *uuid) +{ + if (!uuid) return; + fprintf(header, "DEFINE_GUID(%s_%s, 0x%08lx, 0x%04x, 0x%04x, 0x%02x,0x%02x, 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x);\n", + guid_prefix, name, uuid->Data1, uuid->Data2, uuid->Data3, uuid->Data4[0], uuid->Data4[1], + uuid->Data4[2], uuid->Data4[3], uuid->Data4[4], uuid->Data4[5], uuid->Data4[6], uuid->Data4[7]); +} + +void write_iface_guid(type_t *iface) +{ + UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); + write_guid("IID", iface->name, uuid); +} + +void write_dispiface_guid(type_t *iface) +{ + UUID *uuid = get_attrp(iface->attrs, ATTR_UUID); + write_guid("DIID", iface->name, uuid); +} + +void write_coclass_guid(class_t *cocl) +{ + UUID *uuid = get_attrp(cocl->attrs, ATTR_UUID); + write_guid("CLSID", cocl->name, uuid); +} + +void write_com_interface(type_t *iface) +{ + if (!iface->funcs && !iface->ref) { + yywarning("%s has no methods", iface->name); + return; + } + + fprintf(header, "/*****************************************************************************\n"); + fprintf(header, " * %s interface\n", iface->name); + fprintf(header, " */\n"); + fprintf(header,"#ifndef __%s_INTERFACE_DEFINED__\n", iface->name); + fprintf(header,"#define __%s_INTERFACE_DEFINED__\n\n", iface->name); + write_iface_guid(iface); + write_forward(iface); + /* C++ interface */ + fprintf(header, "#if defined(__cplusplus) && !defined(CINTERFACE)\n"); + if (iface->ref) + { + fprintf(header, "struct %s : public %s\n", iface->name, iface->ref->name); + fprintf(header, "{\n"); + indentation++; + write_cpp_method_def(iface); + indentation--; + fprintf(header, "};\n"); + } + else + { + fprintf(header, "struct %s\n", iface->name); + fprintf(header, "{\n"); + fprintf(header, " BEGIN_INTERFACE\n"); + fprintf(header, "\n"); + indentation++; + write_cpp_method_def(iface); + indentation--; + fprintf(header, " END_INTERFACE\n"); + fprintf(header, "};\n"); + } + fprintf(header, "#else\n"); + /* C interface */ + fprintf(header, "typedef struct %sVtbl %sVtbl;\n", iface->name, iface->name); + fprintf(header, "struct %s {\n", iface->name); + fprintf(header, " const %sVtbl* lpVtbl;\n", iface->name); + fprintf(header, "};\n"); + fprintf(header, "struct %sVtbl {\n", iface->name); + indentation++; + fprintf(header, " BEGIN_INTERFACE\n"); + fprintf(header, "\n"); + write_c_method_def(iface); + indentation--; + fprintf(header, " END_INTERFACE\n"); + fprintf(header, "};\n"); + fprintf(header, "\n"); + fprintf(header, "#ifdef COBJMACROS\n"); + write_method_macro(iface, iface->name); + fprintf(header, "#endif\n"); + fprintf(header, "\n"); + fprintf(header, "#endif\n"); + fprintf(header, "\n"); + write_method_proto(iface); + fprintf(header,"\n#endif /* __%s_INTERFACE_DEFINED__ */\n\n", iface->name); +} + +void write_rpc_interface(type_t *iface) +{ + unsigned long ver = get_attrv(iface->attrs, ATTR_VERSION); + + if (!iface->funcs) return; + + fprintf(header, "/*****************************************************************************\n"); + fprintf(header, " * %s interface (v%d.%d)\n", iface->name, LOWORD(ver), HIWORD(ver)); + fprintf(header, " */\n"); + write_iface_guid(iface); + fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_c_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver)); + fprintf(header, "extern RPC_IF_HANDLE %s_v%d_%d_s_ifspec;\n", iface->name, LOWORD(ver), HIWORD(ver)); + write_function_proto(iface); + fprintf(header, "\n"); + + /* FIXME: server/client code */ +} + +void write_interface(type_t *iface) +{ + if (is_object(iface->attrs)) + write_com_interface(iface); + else + write_rpc_interface(iface); +} + +void write_dispinterface(type_t *iface) +{ + fprintf(header, "/*****************************************************************************\n"); + fprintf(header, " * %s dispinterface\n", iface->name); + fprintf(header, " */\n"); + fprintf(header,"#ifndef __%s_DISPINTERFACE_DEFINED__\n", iface->name); + fprintf(header,"#define __%s_DISPINTERFACE_DEFINED__\n\n", iface->name); + write_dispiface_guid(iface); + write_forward(iface); + /* C++ interface */ + fprintf(header, "#if defined(__cplusplus) && !defined(CINTERFACE)\n"); + fprintf(header, "struct %s : public %s\n", iface->name, iface->ref->name); + fprintf(header, "{\n"); + fprintf(header, "};\n"); + fprintf(header, "#else\n"); + /* C interface */ + fprintf(header, "typedef struct %sVtbl %sVtbl;\n", iface->name, iface->name); + fprintf(header, "struct %s {\n", iface->name); + fprintf(header, " const %sVtbl* lpVtbl;\n", iface->name); + fprintf(header, "};\n"); + fprintf(header, "struct %sVtbl {\n", iface->name); + indentation++; + fprintf(header, " BEGIN_INTERFACE\n"); + fprintf(header, "\n"); + write_c_disp_method_def(iface); + indentation--; + fprintf(header, " END_INTERFACE\n"); + fprintf(header, "};\n"); + fprintf(header, "\n"); + fprintf(header, "#ifdef COBJMACROS\n"); + write_method_macro(iface->ref, iface->name); + fprintf(header, "#endif\n"); + fprintf(header, "\n"); + fprintf(header, "#endif\n"); + fprintf(header, "\n"); + fprintf(header,"#endif /* __%s_DISPINTERFACE_DEFINED__ */\n\n", iface->name); +} + +void write_coclass(class_t *cocl) +{ + fprintf(header, "/*****************************************************************************\n"); + fprintf(header, " * %s coclass\n", cocl->name); + fprintf(header, " */\n\n"); + write_coclass_guid(cocl); + fprintf(header, "\n"); +} diff --git a/reactos/tools/widl/header.h b/reactos/tools/widl/header.h new file mode 100644 index 00000000000..bd69a736509 --- /dev/null +++ b/reactos/tools/widl/header.h @@ -0,0 +1,44 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_HEADER_H +#define __WIDL_HEADER_H + +extern int is_attr(attr_t *a, enum attr_type t); +extern void *get_attrp(attr_t *a, enum attr_type t); +extern unsigned long get_attrv(attr_t *a, enum attr_type t); +extern int is_void(type_t *t, var_t *v); +extern void write_name(FILE *h, var_t *v); +extern char* get_name(var_t *v); +extern void write_type(FILE *h, type_t *t, var_t *v, char *n); +extern int is_object(attr_t *a); +extern int is_local(attr_t *a); +extern var_t *is_callas(attr_t *a); +extern void write_args(FILE *h, var_t *arg, char *name, int obj, int do_indent); +extern void write_forward(type_t *iface); +extern void write_interface(type_t *iface); +extern void write_dispinterface(type_t *iface); +extern void write_coclass(class_t *iface); +extern void write_typedef(type_t *type, var_t *names); +extern void write_expr(FILE *h, expr_t *e); +extern void write_constdef(var_t *v); +extern void write_externdef(var_t *v); + +#endif diff --git a/reactos/tools/widl/parser.h b/reactos/tools/widl/parser.h new file mode 100644 index 00000000000..20a7e2af474 --- /dev/null +++ b/reactos/tools/widl/parser.h @@ -0,0 +1,41 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_PARSER_H +#define __WIDL_PARSER_H + +int yyparse(void); + +extern FILE *yyin; +extern char *yytext; +extern int yydebug; +extern int yy_flex_debug; + +int yylex(void); + +extern int import_stack_ptr; +int do_import(char *fname); +void abort_import(void); + +#define parse_only import_stack_ptr + +int is_type(const char *name); + +#endif diff --git a/reactos/tools/widl/parser.l b/reactos/tools/widl/parser.l new file mode 100644 index 00000000000..340322cc15c --- /dev/null +++ b/reactos/tools/widl/parser.l @@ -0,0 +1,442 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +%option stack +%option never-interactive + +nl \r?\n +ws [ \f\t\r] +cident [a-zA-Z_][0-9a-zA-Z_]* +int [0-9]+ +hexd [0-9a-fA-F] +hex 0x{hexd}+ +uuid {hexd}{8}-{hexd}{4}-{hexd}{4}-{hexd}{4}-{hexd}{12} + +%x QUOTE +%x pp_line + +%{ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "wine/wpp.h" + +#include "y.tab.h" + +#define YY_USE_PROTOS +#define YY_NO_UNPUT +#define YY_NO_TOP_STATE + +extern char *temp_name; + +static void addcchar(char c); +static char *get_buffered_cstring(void); + +static char *cbuffer; +static int cbufidx; +static int cbufalloc = 0; + +static int kw_token(const char *kw); + +#define MAX_IMPORT_DEPTH 10 +struct { + YY_BUFFER_STATE state; + char *input_name; + int line_number; + char *temp_name; +} import_stack[MAX_IMPORT_DEPTH]; +int import_stack_ptr = 0; + +static void pop_import(void); + +static UUID* parse_uuid(const char*u) +{ + UUID* uuid = xmalloc(sizeof(UUID)); + char b[3]; + /* it would be nice to use UuidFromStringA */ + uuid->Data1 = strtoul(u, NULL, 16); + uuid->Data2 = strtoul(u+9, NULL, 16); + uuid->Data3 = strtoul(u+14, NULL, 16); + b[2] = 0; + memcpy(b, u+19, 2); uuid->Data4[0] = strtoul(b, NULL, 16); + memcpy(b, u+21, 2); uuid->Data4[1] = strtoul(b, NULL, 16); + memcpy(b, u+24, 2); uuid->Data4[2] = strtoul(b, NULL, 16); + memcpy(b, u+26, 2); uuid->Data4[3] = strtoul(b, NULL, 16); + memcpy(b, u+28, 2); uuid->Data4[4] = strtoul(b, NULL, 16); + memcpy(b, u+30, 2); uuid->Data4[5] = strtoul(b, NULL, 16); + memcpy(b, u+32, 2); uuid->Data4[6] = strtoul(b, NULL, 16); + memcpy(b, u+34, 2); uuid->Data4[7] = strtoul(b, NULL, 16); + return uuid; +} + +%} + +/* + ************************************************************************** + * The flexer starts here + ************************************************************************** + */ +%% +^{ws}*\#{ws}* yy_push_state(pp_line); +[^\n]* { + int lineno; + char *cptr, *fname; + yy_pop_state(); + lineno = (int)strtol(yytext, &cptr, 10); + if(!lineno) + yyerror("Malformed '#...' line-directive; invalid linenumber"); + fname = strchr(cptr, '"'); + if(!fname) + yyerror("Malformed '#...' line-directive; missing filename"); + fname++; + cptr = strchr(fname, '"'); + if(!cptr) + yyerror("Malformed '#...' line-directive; missing terminating \""); + *cptr = '\0'; + line_number = lineno - 1; /* We didn't read the newline */ + free( input_name ); + input_name = xstrdup(fname); + } +\" yy_push_state(QUOTE); cbufidx = 0; +\" { + yy_pop_state(); + yylval.str = get_buffered_cstring(); + return aSTRING; + } +\\\\ | +\\\" addcchar(yytext[1]); +\\. addcchar('\\'); addcchar(yytext[1]); +. addcchar(yytext[0]); +{uuid} { + yylval.uuid = parse_uuid(yytext); + return aUUID; + } +{hex} { + yylval.num = strtoul(yytext, NULL, 0); + return aHEXNUM; + } +{int} { + yylval.num = strtoul(yytext, NULL, 0); + return aNUM; + } +{cident} return kw_token(yytext); +\n line_number++; +{ws} +\<\< return SHL; +\>\> return SHR; +. return yytext[0]; +<> { + if (import_stack_ptr) { + pop_import(); + return aEOF; + } + else yyterminate(); + } +%% + +#ifndef yywrap +int yywrap(void) +{ + return 1; +} +#endif + +static struct keyword { + const char *kw; + int token; + int val; +} keywords[] = { + {"__cdecl", tCDECL}, + {"__int64", tINT64}, + {"__stdcall", tSTDCALL}, + {"_stdcall", tSTDCALL}, + {"aggregatable", tAGGREGATABLE}, + {"allocate", tALLOCATE}, + {"appobject", tAPPOBJECT}, + {"arrays", tARRAYS}, + {"async", tASYNC}, + {"async_uuid", tASYNCUUID}, + {"auto_handle", tAUTOHANDLE}, + {"bindable", tBINDABLE}, + {"boolean", tBOOLEAN}, + {"broadcast", tBROADCAST}, + {"byte", tBYTE}, + {"byte_count", tBYTECOUNT}, + {"call_as", tCALLAS}, + {"callback", tCALLBACK}, + {"case", tCASE}, + {"char", tCHAR}, + {"coclass", tCOCLASS}, + {"code", tCODE}, + {"comm_status", tCOMMSTATUS}, + {"const", tCONST}, + {"context_handle", tCONTEXTHANDLE}, + {"context_handle_noserialize", tCONTEXTHANDLENOSERIALIZE}, + {"context_handle_serialize", tCONTEXTHANDLENOSERIALIZE}, + {"control", tCONTROL}, + {"cpp_quote", tCPPQUOTE}, +/* ... */ + {"default", tDEFAULT}, + {"defaultvalue", tDEFAULTVALUE}, +/* ... */ + {"dispinterface", tDISPINTERFACE}, +/* ... */ + {"dllname", tDLLNAME}, + {"double", tDOUBLE}, + {"dual", tDUAL}, +/* ... */ + {"endpoint", tENDPOINT}, + {"entry", tENTRY}, + {"enum", tENUM}, + {"error_status_t", tERRORSTATUST}, +/* ... */ + {"extern", tEXTERN}, +/* ... */ + {"float", tFLOAT}, +/* ... */ + {"handle", tHANDLE}, + {"handle_t", tHANDLET}, +/* ... */ + {"helpcontext", tHELPCONTEXT}, + {"helpfile", tHELPFILE}, + {"helpstring", tHELPSTRING}, + {"helpstringcontext", tHELPSTRINGCONTEXT}, + {"helpstringdll", tHELPSTRINGDLL}, +/* ... */ + {"hidden", tHIDDEN}, + {"hyper", tHYPER}, + {"id", tID}, + {"idempotent", tIDEMPOTENT}, +/* ... */ + {"iid_is", tIIDIS}, +/* ... */ + {"import", tIMPORT}, + {"importlib", tIMPORTLIB}, + {"in", tIN}, + {"include", tINCLUDE}, + {"in_line", tINLINE}, + {"input_sync", tINPUTSYNC}, + {"int", tINT}, +/* ... */ + {"interface", tINTERFACE}, +/* ... */ + {"length_is", tLENGTHIS}, + {"library", tLIBRARY}, +/* ... */ + {"local", tLOCAL}, + {"long", tLONG}, +/* ... */ + {"methods", tMETHODS}, +/* ... */ + {"module", tMODULE}, +/* ... */ + {"noncreatable", tNONCREATABLE}, + {"object", tOBJECT}, + {"odl", tODL}, + {"oleautomation", tOLEAUTOMATION}, +/* ... */ + {"optional", tOPTIONAL}, + {"out", tOUT}, +/* ... */ + {"pointer_default", tPOINTERDEFAULT}, +/* ... */ + {"properties", tPROPERTIES}, + {"propget", tPROPGET}, + {"propput", tPROPPUT}, + {"propputref", tPROPPUTREF}, +/* ... */ + {"public", tPUBLIC}, +/* ... */ + {"readonly", tREADONLY}, + {"ref", tREF}, +/* ... */ + {"restricted", tRESTRICTED}, + {"retval", tRETVAL}, +/* ... */ + {"short", tSHORT}, + {"signed", tSIGNED}, + {"size_is", tSIZEIS}, + {"sizeof", tSIZEOF}, +/* ... */ + {"source", tSOURCE}, +/* ... */ + {"string", tSTRING}, + {"struct", tSTRUCT}, + {"switch", tSWITCH}, + {"switch_is", tSWITCHIS}, + {"switch_type", tSWITCHTYPE}, +/* ... */ + {"transmit_as", tTRANSMITAS}, + {"typedef", tTYPEDEF}, + {"union", tUNION}, +/* ... */ + {"unique", tUNIQUE}, + {"unsigned", tUNSIGNED}, +/* ... */ + {"uuid", tUUID}, + {"v1_enum", tV1ENUM}, +/* ... */ + {"vararg", tVARARG}, + {"version", tVERSION}, + {"void", tVOID}, + {"wchar_t", tWCHAR}, + {"wire_marshal", tWIREMARSHAL} +}; +#define NKEYWORDS (sizeof(keywords)/sizeof(keywords[0])) +#define KWP(p) ((const struct keyword *)(p)) + +static int kw_cmp_func(const void *s1, const void *s2) +{ + return strcmp(KWP(s1)->kw, KWP(s2)->kw); +} + +#define KW_BSEARCH +static int kw_token(const char *kw) +{ + struct keyword key, *kwp; + key.kw = kw; +#ifdef KW_BSEARCH + kwp = bsearch(&key, keywords, NKEYWORDS, sizeof(keywords[0]), kw_cmp_func); +#else + { + int i; + for (kwp=NULL, i=0; i < NKEYWORDS; i++) + if (!kw_cmp_func(&key, &keywords[i])) { + kwp = &keywords[i]; + break; + } + } +#endif + if (kwp) { + yylval.str = (char*)kwp->kw; + return kwp->token; + } + yylval.str = xstrdup(kw); + return is_type(kw) ? aKNOWNTYPE : aIDENTIFIER; +} + +static void addcchar(char c) +{ + if(cbufidx >= cbufalloc) + { + cbufalloc += 1024; + cbuffer = xrealloc(cbuffer, cbufalloc * sizeof(cbuffer[0])); + if(cbufalloc > 65536) + yywarning("Reallocating string buffer larger than 64kB"); + } + cbuffer[cbufidx++] = c; +} + +static char *get_buffered_cstring(void) +{ + addcchar(0); + return xstrdup(cbuffer); +} + +static void pop_import(void) +{ + int ptr = import_stack_ptr-1; + + fclose(yyin); + yy_delete_buffer( YY_CURRENT_BUFFER ); + yy_switch_to_buffer( import_stack[ptr].state ); + if (temp_name) { + unlink(temp_name); + free(temp_name); + } + temp_name = import_stack[ptr].temp_name; + free( input_name ); + input_name = import_stack[ptr].input_name; + line_number = import_stack[ptr].line_number; + import_stack_ptr--; +} + +struct imports { + char *name; + struct imports *next; +} *first_import; + +int do_import(char *fname) +{ + FILE *f; + char *hname, *path, *p; + struct imports *import; + int ptr = import_stack_ptr; + int ret; + + if (!parse_only && do_header) { + hname = dup_basename(fname, ".idl"); + p = hname + strlen(hname) - 2; + if (p <= hname || strcmp( p, ".h" )) strcat(hname, ".h"); + + fprintf(header, "#include <%s>\n", hname); + free(hname); + } + + import = first_import; + while (import && strcmp(import->name, fname)) + import = import->next; + if (import) return 0; /* already imported */ + + import = xmalloc(sizeof(struct imports)); + import->name = xstrdup(fname); + import->next = first_import; + first_import = import; + + if (!(path = wpp_find_include( fname, 1 ))) + yyerror("Unable to open include file %s", fname); + + import_stack[ptr].temp_name = temp_name; + import_stack[ptr].input_name = input_name; + import_stack[ptr].line_number = line_number; + import_stack_ptr++; + input_name = path; + line_number = 1; + + ret = wpp_parse_temp( path, NULL, &temp_name ); + if (ret) exit(1); + + if((f = fopen(temp_name, "r")) == NULL) + yyerror("Unable to open %s", temp_name); + + import_stack[ptr].state = YY_CURRENT_BUFFER; + yy_switch_to_buffer(yy_create_buffer(f, YY_BUF_SIZE)); + return 1; +} + +void abort_import(void) +{ + int ptr; + + for (ptr=0; ptr +#include +#include +#include +#include +#include +#ifdef HAVE_ALLOCA_H +#include +#endif + +#include "windef.h" + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" +#include "proxy.h" +#include "typelib.h" + +#if defined(YYBYACC) + /* Berkeley yacc (byacc) doesn't seem to know about these */ + /* Some *BSD supplied versions do define these though */ +# ifndef YYEMPTY +# define YYEMPTY (-1) /* Empty lookahead value of yychar */ +# endif +# ifndef YYLEX +# define YYLEX yylex() +# endif + +#elif defined(YYBISON) + /* Bison was used for original development */ + /* #define YYEMPTY -2 */ + /* #define YYLEX yylex() */ + +#else + /* No yacc we know yet */ +# if !defined(YYEMPTY) || !defined(YYLEX) +# error Yacc version/type unknown. This version needs to be verified for settings of YYEMPTY and YYLEX. +# elif defined(__GNUC__) /* gcc defines the #warning directive */ +# warning Yacc version/type unknown. It defines YYEMPTY and YYLEX, but is not tested + /* #else we just take a chance that it works... */ +# endif +#endif + +static attr_t *make_attr(enum attr_type type); +static attr_t *make_attrv(enum attr_type type, unsigned long val); +static attr_t *make_attrp(enum attr_type type, void *val); +static expr_t *make_expr(enum expr_type type); +static expr_t *make_exprl(enum expr_type type, long val); +static expr_t *make_exprs(enum expr_type type, char *val); +static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr); +static expr_t *make_expr1(enum expr_type type, expr_t *expr); +static expr_t *make_expr2(enum expr_type type, expr_t *exp1, expr_t *exp2); +static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3); +static type_t *make_type(unsigned char type, type_t *ref); +static typeref_t *make_tref(char *name, type_t *ref); +static typeref_t *uniq_tref(typeref_t *ref); +static type_t *type_ref(typeref_t *ref); +static void set_type(var_t *v, typeref_t *ref, expr_t *arr); +static ifref_t *make_ifref(type_t *iface); +static var_t *make_var(char *name); +static func_t *make_func(var_t *def, var_t *args); +static class_t *make_class(char *name); + +static type_t *reg_type(type_t *type, char *name, int t); +static type_t *reg_types(type_t *type, var_t *names, int t); +static type_t *find_type(char *name, int t); +static type_t *find_type2(char *name, int t); +static type_t *get_type(unsigned char type, char *name, int t); +static type_t *get_typev(unsigned char type, var_t *name, int t); +static int get_struct_type(var_t *fields); + +static var_t *reg_const(var_t *var); +static var_t *find_const(char *name, int f); + +#define tsENUM 1 +#define tsSTRUCT 2 +#define tsUNION 3 + +static type_t std_bool = { "boolean" }; +static type_t std_int = { "int" }; +static type_t std_int64 = { "__int64" }; +static type_t std_uhyper = { "MIDL_uhyper" }; + +%} +%union { + attr_t *attr; + expr_t *expr; + type_t *type; + typeref_t *tref; + var_t *var; + func_t *func; + ifref_t *ifref; + class_t *clas; + char *str; + UUID *uuid; + unsigned int num; +} + +%token aIDENTIFIER +%token aKNOWNTYPE +%token aNUM aHEXNUM +%token aSTRING +%token aUUID +%token aEOF +%token SHL SHR +%token tAGGREGATABLE tALLOCATE tAPPOBJECT tARRAYS tASYNC tASYNCUUID +%token tAUTOHANDLE tBINDABLE tBOOLEAN tBROADCAST tBYTE tBYTECOUNT +%token tCALLAS tCALLBACK tCASE tCDECL tCHAR tCOCLASS tCODE tCOMMSTATUS +%token tCONST tCONTEXTHANDLE tCONTEXTHANDLENOSERIALIZE +%token tCONTEXTHANDLESERIALIZE tCONTROL tCPPQUOTE +%token tDEFAULT +%token tDEFAULTVALUE +%token tDISPINTERFACE +%token tDLLNAME tDOUBLE tDUAL +%token tENDPOINT +%token tENTRY tENUM tERRORSTATUST +%token tEXTERN +%token tFLOAT +%token tHANDLE +%token tHANDLET +%token tHELPCONTEXT tHELPFILE +%token tHELPSTRING tHELPSTRINGCONTEXT tHELPSTRINGDLL +%token tHIDDEN +%token tHYPER tID tIDEMPOTENT +%token tIIDIS +%token tIMPORT tIMPORTLIB +%token tIN tINCLUDE tINLINE +%token tINPUTSYNC +%token tINT tINT64 +%token tINTERFACE +%token tLENGTHIS tLIBRARY +%token tLOCAL +%token tLONG +%token tMETHODS +%token tMODULE +%token tNONCREATABLE +%token tOBJECT tODL tOLEAUTOMATION +%token tOPTIONAL +%token tOUT +%token tPOINTERDEFAULT +%token tPROPERTIES +%token tPROPGET tPROPPUT tPROPPUTREF +%token tPUBLIC +%token tREADONLY tREF +%token tRESTRICTED +%token tRETVAL +%token tSHORT +%token tSIGNED +%token tSIZEIS tSIZEOF +%token tSOURCE +%token tSTDCALL +%token tSTRING tSTRUCT +%token tSWITCH tSWITCHIS tSWITCHTYPE +%token tTRANSMITAS +%token tTYPEDEF +%token tUNION +%token tUNIQUE +%token tUNSIGNED +%token tUUID +%token tV1ENUM +%token tVARARG +%token tVERSION +%token tVOID +%token tWCHAR tWIREMARSHAL + +/* used in attr_t */ +%token tPOINTERTYPE + +%type m_attributes attributes attrib_list attribute +%type m_exprs /* exprs expr_list */ m_expr expr expr_list_const expr_const +%type array array_list +%type inherit interface interfacehdr interfacedef interfacedec +%type dispinterface dispinterfacehdr dispinterfacedef +%type module modulehdr moduledef +%type base_type int_std +%type enumdef structdef typedef uniondef +%type gbl_statements coclass_ints coclass_int +%type type +%type m_args no_args args arg +%type fields field s_field cases case enums enum_list enum constdef externdef +%type m_ident t_ident ident p_ident pident pident_list +%type dispint_props +%type funcdef int_statements +%type dispint_meths +%type coclass coclasshdr coclassdef +%type pointer_type version +%type libraryhdr + +%left ',' +%right COND +%left '|' +%left '&' +%left '-' '+' +%left '*' '/' +%left SHL SHR +%right '~' +%right CAST +%right PPTR +%right NEG + +%% + +input: gbl_statements { write_proxies($1); } + ; + +gbl_statements: { $$ = NULL; } + | gbl_statements interfacedec { $$ = $1; } + | gbl_statements interfacedef { $$ = make_ifref($2); LINK($$, $1); } + | gbl_statements coclassdef { $$ = $1; add_coclass($2); } + | gbl_statements moduledef { $$ = $1; add_module($2); } + | gbl_statements librarydef { $$ = $1; } + | gbl_statements statement { $$ = $1; } + ; + +imp_statements: {} + | imp_statements interfacedec { if (!parse_only) add_interface($2); } + | imp_statements interfacedef { if (!parse_only) add_interface($2); } + | imp_statements coclassdef { if (!parse_only) add_coclass($2); } + | imp_statements moduledef { if (!parse_only) add_module($2); } + | imp_statements statement {} + ; + +int_statements: { $$ = NULL; } + | int_statements funcdef ';' { $$ = $2; LINK($$, $1); } + | int_statements statement { $$ = $1; } + ; + +statement: ';' {} + | constdef ';' { if (!parse_only && do_header) { write_constdef($1); } } + | cppquote {} + | enumdef ';' { if (!parse_only && do_header) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n\n"); } } + | externdef ';' { if (!parse_only && do_header) { write_externdef($1); } } + | import {} + | structdef ';' { if (!parse_only && do_header) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n\n"); } } + | typedef ';' {} + | uniondef ';' { if (!parse_only && do_header) { write_type(header, $1, NULL, NULL); fprintf(header, ";\n\n"); } } + ; + +cppquote: tCPPQUOTE '(' aSTRING ')' { if (!parse_only && do_header) fprintf(header, "%s\n", $3); } + ; +import_start: tIMPORT aSTRING ';' { assert(yychar == YYEMPTY); + if (!do_import($2)) yychar = aEOF; } + ; +import: import_start imp_statements aEOF {} + ; + +libraryhdr: tLIBRARY aIDENTIFIER { $$ = $2; } + ; +library_start: attributes libraryhdr '{' { start_typelib($2, $1); } + ; +librarydef: library_start imp_statements '}' { end_typelib(); } + ; + +m_args: { $$ = NULL; } + | args + ; + +no_args: tVOID { $$ = NULL; } + ; + +args: arg + | args ',' arg { LINK($3, $1); $$ = $3; } + | no_args + ; + +/* split into two rules to get bison to resolve a tVOID conflict */ +arg: attributes type pident array { $$ = $3; + set_type($$, $2, $4); + $$->attrs = $1; + } + | type pident array { $$ = $2; + set_type($$, $1, $3); + } + | attributes type pident '(' m_args ')' { $$ = $3; + $$->ptr_level--; + set_type($$, $2, NULL); + $$->attrs = $1; + $$->args = $5; + } + | type pident '(' m_args ')' { $$ = $2; + $$->ptr_level--; + set_type($$, $1, NULL); + $$->args = $4; + } + ; + +array: { $$ = NULL; } + | '[' array_list ']' { $$ = $2; } + | '[' '*' ']' { $$ = make_expr(EXPR_VOID); } + ; + +array_list: m_expr /* size of first dimension is optional */ + | array_list ',' expr { LINK($3, $1); $$ = $3; } + | array_list ']' '[' expr { LINK($4, $1); $$ = $4; } + ; + +m_attributes: { $$ = NULL; } + | attributes + ; + +attributes: + '[' attrib_list ']' { $$ = $2; } + ; + +attrib_list: attribute + | attrib_list ',' attribute { LINK($3, $1); $$ = $3; } + | attrib_list ']' '[' attribute { LINK($4, $1); $$ = $4; } + ; + +attribute: + tASYNC { $$ = make_attr(ATTR_ASYNC); } + | tCALLAS '(' ident ')' { $$ = make_attrp(ATTR_CALLAS, $3); } + | tCASE '(' expr_list_const ')' { $$ = make_attrp(ATTR_CASE, $3); } + | tCONTEXTHANDLE { $$ = make_attrv(ATTR_CONTEXTHANDLE, 0); } + | tCONTEXTHANDLENOSERIALIZE { $$ = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_DONT_SERIALIZE */ } + | tCONTEXTHANDLESERIALIZE { $$ = make_attrv(ATTR_CONTEXTHANDLE, 0); /* RPC_CONTEXT_HANDLE_SERIALIZE */ } + | tCONTROL { $$ = make_attr(ATTR_CONTROL); } + | tDEFAULT { $$ = make_attr(ATTR_DEFAULT); } + | tDEFAULTVALUE '(' expr_const ')' { $$ = make_attrp(ATTR_DEFAULTVALUE_EXPR, $3); } + | tDEFAULTVALUE '(' aSTRING ')' { $$ = make_attrp(ATTR_DEFAULTVALUE_STRING, $3); } + | tDLLNAME '(' aSTRING ')' { $$ = make_attrp(ATTR_DLLNAME, $3); } + | tDUAL { $$ = make_attr(ATTR_DUAL); } + | tENDPOINT '(' aSTRING ')' { $$ = make_attrp(ATTR_ENDPOINT, $3); } + | tENTRY '(' aSTRING ')' { $$ = make_attrp(ATTR_ENTRY_STRING, $3); } + | tENTRY '(' expr_const ')' { $$ = make_attrp(ATTR_ENTRY_ORDINAL, $3); } + | tHANDLE { $$ = make_attr(ATTR_HANDLE); } + | tHELPCONTEXT '(' expr_const ')' { $$ = make_attrp(ATTR_HELPCONTEXT, $3); } + | tHELPFILE '(' aSTRING ')' { $$ = make_attrp(ATTR_HELPFILE, $3); } + | tHELPSTRING '(' aSTRING ')' { $$ = make_attrp(ATTR_HELPSTRING, $3); } + | tHELPSTRINGCONTEXT '(' expr_const ')' { $$ = make_attrp(ATTR_HELPSTRINGCONTEXT, $3); } + | tHELPSTRINGDLL '(' aSTRING ')' { $$ = make_attrp(ATTR_HELPSTRINGDLL, $3); } + | tHIDDEN { $$ = make_attr(ATTR_HIDDEN); } + | tID '(' expr_const ')' { $$ = make_attrp(ATTR_ID, $3); } + | tIDEMPOTENT { $$ = make_attr(ATTR_IDEMPOTENT); } + | tIIDIS '(' ident ')' { $$ = make_attrp(ATTR_IIDIS, $3); } + | tIN { $$ = make_attr(ATTR_IN); } + | tINPUTSYNC { $$ = make_attr(ATTR_INPUTSYNC); } + | tLENGTHIS '(' m_exprs ')' { $$ = make_attrp(ATTR_LENGTHIS, $3); } + | tLOCAL { $$ = make_attr(ATTR_LOCAL); } + | tNONCREATABLE { $$ = make_attr(ATTR_NONCREATABLE); } + | tOBJECT { $$ = make_attr(ATTR_OBJECT); } + | tODL { $$ = make_attr(ATTR_ODL); } + | tOLEAUTOMATION { $$ = make_attr(ATTR_OLEAUTOMATION); } + | tOPTIONAL { $$ = make_attr(ATTR_OPTIONAL); } + | tOUT { $$ = make_attr(ATTR_OUT); } + | tPOINTERDEFAULT '(' pointer_type ')' { $$ = make_attrv(ATTR_POINTERDEFAULT, $3); } + | tPROPGET { $$ = make_attr(ATTR_PROPGET); } + | tPROPPUT { $$ = make_attr(ATTR_PROPPUT); } + | tPROPPUTREF { $$ = make_attr(ATTR_PROPPUTREF); } + | tPUBLIC { $$ = make_attr(ATTR_PUBLIC); } + | tREADONLY { $$ = make_attr(ATTR_READONLY); } + | tRESTRICTED { $$ = make_attr(ATTR_RESTRICTED); } + | tRETVAL { $$ = make_attr(ATTR_RETVAL); } + | tSIZEIS '(' m_exprs ')' { $$ = make_attrp(ATTR_SIZEIS, $3); } + | tSOURCE { $$ = make_attr(ATTR_SOURCE); } + | tSTRING { $$ = make_attr(ATTR_STRING); } + | tSWITCHIS '(' expr ')' { $$ = make_attrp(ATTR_SWITCHIS, $3); } + | tSWITCHTYPE '(' type ')' { $$ = make_attrp(ATTR_SWITCHTYPE, type_ref($3)); } + | tTRANSMITAS '(' type ')' { $$ = make_attrp(ATTR_TRANSMITAS, type_ref($3)); } + | tUUID '(' aUUID ')' { $$ = make_attrp(ATTR_UUID, $3); } + | tV1ENUM { $$ = make_attr(ATTR_V1ENUM); } + | tVARARG { $$ = make_attr(ATTR_VARARG); } + | tVERSION '(' version ')' { $$ = make_attrv(ATTR_VERSION, $3); } + | tWIREMARSHAL '(' type ')' { $$ = make_attrp(ATTR_WIREMARSHAL, type_ref($3)); } + | pointer_type { $$ = make_attrv(ATTR_POINTERTYPE, $1); } + ; + +callconv: + | tSTDCALL + ; + +cases: { $$ = NULL; } + | cases case { if ($2) { LINK($2, $1); $$ = $2; } + else { $$ = $1; } + } + ; + +case: tCASE expr ':' field { attr_t *a = make_attrp(ATTR_CASE, $2); + $$ = $4; if (!$$) $$ = make_var(NULL); + LINK(a, $$->attrs); $$->attrs = a; + } + | tDEFAULT ':' field { attr_t *a = make_attr(ATTR_DEFAULT); + $$ = $3; if (!$$) $$ = make_var(NULL); + LINK(a, $$->attrs); $$->attrs = a; + } + ; + +constdef: tCONST type ident '=' expr_const { $$ = reg_const($3); + set_type($$, $2, NULL); + $$->eval = $5; + $$->lval = $5->cval; + } + ; + +enums: { $$ = NULL; } + | enum_list ',' { $$ = $1; } + | enum_list + ; + +enum_list: enum + | enum_list ',' enum { LINK($3, $1); $$ = $3; + if ($1 && !$3->eval) + $3->lval = $1->lval + 1; + } + ; + +enum: ident '=' expr_const { $$ = reg_const($1); + $$->eval = $3; + $$->lval = $3->cval; + $$->type = make_type(RPC_FC_LONG, &std_int); + } + | ident { $$ = reg_const($1); + $$->lval = 0; /* default for first enum entry */ + $$->type = make_type(RPC_FC_LONG, &std_int); + } + ; + +enumdef: tENUM t_ident '{' enums '}' { $$ = get_typev(RPC_FC_ENUM16, $2, tsENUM); + $$->fields = $4; + $$->defined = TRUE; + if(in_typelib) + add_enum($$); + } + ; + +m_exprs: m_expr + | m_exprs ',' m_expr { LINK($3, $1); $$ = $3; } + ; + +/* +exprs: { $$ = make_expr(EXPR_VOID); } + | expr_list + ; + +expr_list: expr + | expr_list ',' expr { LINK($3, $1); $$ = $3; } + ; +*/ + +m_expr: { $$ = make_expr(EXPR_VOID); } + | expr + ; + +expr: aNUM { $$ = make_exprl(EXPR_NUM, $1); } + | aHEXNUM { $$ = make_exprl(EXPR_HEXNUM, $1); } + | aIDENTIFIER { $$ = make_exprs(EXPR_IDENTIFIER, $1); } + | expr '?' expr ':' expr %prec COND { $$ = make_expr3(EXPR_COND, $1, $3, $5); } + | expr '|' expr { $$ = make_expr2(EXPR_OR , $1, $3); } + | expr '&' expr { $$ = make_expr2(EXPR_AND, $1, $3); } + | expr '+' expr { $$ = make_expr2(EXPR_ADD, $1, $3); } + | expr '-' expr { $$ = make_expr2(EXPR_SUB, $1, $3); } + | expr '*' expr { $$ = make_expr2(EXPR_MUL, $1, $3); } + | expr '/' expr { $$ = make_expr2(EXPR_DIV, $1, $3); } + | expr SHL expr { $$ = make_expr2(EXPR_SHL, $1, $3); } + | expr SHR expr { $$ = make_expr2(EXPR_SHR, $1, $3); } + | '~' expr { $$ = make_expr1(EXPR_NOT, $2); } + | '-' expr %prec NEG { $$ = make_expr1(EXPR_NEG, $2); } + | '*' expr %prec PPTR { $$ = make_expr1(EXPR_PPTR, $2); } + | '(' type ')' expr %prec CAST { $$ = make_exprt(EXPR_CAST, $2, $4); } + | tSIZEOF '(' type ')' { $$ = make_exprt(EXPR_SIZEOF, $3, NULL); } + | '(' expr ')' { $$ = $2; } + ; + +expr_list_const: expr_const + | expr_list_const ',' expr_const { LINK($3, $1); $$ = $3; } + ; + +expr_const: expr { $$ = $1; + if (!$$->is_const) yyerror("expression is not constant\n"); + } + ; + +externdef: tEXTERN tCONST type ident { $$ = $4; + set_type($$, $3, NULL); + } + ; + +fields: { $$ = NULL; } + | fields field { if ($2) { LINK($2, $1); $$ = $2; } + else { $$ = $1; } + } + ; + +field: s_field ';' { $$ = $1; } + | m_attributes uniondef ';' { $$ = make_var(NULL); $$->type = $2; $$->attrs = $1; } + | attributes ';' { $$ = make_var(NULL); $$->attrs = $1; } + | ';' { $$ = NULL; } + ; + +s_field: m_attributes type pident array { $$ = $3; set_type($$, $2, $4); $$->attrs = $1; } + ; + +funcdef: + m_attributes type callconv pident + '(' m_args ')' { set_type($4, $2, NULL); + $4->attrs = $1; + $$ = make_func($4, $6); + if (is_attr($4->attrs, ATTR_IN)) { + yyerror("Inapplicable attribute"); + } + } + ; + +m_ident: { $$ = NULL; } + | ident + ; + +t_ident: { $$ = NULL; } + | aIDENTIFIER { $$ = make_var($1); } + | aKNOWNTYPE { $$ = make_var($1); } + ; + +ident: aIDENTIFIER { $$ = make_var($1); } +/* some "reserved words" used in attributes are also used as field names in some MS IDL files */ + | aKNOWNTYPE { $$ = make_var($1); } + | tID { $$ = make_var($1); } + | tRETVAL { $$ = make_var($1); } + | tVERSION { $$ = make_var($1); } + ; + +base_type: tBYTE { $$ = make_type(RPC_FC_BYTE, NULL); } + | tWCHAR { $$ = make_type(RPC_FC_WCHAR, NULL); } + | int_std + | tSIGNED int_std { $$ = $2; $$->sign = 1; } + | tUNSIGNED int_std { $$ = $2; $$->sign = -1; + switch ($$->type) { + case RPC_FC_CHAR: $$->type = RPC_FC_BYTE; $$->sign = 0; break; + case RPC_FC_SMALL: $$->type = RPC_FC_USMALL; break; + case RPC_FC_SHORT: $$->type = RPC_FC_USHORT; break; + case RPC_FC_LONG: $$->type = RPC_FC_ULONG; break; + case RPC_FC_HYPER: + if (!$$->ref) { $$->ref = &std_uhyper; $$->sign = 0; } + break; + default: break; + } + } + | tFLOAT { $$ = make_type(RPC_FC_FLOAT, NULL); } + | tDOUBLE { $$ = make_type(RPC_FC_DOUBLE, NULL); } + | tBOOLEAN { $$ = make_type(RPC_FC_BYTE, &std_bool); /* ? */ } + | tERRORSTATUST { $$ = make_type(RPC_FC_ERROR_STATUS_T, NULL); } + | tHANDLET { $$ = make_type(RPC_FC_BIND_PRIMITIVE, NULL); /* ? */ } + ; + +m_int: + | tINT + ; + +int_std: tINT { $$ = make_type(RPC_FC_LONG, &std_int); } /* win32 only */ + | tSHORT m_int { $$ = make_type(RPC_FC_SHORT, NULL); } + | tLONG m_int { $$ = make_type(RPC_FC_LONG, NULL); } + | tHYPER m_int { $$ = make_type(RPC_FC_HYPER, NULL); } + | tINT64 { $$ = make_type(RPC_FC_HYPER, &std_int64); } + | tCHAR { $$ = make_type(RPC_FC_CHAR, NULL); } + ; + +coclass: tCOCLASS aIDENTIFIER { $$ = make_class($2); } + | tCOCLASS aKNOWNTYPE { $$ = make_class($2); } + ; + +coclasshdr: attributes coclass { $$ = $2; + $$->attrs = $1; + if (!parse_only && do_header) write_coclass($$); + } + ; + +coclassdef: coclasshdr '{' coclass_ints '}' { $$ = $1; + $$->ifaces = $3; + } + ; + +coclass_ints: { $$ = NULL; } + | coclass_ints coclass_int { LINK($2, $1); $$ = $2; } + ; + +coclass_int: + m_attributes interfacedec { $$ = make_ifref($2); $$->attrs = $1; } + ; + +dispinterface: tDISPINTERFACE aIDENTIFIER { $$ = get_type(0, $2, 0); } + | tDISPINTERFACE aKNOWNTYPE { $$ = get_type(0, $2, 0); } + ; + +dispinterfacehdr: attributes dispinterface { $$ = $2; + if ($$->defined) yyerror("multiple definition error\n"); + $$->attrs = $1; + $$->attrs = make_attr(ATTR_DISPINTERFACE); + LINK($$->attrs, $1); + $$->ref = find_type("IDispatch", 0); + if (!$$->ref) yyerror("IDispatch is undefined\n"); + $$->defined = TRUE; + if (!parse_only && do_header) write_forward($$); + } + ; + +dispint_props: tPROPERTIES ':' { $$ = NULL; } + | dispint_props s_field ';' { LINK($2, $1); $$ = $2; } + ; + +dispint_meths: tMETHODS ':' { $$ = NULL; } + | dispint_meths funcdef ';' { LINK($2, $1); $$ = $2; } + ; + +dispinterfacedef: dispinterfacehdr '{' + dispint_props + dispint_meths + '}' { $$ = $1; + $$->fields = $3; + $$->funcs = $4; + if (!parse_only && do_header) write_dispinterface($$); + } +/* FIXME: not sure how to handle this yet + | dispinterfacehdr '{' interface '}' { $$ = $1; + if (!parse_only && do_header) write_interface($$); + } +*/ + ; + +inherit: { $$ = NULL; } + | ':' aKNOWNTYPE { $$ = find_type2($2, 0); } + ; + +interface: tINTERFACE aIDENTIFIER { $$ = get_type(RPC_FC_IP, $2, 0); } + | tINTERFACE aKNOWNTYPE { $$ = get_type(RPC_FC_IP, $2, 0); } + ; + +interfacehdr: attributes interface { $$ = $2; + if ($$->defined) yyerror("multiple definition error\n"); + $$->attrs = $1; + $$->defined = TRUE; + if (!parse_only && do_header) write_forward($$); + } + ; + +interfacedef: interfacehdr inherit + '{' int_statements '}' { $$ = $1; + $$->ref = $2; + $$->funcs = $4; + if (!parse_only && do_header) write_interface($$); + } +/* MIDL is able to import the definition of a base class from inside the + * definition of a derived class, I'll try to support it with this rule */ + | interfacehdr ':' aIDENTIFIER + '{' import int_statements '}' { $$ = $1; + $$->ref = find_type2($3, 0); + if (!$$->ref) yyerror("base class %s not found in import\n", $3); + $$->funcs = $6; + if (!parse_only && do_header) write_interface($$); + } + | dispinterfacedef { $$ = $1; } + ; + +interfacedec: + interface ';' { $$ = $1; if (!parse_only && do_header) write_forward($$); } + | dispinterface ';' { $$ = $1; if (!parse_only && do_header) write_forward($$); } + ; + +module: tMODULE aIDENTIFIER { $$ = make_type(0, NULL); $$->name = $2; } + | tMODULE aKNOWNTYPE { $$ = make_type(0, NULL); $$->name = $2; } + ; + +modulehdr: attributes module { $$ = $2; + $$->attrs = $1; + } + ; + +moduledef: modulehdr '{' int_statements '}' { $$ = $1; + $$->funcs = $3; + /* FIXME: if (!parse_only && do_header) write_module($$); */ + } + ; + +p_ident: '*' pident %prec PPTR { $$ = $2; $$->ptr_level++; } + | tCONST p_ident { $$ = $2; /* FIXME */ } + ; + +pident: ident + | p_ident + | '(' pident ')' { $$ = $2; } + ; + +pident_list: + pident + | pident_list ',' pident { LINK($3, $1); $$ = $3; } + ; + +pointer_type: + tREF { $$ = RPC_FC_RP; } + | tUNIQUE { $$ = RPC_FC_UP; } + ; + +structdef: tSTRUCT t_ident '{' fields '}' { $$ = get_typev(RPC_FC_STRUCT, $2, tsSTRUCT); + /* overwrite RPC_FC_STRUCT with a more exact type */ + $$->type = get_struct_type( $4 ); + $$->fields = $4; + $$->defined = TRUE; + if(in_typelib) + add_struct($$); + } + ; + +type: tVOID { $$ = make_tref(NULL, make_type(0, NULL)); } + | aKNOWNTYPE { $$ = make_tref($1, find_type($1, 0)); } + | base_type { $$ = make_tref(NULL, $1); } + | tCONST type { $$ = uniq_tref($2); $$->ref->is_const = TRUE; } + | enumdef { $$ = make_tref(NULL, $1); } + | tENUM aIDENTIFIER { $$ = make_tref(NULL, find_type2($2, tsENUM)); } + | structdef { $$ = make_tref(NULL, $1); } + | tSTRUCT aIDENTIFIER { $$ = make_tref(NULL, get_type(RPC_FC_STRUCT, $2, tsSTRUCT)); } + | uniondef { $$ = make_tref(NULL, $1); } + | tUNION aIDENTIFIER { $$ = make_tref(NULL, find_type2($2, tsUNION)); } + ; + +typedef: tTYPEDEF m_attributes type pident_list { typeref_t *tref = uniq_tref($3); + $4->tname = tref->name; + tref->name = NULL; + $$ = type_ref(tref); + $$->attrs = $2; + if (!parse_only && do_header) write_typedef($$, $4); + if (in_typelib && $$->attrs) + add_typedef($$, $4); + reg_types($$, $4, 0); + } + ; + +uniondef: tUNION t_ident '{' fields '}' { $$ = get_typev(RPC_FC_NON_ENCAPSULATED_UNION, $2, tsUNION); + $$->fields = $4; + $$->defined = TRUE; + } + | tUNION t_ident + tSWITCH '(' s_field ')' + m_ident '{' cases '}' { var_t *u = $7; + $$ = get_typev(RPC_FC_ENCAPSULATED_UNION, $2, tsUNION); + if (!u) u = make_var("tagged_union"); + u->type = make_type(RPC_FC_NON_ENCAPSULATED_UNION, NULL); + u->type->fields = $9; + u->type->defined = TRUE; + LINK(u, $5); $$->fields = u; + $$->defined = TRUE; + } + ; + +version: + aNUM { $$ = MAKELONG($1, 0); } + | aNUM '.' aNUM { $$ = MAKELONG($1, $3); } + ; + +%% + +static attr_t *make_attr(enum attr_type type) +{ + attr_t *a = xmalloc(sizeof(attr_t)); + a->type = type; + a->u.ival = 0; + INIT_LINK(a); + return a; +} + +static attr_t *make_attrv(enum attr_type type, unsigned long val) +{ + attr_t *a = xmalloc(sizeof(attr_t)); + a->type = type; + a->u.ival = val; + INIT_LINK(a); + return a; +} + +static attr_t *make_attrp(enum attr_type type, void *val) +{ + attr_t *a = xmalloc(sizeof(attr_t)); + a->type = type; + a->u.pval = val; + INIT_LINK(a); + return a; +} + +static expr_t *make_expr(enum expr_type type) +{ + expr_t *e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = NULL; + e->u.lval = 0; + e->is_const = FALSE; + INIT_LINK(e); + return e; +} + +static expr_t *make_exprl(enum expr_type type, long val) +{ + expr_t *e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = NULL; + e->u.lval = val; + e->is_const = FALSE; + INIT_LINK(e); + /* check for numeric constant */ + if (type == EXPR_NUM || type == EXPR_HEXNUM) { + e->is_const = TRUE; + e->cval = val; + } + return e; +} + +static expr_t *make_exprs(enum expr_type type, char *val) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = NULL; + e->u.sval = val; + e->is_const = FALSE; + INIT_LINK(e); + /* check for predefined constants */ + if (type == EXPR_IDENTIFIER) { + var_t *c = find_const(val, 0); + if (c) { + e->u.sval = c->name; + free(val); + e->is_const = TRUE; + e->cval = c->lval; + } + } + return e; +} + +static expr_t *make_exprt(enum expr_type type, typeref_t *tref, expr_t *expr) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr; + e->u.tref = tref; + e->is_const = FALSE; + INIT_LINK(e); + /* check for cast of constant expression */ + if (type == EXPR_CAST && expr->is_const) { + e->is_const = TRUE; + e->cval = expr->cval; + } + return e; +} + +static expr_t *make_expr1(enum expr_type type, expr_t *expr) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr; + e->u.lval = 0; + e->is_const = FALSE; + INIT_LINK(e); + /* check for compile-time optimization */ + if (expr->is_const) { + e->is_const = TRUE; + switch (type) { + case EXPR_NEG: + e->cval = -expr->cval; + break; + case EXPR_NOT: + e->cval = ~expr->cval; + break; + default: + e->is_const = FALSE; + break; + } + } + return e; +} + +static expr_t *make_expr2(enum expr_type type, expr_t *expr1, expr_t *expr2) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr1; + e->u.ext = expr2; + e->is_const = FALSE; + INIT_LINK(e); + /* check for compile-time optimization */ + if (expr1->is_const && expr2->is_const) { + e->is_const = TRUE; + switch (type) { + case EXPR_ADD: + e->cval = expr1->cval + expr2->cval; + break; + case EXPR_SUB: + e->cval = expr1->cval - expr2->cval; + break; + case EXPR_MUL: + e->cval = expr1->cval * expr2->cval; + break; + case EXPR_DIV: + e->cval = expr1->cval / expr2->cval; + break; + case EXPR_OR: + e->cval = expr1->cval | expr2->cval; + break; + case EXPR_AND: + e->cval = expr1->cval & expr2->cval; + break; + case EXPR_SHL: + e->cval = expr1->cval << expr2->cval; + break; + case EXPR_SHR: + e->cval = expr1->cval >> expr2->cval; + break; + default: + e->is_const = FALSE; + break; + } + } + return e; +} + +static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, expr_t *expr3) +{ + expr_t *e; + e = xmalloc(sizeof(expr_t)); + e->type = type; + e->ref = expr1; + e->u.ext = expr2; + e->ext2 = expr3; + e->is_const = FALSE; + INIT_LINK(e); + /* check for compile-time optimization */ + if (expr1->is_const && expr2->is_const && expr3->is_const) { + e->is_const = TRUE; + switch (type) { + case EXPR_COND: + e->cval = expr1->cval ? expr2->cval : expr3->cval; + break; + default: + e->is_const = FALSE; + break; + } + } + return e; +} + +static type_t *make_type(unsigned char type, type_t *ref) +{ + type_t *t = xmalloc(sizeof(type_t)); + t->name = NULL; + t->type = type; + t->ref = ref; + t->rname = NULL; + t->attrs = NULL; + t->funcs = NULL; + t->fields = NULL; + t->ignore = parse_only; + t->is_const = FALSE; + t->sign = 0; + t->defined = FALSE; + t->written = FALSE; + t->typelib_idx = -1; + INIT_LINK(t); + return t; +} + +static typeref_t *make_tref(char *name, type_t *ref) +{ + typeref_t *t = xmalloc(sizeof(typeref_t)); + t->name = name; + t->ref = ref; + t->uniq = ref ? 0 : 1; + return t; +} + +static typeref_t *uniq_tref(typeref_t *ref) +{ + typeref_t *t = ref; + type_t *tp; + if (t->uniq) return t; + tp = make_type(0, t->ref); + tp->name = t->name; + t->name = NULL; + t->ref = tp; + t->uniq = 1; + return t; +} + +static type_t *type_ref(typeref_t *ref) +{ + type_t *t = ref->ref; + if (ref->name) free(ref->name); + free(ref); + return t; +} + +static void set_type(var_t *v, typeref_t *ref, expr_t *arr) +{ + v->type = ref->ref; + v->tname = ref->name; + ref->name = NULL; + free(ref); + v->array = arr; +} + +static ifref_t *make_ifref(type_t *iface) +{ + ifref_t *l = xmalloc(sizeof(ifref_t)); + l->iface = iface; + l->attrs = NULL; + INIT_LINK(l); + return l; +} + +static var_t *make_var(char *name) +{ + var_t *v = xmalloc(sizeof(var_t)); + v->name = name; + v->ptr_level = 0; + v->type = NULL; + v->tname = NULL; + v->attrs = NULL; + v->array = NULL; + v->eval = NULL; + v->lval = 0; + INIT_LINK(v); + return v; +} + +static func_t *make_func(var_t *def, var_t *args) +{ + func_t *f = xmalloc(sizeof(func_t)); + f->def = def; + f->args = args; + f->ignore = parse_only; + f->idx = -1; + INIT_LINK(f); + return f; +} + +static class_t *make_class(char *name) +{ + class_t *c = xmalloc(sizeof(class_t)); + c->name = name; + c->attrs = NULL; + c->ifaces = NULL; + INIT_LINK(c); + return c; +} + +#define HASHMAX 64 + +static int hash_ident(const char *name) +{ + const char *p = name; + int sum = 0; + /* a simple sum hash is probably good enough */ + while (*p) { + sum += *p; + p++; + } + return sum & (HASHMAX-1); +} + +/***** type repository *****/ + +struct rtype { + char *name; + type_t *type; + int t; + struct rtype *next; +}; + +struct rtype *type_hash[HASHMAX]; + +static type_t *reg_type(type_t *type, char *name, int t) +{ + struct rtype *nt; + int hash; + if (!name) { + yyerror("registering named type without name\n"); + return type; + } + hash = hash_ident(name); + nt = xmalloc(sizeof(struct rtype)); + nt->name = name; + nt->type = type; + nt->t = t; + nt->next = type_hash[hash]; + type_hash[hash] = nt; + return type; +} + +/* determine pointer type from attrs */ +static unsigned char get_pointer_type( type_t *type ) +{ + int t; + if (is_attr( type->attrs, ATTR_STRING )) + { + type_t *t = type; + while( t->type == 0 && t->ref ) + t = t->ref; + switch( t->type ) + { + case RPC_FC_CHAR: + return RPC_FC_C_CSTRING; + case RPC_FC_WCHAR: + return RPC_FC_C_WSTRING; + } + } + t = get_attrv( type->attrs, ATTR_POINTERTYPE ); + if (t) return t; + return RPC_FC_FP; +} + +static type_t *reg_types(type_t *type, var_t *names, int t) +{ + type_t *ptr = type; + int ptrc = 0; + + while (names) { + var_t *next = NEXT_LINK(names); + if (names->name) { + type_t *cur = ptr; + int cptr = names->ptr_level; + if (cptr > ptrc) { + while (cptr > ptrc) { + int t = get_pointer_type( cur ); + cur = ptr = make_type(t, cur); + ptrc++; + } + } else { + while (cptr < ptrc) { + cur = cur->ref; + cptr++; + } + } + reg_type(cur, names->name, t); + } + free(names); + names = next; + } + return type; +} + +static type_t *find_type(char *name, int t) +{ + struct rtype *cur = type_hash[hash_ident(name)]; + while (cur && (cur->t != t || strcmp(cur->name, name))) + cur = cur->next; + if (!cur) { + yyerror("type %s not found\n", name); + return NULL; + } + return cur->type; +} + +static type_t *find_type2(char *name, int t) +{ + type_t *tp = find_type(name, t); + free(name); + return tp; +} + +int is_type(const char *name) +{ + struct rtype *cur = type_hash[hash_ident(name)]; + while (cur && (cur->t || strcmp(cur->name, name))) + cur = cur->next; + if (cur) return TRUE; + return FALSE; +} + +static type_t *get_type(unsigned char type, char *name, int t) +{ + struct rtype *cur = NULL; + type_t *tp; + if (name) { + cur = type_hash[hash_ident(name)]; + while (cur && (cur->t != t || strcmp(cur->name, name))) + cur = cur->next; + } + if (cur) { + free(name); + return cur->type; + } + tp = make_type(type, NULL); + tp->name = name; + if (!name) return tp; + return reg_type(tp, name, t); +} + +static type_t *get_typev(unsigned char type, var_t *name, int t) +{ + char *sname = NULL; + if (name) { + sname = name->name; + free(name); + } + return get_type(type, sname, t); +} + +static int get_struct_type(var_t *field) +{ + int has_pointer = 0; + int has_conformant_array = 0; + int has_conformant_string = 0; + + while (field) + { + type_t *t = field->type; + + /* get the base type */ + while( (t->type == 0) && t->ref ) + t = t->ref; + + switch (t->type) + { + /* + * RPC_FC_BYTE, RPC_FC_STRUCT, etc + * Simple types don't effect the type of struct. + * A struct containing a simple struct is still a simple struct. + * So long as we can block copy the data, we return RPC_FC_STRUCT. + */ + case 0: /* void pointer */ + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_INT3264: + case RPC_FC_UINT3264: + case RPC_FC_HYPER: + case RPC_FC_FLOAT: + case RPC_FC_DOUBLE: + case RPC_FC_STRUCT: + case RPC_FC_ENUM16: + case RPC_FC_ENUM32: + break; + + case RPC_FC_UP: + case RPC_FC_FP: + has_pointer = 1; + break; + case RPC_FC_CARRAY: + has_conformant_array = 1; + break; + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + has_conformant_string = 1; + break; + + /* + * Propagate member attributes + * a struct should be at least as complex as its member + */ + case RPC_FC_CVSTRUCT: + has_conformant_string = 1; + has_pointer = 1; + break; + + case RPC_FC_CPSTRUCT: + has_conformant_array = 1; + has_pointer = 1; + break; + + case RPC_FC_CSTRUCT: + has_conformant_array = 1; + break; + + case RPC_FC_PSTRUCT: + has_pointer = 1; + break; + + default: + fprintf(stderr,"Unknown struct member %s with type (0x%02x)\n", + field->name, t->type); + /* fallthru - treat it as complex */ + + /* as soon as we see one of these these members, it's bogus... */ + case RPC_FC_IP: + case RPC_FC_ENCAPSULATED_UNION: + case RPC_FC_NON_ENCAPSULATED_UNION: + case RPC_FC_TRANSMIT_AS: + case RPC_FC_REPRESENT_AS: + case RPC_FC_PAD: + case RPC_FC_EMBEDDED_COMPLEX: + case RPC_FC_BOGUS_STRUCT: + return RPC_FC_BOGUS_STRUCT; + } + field = NEXT_LINK(field); + } + + if( has_conformant_string && has_pointer ) + return RPC_FC_CVSTRUCT; + if( has_conformant_array && has_pointer ) + return RPC_FC_CPSTRUCT; + if( has_conformant_array ) + return RPC_FC_CSTRUCT; + if( has_pointer ) + return RPC_FC_PSTRUCT; + return RPC_FC_STRUCT; +} + +/***** constant repository *****/ + +struct rconst { + char *name; + var_t *var; + struct rconst *next; +}; + +struct rconst *const_hash[HASHMAX]; + +static var_t *reg_const(var_t *var) +{ + struct rconst *nc; + int hash; + if (!var->name) { + yyerror("registering constant without name\n"); + return var; + } + hash = hash_ident(var->name); + nc = xmalloc(sizeof(struct rconst)); + nc->name = var->name; + nc->var = var; + nc->next = const_hash[hash]; + const_hash[hash] = nc; + return var; +} + +static var_t *find_const(char *name, int f) +{ + struct rconst *cur = const_hash[hash_ident(name)]; + while (cur && strcmp(cur->name, name)) + cur = cur->next; + if (!cur) { + if (f) yyerror("constant %s not found\n", name); + return NULL; + } + return cur->var; +} diff --git a/reactos/tools/widl/proxy.c b/reactos/tools/widl/proxy.c new file mode 100644 index 00000000000..a1c8c2431b4 --- /dev/null +++ b/reactos/tools/widl/proxy.c @@ -0,0 +1,1057 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * Copyright 2004 Mike McCormack + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" + +#define END_OF_LIST(list) \ + do { \ + if (list) { \ + while (NEXT_LINK(list)) \ + list = NEXT_LINK(list); \ + } \ + } while(0) + +static FILE* proxy; +static int indent = 0; + +/* FIXME: support generation of stubless proxies */ + +static int print_proxy( const char *format, ... ) +{ + va_list va; + int i, r; + + va_start( va, format ); + for( i=0; itype; + while( (t->type == 0) && t->ref ) + t = t->ref; + return t; +} + +static void write_stubdescproto(void) +{ + print_proxy( "extern const MIDL_STUB_DESC Object_StubDesc;\n"); + print_proxy( "\n"); +} + +static void write_stubdesc(void) +{ + print_proxy( "const MIDL_STUB_DESC Object_StubDesc = {\n"); + print_proxy( " 0,\n"); + print_proxy( " NdrOleAllocate,\n"); + print_proxy( " NdrOleFree,\n"); + print_proxy( " {0}, 0, 0, 0, 0,\n"); + print_proxy( " 0 /* __MIDL_TypeFormatString.Format */\n"); + print_proxy( "};\n"); + print_proxy( "\n"); +} + +static void write_formatdesc( const char *str ) +{ + print_proxy( "typedef struct _MIDL_%s_FORMAT_STRING\n", str ); + indent++; + print_proxy( "{\n"); + print_proxy( "short Pad;\n"); + print_proxy( "unsigned char Format[%s_FORMAT_STRING_SIZE];\n", str); + indent--; + print_proxy( "} MIDL_%s_FORMAT_STRING;\n", str); + print_proxy( "\n"); +} + +static void write_formatstringsdecl(void) +{ + print_proxy( "#define TYPE_FORMAT_STRING_SIZE %d\n",1); /* FIXME */ + print_proxy( "#define PROC_FORMAT_STRING_SIZE %d\n",1); /* FIXME */ + fprintf(proxy, "\n"); + write_formatdesc( "TYPE" ); + write_formatdesc( "PROC" ); + fprintf(proxy, "\n"); + print_proxy( "extern const MIDL_TYPE_FORMAT_STRING __MIDL_TypeFormatString;\n"); + print_proxy( "extern const MIDL_PROC_FORMAT_STRING __MIDL_ProcFormatString;\n"); + print_proxy( "\n"); +} + +static void write_formatstring( int proc ) +{ + const char *t, *n; + if( !proc ) + { + t = "TYPE"; + n = "Type"; + } + else + { + t = "PROC"; + n = "Proc"; + } + print_proxy( "static const MIDL_%s_FORMAT_STRING __MIDL_%sFormatString =\n", t, n); + print_proxy( "{\n"); + indent++; + print_proxy( "0,\n"); + print_proxy( "{\n"); + indent++; + print_proxy( "0\n"); + indent--; + print_proxy( "}\n"); + indent--; + print_proxy( "};\n"); + print_proxy( "\n"); +} + +static void init_proxy() +{ + if (proxy) return; + if(!(proxy = fopen(proxy_name, "w"))) + error("Could not open %s for output\n", proxy_name); + print_proxy( "/*** Autogenerated by WIDL %s - Do not edit ***/\n", WIDL_FULLVERSION); + print_proxy( "\n"); + print_proxy( "#ifndef __REDQ_RPCPROXY_H_VERSION__\n"); + print_proxy( "#define __REQUIRED_RPCPROXY_H_VERSION__ 440\n"); + print_proxy( "#endif /* __REDQ_RPCPROXY_H_VERSION__ */\n"); + print_proxy( "\n"); + print_proxy( "#include \"rpcproxy.h\"\n"); + print_proxy( "#ifndef __RPCPROXY_H_VERSION__\n"); + print_proxy( "#error This code needs a newer version of rpcproxy.h\n"); + print_proxy( "#endif /* __RPCPROXY_H_VERSION__ */\n"); + print_proxy( "\n"); + print_proxy( "#include \"%s\"\n", header_name); + print_proxy( "\n"); + write_formatstringsdecl(); + write_stubdescproto(); +} + +static void clear_output_vars( var_t *arg ) +{ + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_OUT) && !is_attr(arg->attrs, ATTR_IN)) { + print_proxy( "if(%s)\n", arg->name ); + indent++; + print_proxy( "MIDL_memset( %s, 0, sizeof( ", arg->name ); + indent--; + write_type(proxy, arg->type, arg, arg->tname); + fprintf( proxy, " ));\n" ); + } + arg = PREV_LINK(arg); + } +} + +static int is_pointer(var_t *arg) +{ + if (arg->ptr_level) + return 1; + if (arg->type->type == RPC_FC_FP ) + return 1; + return 0; +} + +static void proxy_check_pointers( var_t *arg ) +{ + END_OF_LIST(arg); + while (arg) { + if (is_pointer(arg)) { + print_proxy( "if(!%s)\n", arg->name ); + indent++; + print_proxy( "RpcRaiseException(RPC_X_NULL_REF_POINTER);\n"); + indent--; + } + arg = PREV_LINK(arg); + } +} + +static void marshall_size_arg( var_t *arg ) +{ + int index = 0; + type_t *type = get_base_type(arg); + expr_t *expr; + + expr = get_attrp( arg->attrs, ATTR_SIZEIS ); + if (expr) + { + print_proxy( "_StubMsg.MaxCount = ", arg->name ); + write_expr(proxy, expr); + fprintf(proxy, ";\n\n"); + print_proxy( "NdrConformantArrayBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + return; + } + + switch( type->type ) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 1, arg->name ); + break; + + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_ENUM16: + print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 2, arg->name ); + break; + + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + print_proxy( "_StubMsg.BufferLength += %d; /* %s */\n", 4, arg->name ); + break; + + case RPC_FC_STRUCT: + print_proxy( "NdrSimpleStructBufferSize(&_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index ); + break; + + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + case RPC_FC_CARRAY: + print_proxy( "NdrConformantArrayBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + break; + + case RPC_FC_BOGUS_STRUCT: + print_proxy( "NdrComplexStructBufferSize(&_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index ); + break; + + case RPC_FC_FP: + { + var_t temp; + memset( &temp, 0, sizeof temp ); + temp.type = type->ref; + temp.name = arg->name; /* FIXME */ +#if 0 + print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name ); +#endif + marshall_size_arg( &temp ); + } + break; + + case RPC_FC_IP: + print_proxy( "NdrPointerBufferSize( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + break; + + default: + print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); + } +} + +static void proxy_gen_marshall_size( var_t *arg ) +{ + print_proxy( "_StubMsg.BufferLength = 0U;\n" ); + + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_IN)) + { + marshall_size_arg( arg ); + fprintf(proxy, "\n"); + } + arg = PREV_LINK(arg); + } +} + +static void marshall_copy_arg( var_t *arg ) +{ + int index = 0; + type_t *type = get_base_type(arg); + expr_t *expr; + + expr = get_attrp( arg->attrs, ATTR_SIZEIS ); + if (expr) + { + print_proxy( "_StubMsg.MaxCount = ", arg->name ); + write_expr(proxy, expr); + fprintf(proxy, ";\n\n"); + print_proxy( "NdrConformantArrayMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + return; + } + + switch( type->type ) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_ENUM16: + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + print_proxy( "*(("); + write_type(proxy, arg->type, arg, arg->tname); + fprintf(proxy,"*)_StubMsg.Buffer)++ = %s;\n", arg->name ); + break; + + case RPC_FC_STRUCT: + /* FIXME: add the format string, and set the index below */ + print_proxy( "NdrSimpleStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + break; + + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + case RPC_FC_CARRAY: + break; + + case RPC_FC_BOGUS_STRUCT: + print_proxy( "NdrComplexStructMarshall(&_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d] );\n", index ); + break; + + case RPC_FC_FP: + { + var_t temp; + memset( &temp, 0, sizeof temp ); + temp.type = type->ref; + temp.name = arg->name; /* FIXME */ +#if 0 + print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name ); +#endif + marshall_copy_arg( &temp ); + } + break; + + case RPC_FC_IP: + print_proxy( "NdrPointerMarshall( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + break; + + default: + print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); + } +} + +static void gen_marshall_copydata( var_t *arg ) +{ + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_IN)) + { + marshall_copy_arg( arg ); + fprintf(proxy, "\n"); + } + arg = PREV_LINK(arg); + } +} + +static void gen_marshall( var_t *arg ) +{ + /* generated code to determine the size of the buffer required */ + proxy_gen_marshall_size( arg ); + + /* generated code to allocate the buffer */ + print_proxy( "NdrProxyGetBuffer(This, &_StubMsg);\n" ); + + /* generated code to copy the args into the buffer */ + gen_marshall_copydata( arg ); + + print_proxy( "\n"); +} + +static void unmarshall_copy_arg( var_t *arg ) +{ + int index = 0; + type_t *type = get_base_type(arg); + expr_t *expr; + + expr = get_attrp( arg->attrs, ATTR_SIZEIS ); + if (expr) + { + print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + return; + } + + switch( type->type ) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_ENUM16: + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + print_proxy( "%s = *((", arg->name ); + write_type(proxy, arg->type, arg, arg->tname); + fprintf(proxy,"*)_StubMsg.Buffer)++;\n"); + break; + + case RPC_FC_STRUCT: + print_proxy( "NdrSimpleStructUnmarshall(&_StubMsg, (unsigned char**)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index ); + break; + + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + case RPC_FC_CARRAY: + print_proxy( "NdrConformantArrayUnmarshall( &_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d]);\n", index ); + break; + + case RPC_FC_BOGUS_STRUCT: + print_proxy( "NdrComplexStructUnmarshall(&_StubMsg, (unsigned char*)%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0 );\n", index ); + break; + + case RPC_FC_FP: + { + var_t temp; + memset( &temp, 0, sizeof temp ); + temp.type = type->ref; + temp.name = arg->name; /* FIXME */ +#if 1 + print_proxy( "/* FIXME: %s use the right name for %s */\n", __FUNCTION__, arg->name ); +#endif + unmarshall_copy_arg( &temp ); + } + break; + + case RPC_FC_IP: + print_proxy( "NdrPointerUnmarshall(&_StubMsg, (unsigned char**)&%s, ", arg->name ); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], 0);\n", index ); + break; + + default: + print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); + } +} + +static void gen_unmarshall( var_t *arg ) +{ + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_OUT)) + { + unmarshall_copy_arg( arg ); + fprintf(proxy, "\n"); + } + arg = PREV_LINK(arg); + } +} + +static void free_variable( var_t *arg ) +{ + var_t *constraint; + int index = 0; /* FIXME */ + type_t *type; + expr_t *expr; + + expr = get_attrp( arg->attrs, ATTR_SIZEIS ); + if (expr) + { + print_proxy( "_StubMsg.MaxCount = ", arg->name ); + write_expr(proxy, expr); + fprintf(proxy, ";\n\n"); + print_proxy( "NdrClearOutParameters( &_StubMsg, "); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index ); + fprintf(proxy, "(void*)%s );\n", arg->name ); + return; + } + + type = get_base_type(arg); + switch( type->type ) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_ENUM16: + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + case RPC_FC_STRUCT: + break; + + case RPC_FC_FP: + case RPC_FC_IP: + constraint = get_attrp( arg->attrs, ATTR_IIDIS ); + if( constraint ) + print_proxy( "_StubMsg.MaxCount = (unsigned long) ( %s );\n",constraint->name); + print_proxy( "NdrClearOutParameters( &_StubMsg, "); + fprintf(proxy, "&__MIDL_TypeFormatString.Format[%d], ", index ); + fprintf(proxy, "(void*)%s );\n", arg->name ); + break; + + default: + print_proxy("/* FIXME: %s code for %s type %d missing */\n", __FUNCTION__, arg->name, type->type ); + } +} + +static void proxy_free_variables( var_t *arg ) +{ + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_OUT)) + { + free_variable( arg ); + fprintf(proxy, "\n"); + } + arg = PREV_LINK(arg); + } +} + +static void gen_proxy(type_t *iface, func_t *cur, int idx) +{ + var_t *def = cur->def; + int has_ret = !is_void(def->type, def); + + indent = 0; + write_type(proxy, def->type, def, def->tname); + print_proxy( " STDMETHODCALLTYPE %s_", iface->name); + write_name(proxy, def); + print_proxy( "_Proxy(\n"); + write_args(proxy, cur->args, iface->name, 1, TRUE); + print_proxy( ")\n"); + print_proxy( "{\n"); + indent ++; + /* local variables */ + if (has_ret) { + print_proxy( "" ); + write_type(proxy, def->type, def, def->tname); + print_proxy( " _RetVal;\n"); + } + print_proxy( "RPC_MESSAGE _Msg;\n" ); + print_proxy( "MIDL_STUB_MESSAGE _StubMsg;\n" ); + print_proxy( "\n"); + + /* FIXME: trace */ + clear_output_vars( cur->args ); + + print_proxy( "RpcTryExcept\n" ); + print_proxy( "{\n" ); + indent++; + print_proxy( "NdrProxyInitialize(This, &_Msg, &_StubMsg, &Object_StubDesc, %d);\n", idx); + proxy_check_pointers( cur->args ); + + print_proxy( "RpcTryFinally\n" ); + print_proxy( "{\n" ); + indent++; + + gen_marshall( cur->args ); + + print_proxy( "NdrProxySendReceive(This, &_StubMsg);\n" ); + fprintf(proxy, "\n"); + print_proxy("if ((_Msg.DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n"); + indent++; + print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" ); + indent--; + fprintf(proxy, "\n"); + + gen_unmarshall( cur->args ); + if (has_ret) { + /* + * FIXME: We only need to round the buffer up if it could be unaligned... + * We should calculate how much buffer we used and output the following + * line only if necessary. + */ + print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n"); + + print_proxy( "_RetVal = *((" ); + write_type(proxy, def->type, def, def->tname); + fprintf(proxy, "*)_StubMsg.Buffer)++;\n"); + } + + indent--; + print_proxy( "}\n"); + print_proxy( "RpcFinally\n" ); + print_proxy( "{\n" ); + indent++; + print_proxy( "NdrProxyFreeBuffer(This, &_StubMsg);\n" ); + indent--; + print_proxy( "}\n"); + print_proxy( "RpcEndFinally\n" ); + indent--; + print_proxy( "}\n" ); + print_proxy( "RpcExcept(_StubMsg.dwStubPhase != PROXY_SENDRECEIVE)\n" ); + print_proxy( "{\n" ); + if (has_ret) { + indent++; + proxy_free_variables( cur->args ); + print_proxy( "_RetVal = NdrProxyErrorHandler(RpcExceptionCode());\n" ); + indent--; + } + print_proxy( "}\n" ); + print_proxy( "RpcEndExcept\n" ); + + if (has_ret) { + print_proxy( "return _RetVal;\n" ); + } + indent--; + print_proxy( "}\n"); + print_proxy( "\n"); +} + +static void stub_write_locals( var_t *arg ) +{ + int n = 0; + while (arg) { + int outptr = is_attr(arg->attrs, ATTR_OUT); + + /* create a temporary variable to store the output */ + if (outptr) { + var_t temp; + memset( &temp, 0, sizeof temp ); + temp.ptr_level = arg->ptr_level - 1; /* dereference once */ + print_proxy(""); + write_type(proxy, arg->type, &temp, arg->tname); + fprintf(proxy, " _M%d;\n",n++); + } + print_proxy(""); + write_type(proxy, arg->type, arg, arg->tname); + fprintf(proxy, " "); + write_name(proxy, arg); + fprintf(proxy, ";\n"); + arg = NEXT_LINK(arg); + } +} + +static void stub_unmarshall( var_t *arg ) +{ + int n = 0; + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_IN)) + { + unmarshall_copy_arg( arg ); + fprintf(proxy,"\n"); + } + else if (is_attr(arg->attrs, ATTR_OUT)) { + type_t *type = get_base_type(arg); + switch( type->type ) + { + case RPC_FC_STRUCT: + print_proxy("MIDL_memset("); + write_name(proxy, arg); + fprintf(proxy,", 0, sizeof("); + write_type(proxy, arg->type, arg, arg->tname); + fprintf(proxy,"));\n"); + break; + default: + print_proxy(""); + write_name(proxy, arg); + fprintf(proxy," = &_M%d;\n", n); + print_proxy("_M%d = 0;\n", n++); + break; + } + } + arg = PREV_LINK(arg); + } +} + +static void stub_gen_marshall_size( var_t *arg ) +{ + print_proxy( "_StubMsg.BufferLength = 0U;\n" ); + + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_OUT)) + marshall_size_arg( arg ); + arg = PREV_LINK(arg); + } +} + +static void stub_gen_marshall_copydata( var_t *arg ) +{ + END_OF_LIST(arg); + while (arg) { + if (is_attr(arg->attrs, ATTR_OUT)) + marshall_copy_arg( arg ); + arg = PREV_LINK(arg); + } +} + +static void stub_genmarshall( var_t *args ) +{ + /* FIXME: size buffer */ + stub_gen_marshall_size( args ); + + print_proxy("NdrStubGetBuffer(This, pRpcChannelBuffer, &_StubMsg);\n"); + + stub_gen_marshall_copydata( args ); +} + +static void gen_stub(type_t *iface, func_t *cur, char *cas) +{ + var_t *def = cur->def; + var_t *arg; + int has_ret = !is_void(def->type, def); + + indent = 0; + print_proxy( "void __RPC_STUB %s_", iface->name); + write_name(proxy, def); + print_proxy( "_Stub(\n"); + indent++; + print_proxy( "IRpcStubBuffer* This,\n"); + print_proxy( "IRpcChannelBuffer* pRpcChannelBuffer,\n"); + print_proxy( "PRPC_MESSAGE _Msg,\n"); + print_proxy( "DWORD* _pdwStubPhase)\n"); + indent--; + print_proxy( "{\n"); + indent++; + /* local variables */ + if (has_ret) { + print_proxy(""); + write_type(proxy, def->type, def, def->tname); + fprintf(proxy, " _RetVal;\n"); + } + print_proxy("%s * _This = (%s*)((CStdStubBuffer*)This)->pvServerObject;\n", iface->name, iface->name); + print_proxy("MIDL_STUB_MESSAGE _StubMsg;\n"); + stub_write_locals( cur->args ); + fprintf(proxy, "\n"); + + /* FIXME: trace */ + + print_proxy("NdrStubInitialize(_Msg, &_StubMsg, &Object_StubDesc, pRpcChannelBuffer);\n"); + fprintf(proxy, "\n"); + + print_proxy("RpcTryFinally\n"); + print_proxy("{\n"); + indent++; + print_proxy("if ((_Msg->DataRepresentation&0xffff) != NDR_LOCAL_DATA_REPRESENTATION)\n"); + indent++; + print_proxy("NdrConvert( &_StubMsg, &__MIDL_ProcFormatString.Format[0]);\n" ); + indent--; + fprintf(proxy, "\n"); + + stub_unmarshall( cur->args ); + fprintf(proxy, "\n"); + + print_proxy("*_pdwStubPhase = STUB_CALL_SERVER;\n"); + fprintf(proxy, "\n"); + print_proxy(""); + if (has_ret) fprintf(proxy, "_RetVal = "); + fprintf(proxy, "%s_", iface->name); + if (cas) fprintf(proxy, "%s_Stub", cas); + else write_name(proxy, def); + fprintf(proxy, "(_This"); + arg = cur->args; + if (arg) { + END_OF_LIST(arg); + while (arg) { + fprintf(proxy, ", "); + write_name(proxy, arg); + arg = PREV_LINK(arg); + } + } + fprintf(proxy, ");\n"); + fprintf(proxy, "\n"); + print_proxy("*_pdwStubPhase = STUB_MARSHAL;\n"); + fprintf(proxy, "\n"); + + stub_genmarshall( cur->args ); + fprintf(proxy, "\n"); + + if (has_ret) { + /* + * FIXME: We only need to round the buffer up if it could be unaligned... + * We should calculate how much buffer we used and output the following + * line only if necessary. + */ + print_proxy( "_StubMsg.Buffer = (unsigned char *)(((long)_StubMsg.Buffer + 3) & ~ 0x3);\n"); + + print_proxy( "*((" ); + write_type(proxy, def->type, def, def->tname); + fprintf(proxy, "*)_StubMsg.Buffer)++ = _RetVal;\n"); + } + + indent--; + print_proxy("}\n"); + print_proxy("RpcFinally\n"); + print_proxy("{\n"); + print_proxy("}\n"); + print_proxy("RpcEndFinally\n"); + + print_proxy("_Msg->BufferLength = ((long)_StubMsg.Buffer - (long)_Msg->Buffer);\n"); + indent--; + + print_proxy("}\n"); + print_proxy("\n"); +} + +static int write_proxy_methods(type_t *iface) +{ + func_t *cur = iface->funcs; + int i = 0; + + END_OF_LIST(cur); + + if (iface->ref) i = write_proxy_methods(iface->ref); + while (cur) { + var_t *def = cur->def; + if (!is_callas(def->attrs)) { + if (i) fprintf(proxy, ",\n"); + print_proxy( "%s_", iface->name); + write_name(proxy, def); + fprintf(proxy, "_Proxy"); + i++; + } + cur = PREV_LINK(cur); + } + return i; +} + +static int write_stub_methods(type_t *iface) +{ + func_t *cur = iface->funcs; + int i = 0; + + END_OF_LIST(cur); + + if (iface->ref) i = write_stub_methods(iface->ref); + else return i; /* skip IUnknown */ + while (cur) { + var_t *def = cur->def; + if (!is_local(def->attrs)) { + if (i) fprintf(proxy,",\n"); + print_proxy( "%s_", iface->name); + write_name(proxy, def); + fprintf(proxy, "_Stub"); + i++; + } + cur = PREV_LINK(cur); + } + return i; +} + +static void write_proxy(type_t *iface) +{ + int midx = -1, stubs; + func_t *cur = iface->funcs; + + if (!cur) return; + + END_OF_LIST(cur); + + /* FIXME: check for [oleautomation], shouldn't generate proxies/stubs if specified */ + + fprintf(proxy, "/*****************************************************************************\n"); + fprintf(proxy, " * %s interface\n", iface->name); + fprintf(proxy, " */\n"); + while (cur) { + var_t *def = cur->def; + if (!is_local(def->attrs)) { + var_t *cas = is_callas(def->attrs); + char *cname = cas ? cas->name : NULL; + int idx = cur->idx; + if (cname) { + func_t *m = iface->funcs; + while (m && strcmp(get_name(m->def), cname)) + m = NEXT_LINK(m); + idx = m->idx; + } + gen_proxy(iface, cur, idx); + gen_stub(iface, cur, cname); + if (midx == -1) midx = idx; + else if (midx != idx) yyerror("method index mismatch in write_proxy"); + midx++; + } + cur = PREV_LINK(cur); + } + + /* proxy vtable */ + print_proxy( "const CINTERFACE_PROXY_VTABLE(%d) _%sProxyVtbl =\n", midx, iface->name); + print_proxy( "{\n"); + indent++; + print_proxy( "{\n", iface->name); + indent++; + print_proxy( "&IID_%s,\n", iface->name); + indent--; + print_proxy( "},\n"); + print_proxy( "{\n"); + indent++; + write_proxy_methods(iface); + fprintf(proxy, "\n"); + indent--; + print_proxy( "}\n"); + indent--; + print_proxy( "};\n"); + fprintf(proxy, "\n\n"); + + /* stub vtable */ + print_proxy( "static const PRPC_STUB_FUNCTION %s_table[] =\n", iface->name); + print_proxy( "{\n"); + indent++; + stubs = write_stub_methods(iface); + fprintf(proxy, "\n"); + indent--; + fprintf(proxy, "};\n"); + print_proxy( "\n"); + print_proxy( "const CInterfaceStubVtbl _%sStubVtbl =\n", iface->name); + print_proxy( "{\n"); + indent++; + print_proxy( "{\n"); + indent++; + print_proxy( "&IID_%s,\n", iface->name); + print_proxy( "0,\n"); + print_proxy( "%d,\n", stubs+3); + print_proxy( "&%s_table[-3],\n", iface->name); + indent--; + print_proxy( "},\n", iface->name); + print_proxy( "{\n"); + indent++; + print_proxy( "CStdStubBuffer_METHODS\n"); + indent--; + print_proxy( "}\n"); + indent--; + print_proxy( "};\n"); + print_proxy( "\n"); +} + +void write_proxies(ifref_t *ifaces) +{ + ifref_t *lcur = ifaces; + ifref_t *cur; + char *file_id = proxy_token; + int c; + + if (!do_proxies) return; + if (!lcur) return; + END_OF_LIST(lcur); + + init_proxy(); + if(!proxy) return; + + cur = lcur; + while (cur) { + if (is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) + write_proxy(cur->iface); + cur = PREV_LINK(cur); + } + + if (!proxy) return; + + write_stubdesc(); + + print_proxy( "#if !defined(__RPC_WIN32__)\n"); + print_proxy( "#error Currently only Wine and WIN32 are supported.\n"); + print_proxy( "#endif\n"); + print_proxy( "\n"); + write_formatstring( 1 ); + write_formatstring( 0 ); + + fprintf(proxy, "const CInterfaceProxyVtbl* _%s_ProxyVtblList[] =\n", file_id); + fprintf(proxy, "{\n"); + cur = lcur; + while (cur) { + if(cur->iface->ref && cur->iface->funcs && + is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) + fprintf(proxy, " (CInterfaceProxyVtbl*)&_%sProxyVtbl,\n", cur->iface->name); + cur = PREV_LINK(cur); + } + fprintf(proxy, " 0\n"); + fprintf(proxy, "};\n"); + fprintf(proxy, "\n"); + + fprintf(proxy, "const CInterfaceStubVtbl* _%s_StubVtblList[] =\n", file_id); + fprintf(proxy, "{\n"); + cur = lcur; + while (cur) { + if(cur->iface->ref && cur->iface->funcs && + is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) + fprintf(proxy, " (CInterfaceStubVtbl*)&_%sStubVtbl,\n", cur->iface->name); + cur = PREV_LINK(cur); + } + fprintf(proxy, " 0\n"); + fprintf(proxy, "};\n"); + fprintf(proxy, "\n"); + + fprintf(proxy, "PCInterfaceName const _%s_InterfaceNamesList[] =\n", file_id); + fprintf(proxy, "{\n"); + cur = lcur; + while (cur) { + if(cur->iface->ref && cur->iface->funcs && + is_object(cur->iface->attrs) && !is_local(cur->iface->attrs)) + fprintf(proxy, " \"%s\",\n", cur->iface->name); + cur = PREV_LINK(cur); + } + fprintf(proxy, " 0\n"); + fprintf(proxy, "};\n"); + fprintf(proxy, "\n"); + + fprintf(proxy, "#define _%s_CHECK_IID(n) IID_GENERIC_CHECK_IID(_%s, pIID, n)\n", file_id, file_id); + fprintf(proxy, "\n"); + fprintf(proxy, "int __stdcall _%s_IID_Lookup(const IID* pIID, int* pIndex)\n", file_id); + fprintf(proxy, "{\n"); + cur = lcur; + c = 0; + while (cur) { + if(cur->iface->ref) + { + fprintf(proxy, " if (!_%s_CHECK_IID(%d))\n", file_id, c); + fprintf(proxy, " {\n"); + fprintf(proxy, " *pIndex = %d;\n", c); + fprintf(proxy, " return 1;\n"); + fprintf(proxy, " }\n"); + c++; + } + cur = PREV_LINK(cur); + } + fprintf(proxy, " return 0;\n"); + fprintf(proxy, "}\n"); + fprintf(proxy, "\n"); + + fprintf(proxy, "const ExtendedProxyFileInfo %s_ProxyFileInfo =\n", file_id); + fprintf(proxy, "{\n"); + fprintf(proxy, " (PCInterfaceProxyVtblList*)&_%s_ProxyVtblList,\n", file_id); + fprintf(proxy, " (PCInterfaceStubVtblList*)&_%s_StubVtblList,\n", file_id); + fprintf(proxy, " (const PCInterfaceName*)&_%s_InterfaceNamesList,\n", file_id); + fprintf(proxy, " 0,\n"); + fprintf(proxy, " &_%s_IID_Lookup,\n", file_id); + fprintf(proxy, " %d,\n", c); + fprintf(proxy, " 1,\n"); + fprintf(proxy, " 0,\n"); + fprintf(proxy, " 0,\n"); + fprintf(proxy, " 0,\n"); + fprintf(proxy, " 0\n"); + fprintf(proxy, "};\n"); + + fclose(proxy); +} diff --git a/reactos/tools/widl/proxy.h b/reactos/tools/widl/proxy.h new file mode 100644 index 00000000000..fb32b5ebd32 --- /dev/null +++ b/reactos/tools/widl/proxy.h @@ -0,0 +1,26 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_PROXY_H +#define __WIDL_PROXY_H + +extern void write_proxies(ifref_t *ifaces); + +#endif diff --git a/reactos/tools/widl/typelib.c b/reactos/tools/widl/typelib.c new file mode 100644 index 00000000000..c597138dd6b --- /dev/null +++ b/reactos/tools/widl/typelib.c @@ -0,0 +1,274 @@ +/* + * IDL Compiler + * + * Copyright 2004 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "header.h" +#include "typelib.h" + +int in_typelib = 0; + +static typelib_t *typelib; + +/* List of oleauto types that should be recognized by name. + * (most of) these seem to be intrinsic types in mktyplib. */ + +static struct oatype { + const char *kw; + unsigned short vt; +} oatypes[] = { + {"BSTR", VT_BSTR}, + {"CURRENCY", VT_CY}, + {"DATE", VT_DATE}, + {"DECIMAL", VT_DECIMAL}, + {"HRESULT", VT_HRESULT}, + {"LPSTR", VT_LPSTR}, + {"LPWSTR", VT_LPWSTR}, + {"SCODE", VT_ERROR}, + {"VARIANT", VT_VARIANT}, + {"VARIANT_BOOL", VT_BOOL} +}; +#define NTYPES (sizeof(oatypes)/sizeof(oatypes[0])) +#define KWP(p) ((const struct oatype *)(p)) + +static int kw_cmp_func(const void *s1, const void *s2) +{ + return strcmp(KWP(s1)->kw, KWP(s2)->kw); +} + +static unsigned short builtin_vt(const char *kw) +{ + struct oatype key, *kwp; + key.kw = kw; +#ifdef KW_BSEARCH + kwp = bsearch(&key, oatypes, NTYPES, sizeof(oatypes[0]), kw_cmp_func); +#else + { + int i; + for (kwp=NULL, i=0; i < NTYPES; i++) + if (!kw_cmp_func(&key, &oatypes[i])) { + kwp = &oatypes[i]; + break; + } + } +#endif + if (kwp) { + return kwp->vt; + } + return 0; +} + +static int match(const char*n, const char*m) +{ + if (!n) return 0; + return !strcmp(n, m); +} + +unsigned short get_type_vt(type_t *t) +{ + unsigned short vt; + + chat("get_type_vt: %p type->name %s\n", t, t->name); + if (t->name) { + vt = builtin_vt(t->name); + if (vt) return vt; + } + + switch (t->type) { + case RPC_FC_BYTE: + case RPC_FC_USMALL: + return VT_UI1; + case RPC_FC_CHAR: + case RPC_FC_SMALL: + return VT_I1; + case RPC_FC_WCHAR: + return VT_I2; /* mktyplib seems to parse wchar_t as short */ + case RPC_FC_SHORT: + return VT_I2; + case RPC_FC_USHORT: + return VT_UI2; + case RPC_FC_LONG: + if (t->ref && match(t->ref->name, "int")) return VT_INT; + return VT_I4; + case RPC_FC_ULONG: + if (t->ref && match(t->ref->name, "int")) return VT_UINT; + return VT_UI4; + case RPC_FC_HYPER: + if (t->sign < 0) return VT_UI8; + if (t->ref && match(t->ref->name, "MIDL_uhyper")) return VT_UI8; + return VT_I8; + case RPC_FC_FLOAT: + return VT_R4; + case RPC_FC_DOUBLE: + return VT_R8; + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + if(t->ref) + return VT_PTR; + + error("get_type_vt: unknown-deref-type: %d\n", t->ref->type); + break; + case RPC_FC_IP: + if(match(t->name, "IUnknown")) + return VT_UNKNOWN; + if(match(t->name, "IDispatch")) + return VT_DISPATCH; + return VT_USERDEFINED; + + case RPC_FC_STRUCT: + case RPC_FC_PSTRUCT: + return VT_USERDEFINED; + case 0: + if(t->attrs) + return VT_USERDEFINED; + return 0; + default: + error("get_type_vt: unknown-type: %d\n", t->type); + } + return 0; +} + +unsigned short get_var_vt(var_t *v) +{ + unsigned short vt; + + chat("get_var_vt: %p tname %s\n", v, v->tname); + if (v->tname) { + vt = builtin_vt(v->tname); + if (vt) return vt; + } + + return get_type_vt(v->type); +} + +void start_typelib(char *name, attr_t *attrs) +{ + in_typelib++; + if (!do_typelib) return; + + typelib = xmalloc(sizeof(*typelib)); + typelib->name = xstrdup(name); + typelib->filename = xstrdup(typelib_name); + typelib->attrs = attrs; +} + +void end_typelib(void) +{ + in_typelib--; + if (!typelib) return; + + create_msft_typelib(typelib); + return; +} + +void add_interface(type_t *iface) +{ + typelib_entry_t *entry; + if (!typelib) return; + + chat("add interface: %s\n", iface->name); + entry = xmalloc(sizeof(*entry)); + entry->kind = TKIND_INTERFACE; + entry->u.interface = iface; + LINK(entry, typelib->entry); + typelib->entry = entry; +} + +void add_coclass(class_t *cls) +{ + typelib_entry_t *entry; + + if (!typelib) return; + + chat("add coclass: %s\n", cls->name); + + entry = xmalloc(sizeof(*entry)); + entry->kind = TKIND_COCLASS; + entry->u.class = cls; + LINK(entry, typelib->entry); + typelib->entry = entry; +} + +void add_module(type_t *module) +{ + typelib_entry_t *entry; + if (!typelib) return; + + chat("add module: %s\n", module->name); + entry = xmalloc(sizeof(*entry)); + entry->kind = TKIND_MODULE; + entry->u.module = module; + LINK(entry, typelib->entry); + typelib->entry = entry; +} + +void add_struct(type_t *structure) +{ + typelib_entry_t *entry; + if (!typelib) return; + + chat("add struct: %s\n", structure->name); + entry = xmalloc(sizeof(*entry)); + entry->kind = TKIND_RECORD; + entry->u.structure = structure; + LINK(entry, typelib->entry); + typelib->entry = entry; +} + +void add_enum(type_t *enumeration) +{ + typelib_entry_t *entry; + if (!typelib) return; + + chat("add enum: %s\n", enumeration->name); + entry = xmalloc(sizeof(*entry)); + entry->kind = TKIND_ENUM; + entry->u.enumeration = enumeration; + LINK(entry, typelib->entry); + typelib->entry = entry; +} + +void add_typedef(type_t *tdef, var_t *name) +{ + typelib_entry_t *entry; + if (!typelib) return; + + entry = xmalloc(sizeof(*entry)); + entry->kind = TKIND_ALIAS; + entry->u.tdef = xmalloc(sizeof(*entry->u.tdef)); + memcpy(entry->u.tdef, name, sizeof(*name)); + entry->u.tdef->type = tdef; + entry->u.tdef->name = xstrdup(name->name); + LINK(entry, typelib->entry); + typelib->entry = entry; +} diff --git a/reactos/tools/widl/typelib.h b/reactos/tools/widl/typelib.h new file mode 100644 index 00000000000..d6ba5a7d700 --- /dev/null +++ b/reactos/tools/widl/typelib.h @@ -0,0 +1,92 @@ +/* + * IDL Compiler + * + * Copyright 2004 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_TYPELIB_H +#define __WIDL_TYPELIB_H + +extern int in_typelib; +extern void start_typelib(char *name, attr_t *attrs); +extern void end_typelib(void); +extern void add_interface(type_t *iface); +extern void add_coclass(class_t *cls); +extern void add_module(type_t *module); +extern void add_struct(type_t *structure); +extern void add_enum(type_t *enumeration); +extern void add_typedef(type_t *tdef, var_t *name); + +/* Copied from wtypes.h. Not included directly because that would create a + * circular dependency (after all, wtypes.h is generated by widl...) */ + +enum VARENUM { + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_PTR = 26, + VT_SAFEARRAY = 27, + VT_CARRAY = 28, + VT_USERDEFINED = 29, + VT_LPSTR = 30, + VT_LPWSTR = 31, + VT_RECORD = 36, + VT_FILETIME = 64, + VT_BLOB = 65, + VT_STREAM = 66, + VT_STORAGE = 67, + VT_STREAMED_OBJECT = 68, + VT_STORED_OBJECT = 69, + VT_BLOB_OBJECT = 70, + VT_CF = 71, + VT_CLSID = 72, + VT_BSTR_BLOB = 0xfff, + VT_VECTOR = 0x1000, + VT_ARRAY = 0x2000, + VT_BYREF = 0x4000, + VT_RESERVED = 0x8000, + VT_ILLEGAL = 0xffff, + VT_ILLEGALMASKED = 0xfff, + VT_TYPEMASK = 0xfff +}; +extern unsigned short get_type_vt(type_t *t); +extern unsigned short get_var_vt(var_t *v); + +extern int create_msft_typelib(typelib_t *typelib); +#endif diff --git a/reactos/tools/widl/typelib_struct.h b/reactos/tools/widl/typelib_struct.h new file mode 100644 index 00000000000..43c140628e9 --- /dev/null +++ b/reactos/tools/widl/typelib_struct.h @@ -0,0 +1,598 @@ +/* + * typelib_struct.h internal wine data structures + * used to decode typelib's + * + * Copyright 1999 Rein KLazes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _WIDL_TYPELIB_STRUCT_H +#define _WIDL_TYPELIB_STRUCT_H + +#define HELPDLLFLAG (0x0100) +#define DO_NOT_SEEK (-1) + +#define MSFT_HREFTYPE_INTHISFILE(href) (!((href) & 3)) +#define MSFT_HREFTYPE_INDEX(href) ((href) /sizeof(MSFT_TypeInfoBase)) + +/*-------------------------FILE STRUCTURES-----------------------------------*/ + +/* There are two known file formats, those created with ICreateTypeLib + * have the signature "SLTG" as their first four bytes, while those created + * with ICreateTypeLib2 have "MSFT". + */ + +/***************************************************** + * MSFT typelibs + * + * These are TypeLibs created with ICreateTypeLib2 + * + */ + +/* + * structure of the typelib type2 header + * it is at the beginning of a type lib file + * + */ +typedef struct tagMSFT_Header { +/*0x00*/INT magic1; /* 0x5446534D "MSFT" */ + INT magic2; /* 0x00010002 version nr? */ + INT posguid; /* position of libid in guid table */ + /* (should be, else -1) */ + INT lcid; /* locale id */ +/*0x10*/INT lcid2; + INT varflags; /* (largely) unknown flags */ + /* the lower nibble is syskind */ + /* 0x40 always seems to be set */ + /* 0x10 set with a helpfile defined */ + /* 0x100 set with a helpstringdll defined - in this + case the offset to the name in the stringtable + appears right after this struct, before the + typeinfo offsets */ + INT version; /* set with SetVersion() */ + INT flags; /* set with SetFlags() */ +/*0x20*/INT nrtypeinfos; /* number of typeinfo's (till so far) */ + INT helpstring; /* position of help string in stringtable */ + INT helpstringcontext; + INT helpcontext; +/*0x30*/INT nametablecount; /* number of names in name table */ + INT nametablechars; /* nr of characters in name table */ + INT NameOffset; /* offset of name in name table */ + INT helpfile; /* position of helpfile in stringtable */ +/*0x40*/INT CustomDataOffset; /* if -1 no custom data, else it is offset */ + /* in customer data/guid offset table */ + INT res44; /* unknown always: 0x20 (guid hash size?) */ + INT res48; /* unknown always: 0x80 (name hash size?) */ + INT dispatchpos; /* HREFTYPE to IDispatch, or -1 if no IDispatch */ +/*0x50*/INT res50; /* is zero becomes one when an interface is derived */ +} MSFT_Header; + +/* segments in the type lib file have a structure like this: */ +typedef struct tagMSFT_pSeg { + INT offset; /* absolute offset in file */ + INT length; /* length of segment */ + INT res08; /* unknown always -1 */ + INT res0c; /* unknown always 0x0f in the header */ + /* 0x03 in the typeinfo_data */ +} MSFT_pSeg; + +/* layout of the main segment directory */ +typedef struct tagMSFT_SegDir { +/*1*/MSFT_pSeg pTypeInfoTab; /* each type info get an entry of 0x64 bytes */ + /* (25 ints) */ +/*2*/MSFT_pSeg pImpInfo; /* table with info for imported types */ +/*3*/MSFT_pSeg pImpFiles; /* import libaries */ +/*4*/MSFT_pSeg pRefTab; /* References table */ +/*5*/MSFT_pSeg pLibtab; /* always exists, alway same size (0x80) */ + /* hash table w offsets to guid????? */ +/*6*/MSFT_pSeg pGuidTab; /* all guids are stored here together with */ + /* offset in some table???? */ +/*7*/MSFT_pSeg res07; /* always created, alway same size (0x200) */ + /* purpose largely unknown */ +/*8*/MSFT_pSeg pNametab; /* name tables */ +/*9*/MSFT_pSeg pStringtab; /* string table */ +/*A*/MSFT_pSeg pTypdescTab; /* table with type descriptors */ +/*B*/MSFT_pSeg pArrayDescriptions; +/*C*/MSFT_pSeg pCustData; /* data table, used for custom data and default */ + /* parameter values */ +/*D*/MSFT_pSeg pCDGuids; /* table with offsets for the guids and into */ + /* the customer data table */ +/*E*/MSFT_pSeg res0e; /* unknown */ +/*F*/MSFT_pSeg res0f; /* unknown */ +} MSFT_SegDir; + + +/* base type info data */ +typedef struct tagMSFT_TypeInfoBase { +/*000*/ INT typekind; /* it is the TKIND_xxx */ + /* some byte alignment stuf */ + INT memoffset; /* points past the file, if no elements */ + INT res2; /* zero if no element, N*0x40 */ + INT res3; /* -1 if no lement, (N-1)*0x38 */ +/*010*/ INT res4; /* always? 3 */ + INT res5; /* always? zero */ + INT cElement; /* counts elements, HI=cVars, LO=cFuncs */ + INT res7; /* always? zero */ +/*020*/ INT res8; /* always? zero */ + INT res9; /* always? zero */ + INT resA; /* always? zero */ + INT posguid; /* position in guid table */ +/*030*/ INT flags; /* Typeflags */ + INT NameOffset; /* offset in name table */ + INT version; /* element version */ + INT docstringoffs; /* offset of docstring in string tab */ +/*040*/ INT helpstringcontext; /* */ + INT helpcontext; /* */ + INT oCustData; /* offset in customer data table */ +#ifdef WORDS_BIGENDIAN + INT16 cbSizeVft; /* virtual table size, including inherits */ + INT16 cImplTypes; /* nr of implemented interfaces */ +#else + INT16 cImplTypes; /* nr of implemented interfaces */ + INT16 cbSizeVft; /* virtual table size, including inherits */ +#endif +/*050*/ INT size; /* size in bytes, at least for structures */ + /* FIXME: name of this field */ + INT datatype1; /* position in type description table */ + /* or in base intefaces */ + /* if coclass: offset in reftable */ + /* if interface: reference to inherited if */ + INT datatype2; /* for interfaces: hiword is num of inherited funcs */ + /* loword is num of inherited interfaces */ + INT res18; /* always? 0 */ +/*060*/ INT res19; /* always? -1 */ + } MSFT_TypeInfoBase; + +/* layout of an entry with information on imported types */ +typedef struct tagMSFT_ImpInfo { + INT res0; /* unknown */ + INT oImpFile; /* offset inthe Import File table */ + INT oGuid; /* offset in Guid table */ + } MSFT_ImpInfo; + +/* function description data */ +typedef struct { +/* INT recsize; record size including some xtra stuff */ + INT DataType; /* data type of the memeber, eg return of function */ + INT Flags; /* something to do with attribute flags (LOWORD) */ +#ifdef WORDS_BIGENDIAN + INT16 funcdescsize; /* size of reconstituted FUNCDESC and related structs */ + INT16 VtableOffset; /* offset in vtable */ +#else + INT16 VtableOffset; /* offset in vtable */ + INT16 funcdescsize; /* size of reconstituted FUNCDESC and related structs */ +#endif + INT FKCCIC; /* bit string with the following */ + /* meaning (bit 0 is the lsb): */ + /* bits 0 - 2: FUNCKIND */ + /* bits 3 - 6: INVOKEKIND */ + /* bit 7: custom data present */ + /* bits 8 - 11: CALLCONV */ + /* bit 12: parameters have default values */ + /* bit 13: oEntry is numeric */ + /* bit 14: has retval param */ + /* bits 16 - 31: index of next function with same id */ +#ifdef WORDS_BIGENDIAN + INT16 nroargs; /* nr of optional arguments */ + INT16 nrargs; /* number of arguments (including optional ????) */ +#else + INT16 nrargs; /* number of arguments (including optional ????) */ + INT16 nroargs; /* nr of optional arguments */ +#endif + /* optional attribute fields, the number of them is variable */ + INT OptAttr[1]; +/* +0* INT helpcontext; +1* INT oHelpString; +2* INT oEntry; // either offset in string table or numeric as it is (see bit 13 of FKCCIC) // +3* INT res9; // unknown (-1) // +4* INT resA; // unknown (-1) // +5* INT HelpStringContext; + // these are controlled by a bit set in the FKCCIC field // +6* INT oCustData; // custom data for function // +7* INT oArgCustData[1]; // custom data per argument // +*/ +} MSFT_FuncRecord; + +/* after this may follow an array with default value pointers if the + * appropriate bit in the FKCCIC field has been set: + * INT oDefautlValue[nrargs]; + */ + + /* Parameter info one per argument*/ +typedef struct { + INT DataType; + INT oName; + INT Flags; + } MSFT_ParameterInfo; + +/* Variable description data */ +typedef struct { +/* INT recsize; // record size including some xtra stuff */ + INT DataType; /* data type of the variable */ + INT Flags; /* VarFlags (LOWORD) */ +#ifdef WORDS_BIGENDIAN + INT16 vardescsize; /* size of reconstituted VARDESC and related structs */ + INT16 VarKind; /* VarKind */ +#else + INT16 VarKind; /* VarKind */ + INT16 vardescsize; /* size of reconstituted VARDESC and related structs */ +#endif + INT OffsValue; /* value of the variable or the offset */ + /* in the data structure */ + /* optional attribute fields, the number of them is variable */ + /* controlled by record length */ + INT HelpContext; + INT oHelpString; + INT res9; /* unknown (-1) */ + INT oCustData; /* custom data for variable */ + INT HelpStringContext; + +} MSFT_VarRecord; + +/* Structure of the reference data */ +typedef struct { + INT reftype; /* either offset in type info table, then it's */ + /* a multiple of 64 */ + /* or offset in the external reference table */ + /* with an offset of 1 */ + INT flags; + INT oCustData; /* custom data */ + INT onext; /* next offset, -1 if last */ +} MSFT_RefRecord; + +/* this is how a guid is stored */ +typedef struct { + GUID guid; + INT hreftype; /* -2 for the typelib guid, typeinfo offset + for typeinfo guid, low two bits are 01 if + this is an imported typeinfo, low two bits + are 10 if this is an imported typelib (used + by imported typeinfos) */ + INT next_hash; /* offset to next guid in the hash bucket */ +} MSFT_GuidEntry; +/* some data preceding entries in the name table */ +typedef struct { + INT hreftype; /* is -1 if name is for neither a typeinfo, + a variable, or a function (that is, name + is for a typelib or a function parameter). + otherwise is the offset of the first + typeinfo that this name refers to (either + to the typeinfo itself or to a member of + the typeinfo */ + INT next_hash; /* offset to next name in the hash bucket */ + INT namelen; /* only lower 8 bits are valid */ + /* 0x1000 if name is only used once as a variable name */ + /* 0x2000 if name is a variable in an enumeration */ + /* 0x3800 if name is typeinfo name */ + /* upper 16 bits are hash code */ +} MSFT_NameIntro; +/* the custom data table directory has enties like this */ +typedef struct { + INT GuidOffset; + INT DataOffset; + INT next; /* next offset in the table, -1 if it's the last */ +} MSFT_CDGuid; + + +/*********************************************************** + * + * SLTG typelibs. + * + * These are created with ICreateTypeLib + * + */ + +#include "pshpack1.h" + +typedef struct { +/*00*/ DWORD SLTG_magic; /* 0x47544c53 == "SLTG" */ +/*04*/ WORD nrOfFileBlks; /* no of SLTG_BlkEntry's + 1 */ +/*06*/ WORD res06; /* ?? always 9 */ +/*08*/ WORD res08; /* some kind of len/offset ?? */ +/*0a*/ WORD first_blk; /* 1 based index into blk entries that + corresponds to first block in file */ +/*0c*/ DWORD res0c; /* always 0x000204ff */ +/*10*/ DWORD res10; /* always 0x00000000 */ +/*14*/ DWORD res14; /* always 0x000000c0 */ +/*18*/ DWORD res18; /* always 0x46000000 */ +/*1c*/ DWORD res1c; /* always 0x00000044 */ +/*20*/ DWORD res20; /* always 0xffff0000 */ +} SLTG_Header; + +/* This gets followed by a list of block entries */ +typedef struct { +/*00*/ DWORD len; +/*04*/ WORD index_string; /* offs from start of SLTG_Magic to index string */ +/*06*/ WORD next; +} SLTG_BlkEntry; + +/* The order of the blocks in the file is given by starting at Block + entry firt_blk and stepping through using the next pointer */ + +/* These then get followed by this magic */ +typedef struct { +/*00*/ BYTE res00; /* always 0x01 */ +/*01*/ CHAR CompObj_magic[8]; /* always "CompObj" */ +/*09*/ CHAR dir_magic[4]; /* always "dir" */ +} SLTG_Magic; + +#define SLTG_COMPOBJ_MAGIC "CompObj" +#define SLTG_DIR_MAGIC "dir" + +/* Next we have SLTG_Header.nrOfFileBlks - 2 of Index strings. These +are presumably unique to within the file and look something like +"AAAAAAAAAA" with the first character incremented from 'A' to ensure +uniqueness. I guess successive chars increment when we need to wrap +the first one. */ + +typedef struct { +/*00*/ CHAR string[11]; +} SLTG_Index; + + +/* This is followed by SLTG_pad9 */ +typedef struct { +/*00*/ CHAR pad[9]; /* 9 '\0's */ +} SLTG_Pad9; + + +/* Now we have the noOfFileBlks - 1 worth of blocks. The length of +each block is given by its entry in SLTG_BlkEntry. */ + +/* type SLTG_NAME in rather like a BSTR except that the length in +bytes is given by the first WORD and the string contains 8bit chars */ + +typedef WORD SLTG_Name; + +/* The main library block looks like this. This one seems to come last */ + +typedef struct { +/*00*/ WORD magic; /* 0x51cc */ +/*02*/ WORD res02; /* 0x0003, 0x0004 */ +/*04*/ WORD name; /* offset to name in name table */ +/*06*/ SLTG_Name res06; /* maybe this is just WORD == 0xffff */ + SLTG_Name helpstring; + SLTG_Name helpfile; + DWORD helpcontext; + WORD syskind; /* == 1 for win32, 0 for win16 */ + WORD lcid; /* == 0x409, 0x809 etc */ + DWORD res12; /* == 0 */ + WORD libflags; /* LIBFLAG_* */ + WORD maj_vers; + WORD min_vers; + GUID uuid; +} SLTG_LibBlk; + +#define SLTG_LIBBLK_MAGIC 0x51cc + +/* we then get 0x40 bytes worth of 0xffff or small numbers followed by + nrOfFileBlks - 2 of these */ +typedef struct { + WORD small_no; + SLTG_Name index_name; /* This refers to a name in the directory */ + SLTG_Name other_name; /* Another one of these weird names */ + WORD res1a; /* 0xffff */ + WORD name_offs; /* offset to name in name table */ + WORD more_bytes; /* if this is non-zero we get this many + bytes before the next element, which seem + to reference the docstring of the type ? */ + WORD res20; /* 0xffff */ + DWORD helpcontext; + WORD res26; /* 0xffff */ + GUID uuid; +} SLTG_OtherTypeInfo; + +/* Next we get WORD 0x0003 followed by a DWORD which if we add to +0x216 gives the offset to the name table from the start of the LibBlk +struct */ + +typedef struct { +/*00*/ WORD magic; /* 0x0501 */ +/*02*/ DWORD href_table; /* if not 0xffffffff, then byte offset from + beginning of struct to href table */ +/*06*/ DWORD res06; /* 0xffffffff */ +/*0a*/ DWORD elem_table; /* offset to members */ +/*0e*/ DWORD res0e; /* 0xffffffff */ +/*12*/ WORD major_version; /* major version number */ +/*14*/ WORD minor_version; /* minor version number */ +/*16*/ DWORD res16; /* 0xfffe0000 */ +/*1a*/ BYTE typeflags1;/* 0x02 | top 5 bits hold l5sbs of TYPEFLAGS */ +/*1b*/ BYTE typeflags2;/* TYPEFLAGS >> 5 */ +/*1c*/ BYTE typeflags3;/* 0x02*/ +/*1d*/ BYTE typekind; /* 0x03 == TKIND_INTERFACE etc. */ +/*1e*/ DWORD res1e; /* 0x00000000 or 0xffffffff */ +} SLTG_TypeInfoHeader; + +#define SLTG_TIHEADER_MAGIC 0x0501 + +typedef struct { +/*00*/ WORD cFuncs; +/*02*/ WORD cVars; +/*04*/ WORD cImplTypes; +/*06*/ WORD res06; +/*08*/ WORD res08; +/*0a*/ WORD res0a; +/*0c*/ WORD res0c; +/*0e*/ WORD res0e; +/*10*/ WORD res10; +/*12*/ WORD res12; +/*14*/ WORD tdescalias_vt; /* for TKIND_ALIAS */ +/*16*/ WORD res16; +/*18*/ WORD res18; +/*1a*/ WORD res1a; +/*1c*/ WORD res1c; +/*1e*/ WORD res1e; +/*20*/ WORD cbSizeInstance; +/*22*/ WORD cbAlignment; +/*24*/ WORD res24; +/*26*/ WORD res26; +/*28*/ WORD cbSizeVft; +/*2a*/ WORD res2a; +/*2c*/ WORD res2c; +/*2e*/ WORD res2e; +/*30*/ WORD res30; +/*32*/ WORD res32; +/*34*/ WORD res34; +} SLTG_TypeInfoTail; + +typedef struct { +/*00*/ WORD res00; /* 0x0001 sometimes 0x0003 ?? */ +/*02*/ WORD res02; /* 0xffff */ +/*04*/ BYTE res04; /* 0x01 */ +/*05*/ DWORD cbExtra; /* No of bytes that follow */ +} SLTG_MemberHeader; + +typedef struct { +/*00*/ WORD magic; /* 0x120a */ +/*02*/ WORD next; /* offset in bytes to next block from start of block + group, 0xffff if last item */ +/*04*/ WORD name; /* offset to name within name table */ +/*06*/ WORD value; /* offset to value from start of block group */ +/*08*/ WORD res08; /* 0x56 */ +/*0a*/ DWORD memid; /* memid */ +/*0e*/ WORD helpcontext;/* 0xfffe == no context, 0x0001 == stored in EnumInfo struct, else offset + to value from start of block group */ +/*10*/ WORD helpstring;/* offset from start of block group to string offset */ +} SLTG_EnumItem; + +#define SLTG_ENUMITEM_MAGIC 0x120a + +typedef struct { +/*00*/ WORD vt; /* vartype, 0xffff marks end. */ +/*02*/ WORD res02; /* ?, 0xffff marks end */ +} SLTG_AliasItem; + +#define SLTG_ALIASITEM_MAGIC 0x001d + + +typedef struct { + BYTE magic; /* 0x4c or 0x6c */ + BYTE inv; /* high nibble is INVOKE_KIND, low nibble = 2 */ + WORD next; /* byte offset from beginning of group to next fn */ + WORD name; /* Offset within name table to name */ + DWORD dispid; /* dispid */ + WORD helpcontext; /* helpcontext (again 1 is special) */ + WORD helpstring;/* helpstring offset to offset */ + WORD arg_off; /* offset to args from start of block */ + BYTE nacc; /* lowest 3bits are CALLCONV, rest are no of args */ + BYTE retnextopt;/* if 0x80 bit set ret type follows else next WORD + is offset to ret type. No of optional args is + middle 6 bits */ + WORD rettype; /* return type VT_?? or offset to ret type */ + WORD vtblpos; /* position in vtbl? */ + WORD funcflags; /* present if magic == 0x6c */ +/* Param list starts, repeat next two as required */ +#if 0 + WORD name; /* offset to 2nd letter of name */ + WORD+ type; /* VT_ of param */ +#endif +} SLTG_Function; + +#define SLTG_FUNCTION_MAGIC 0x4c +#define SLTG_FUNCTION_WITH_FLAGS_MAGIC 0x6c + +typedef struct { +/*00*/ BYTE magic; /* 0xdf */ +/*01*/ BYTE res01; /* 0x00 */ +/*02*/ DWORD res02; /* 0xffffffff */ +/*06*/ DWORD res06; /* 0xffffffff */ +/*0a*/ DWORD res0a; /* 0xffffffff */ +/*0e*/ DWORD res0e; /* 0xffffffff */ +/*12*/ DWORD res12; /* 0xffffffff */ +/*16*/ DWORD res16; /* 0xffffffff */ +/*1a*/ DWORD res1a; /* 0xffffffff */ +/*1e*/ DWORD res1e; /* 0xffffffff */ +/*22*/ DWORD res22; /* 0xffffffff */ +/*26*/ DWORD res26; /* 0xffffffff */ +/*2a*/ DWORD res2a; /* 0xffffffff */ +/*2e*/ DWORD res2e; /* 0xffffffff */ +/*32*/ DWORD res32; /* 0xffffffff */ +/*36*/ DWORD res36; /* 0xffffffff */ +/*3a*/ DWORD res3a; /* 0xffffffff */ +/*3e*/ DWORD res3e; /* 0xffffffff */ +/*42*/ WORD res42; /* 0xffff */ +/*44*/ DWORD number; /* this is 8 times the number of refs */ +/*48*/ /* Now we have number bytes (8 for each ref) of SLTG_UnknownRefInfo */ + +/*50*/ WORD res50; /* 0xffff */ +/*52*/ BYTE res52; /* 0x01 */ +/*53*/ DWORD res53; /* 0x00000000 */ +/*57*/ SLTG_Name names[1]; + /* Now we have number/8 SLTG_Names (first WORD is no of bytes in the ascii + * string). Strings look like "*\Rxxxx*#n". If xxxx == ffff then the + * ref refers to the nth type listed in this library (0 based). Else + * the xxxx (which maybe fewer than 4 digits) is the offset into the name + * table to a string "*\G{}#1.0#0#C:\WINNT\System32\stdole32.tlb#" + * The guid is the typelib guid; the ref again refers to the nth type of + * the imported typelib. + */ + +/*xx*/ BYTE resxx; /* 0xdf */ + +} SLTG_RefInfo; + +#define SLTG_REF_MAGIC 0xdf + +typedef struct { + WORD res00; /* 0x0001 */ + BYTE res02; /* 0x02 */ + BYTE res03; /* 0x40 if internal ref, 0x00 if external ? */ + WORD res04; /* 0xffff */ + WORD res06; /* 0x0000, 0x0013 or 0xffff ?? */ +} SLTG_UnknownRefInfo; + +typedef struct { + WORD res00; /* 0x004a */ + WORD next; /* byte offs to next interface */ + WORD res04; /* 0xffff */ + BYTE impltypeflags; /* IMPLTYPEFLAG_* */ + BYTE res07; /* 0x80 */ + WORD res08; /* 0x0012, 0x0028 ?? */ + WORD ref; /* number in ref table ? */ + WORD res0c; /* 0x4000 */ + WORD res0e; /* 0xfffe */ + WORD res10; /* 0xffff */ + WORD res12; /* 0x001d */ + WORD pos_in_table; /* 0x0, 0x4, ? */ +} SLTG_ImplInfo; + +#define SLTG_IMPL_MAGIC 0x004a + +typedef struct { + BYTE magic; /* 0x0a */ + BYTE typepos; + WORD next; + WORD name; + WORD byte_offs; /* pos in struct */ + WORD type; /* if typepos == 0x02 this is the type, else offset to type */ + DWORD memid; + WORD helpcontext; /* ?? */ + WORD helpstring; /* ?? */ +} SLTG_RecordItem; + +#define SLTG_RECORD_MAGIC 0x0a + + +/* CARRAYs look like this +WORD type == VT_CARRAY +WORD offset from start of block to SAFEARRAY +WORD typeofarray +*/ + +#include "poppack.h" + +/*---------------------------END--------------------------------------------*/ +#endif diff --git a/reactos/tools/widl/utils.c b/reactos/tools/widl/utils.c new file mode 100644 index 00000000000..4a7952b7e6b --- /dev/null +++ b/reactos/tools/widl/utils.c @@ -0,0 +1,197 @@ +/* + * Utility routines + * + * Copyright 1998 Bertho A. Stultiens + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "widl.h" +#include "utils.h" +#include "parser.h" + +/* #define WANT_NEAR_INDICATION */ + +#ifdef WANT_NEAR_INDICATION +void make_print(char *str) +{ + while(*str) + { + if(!isprint(*str)) + *str = ' '; + str++; + } +} +#endif + +static void generic_msg(const char *s, const char *t, const char *n, va_list ap) +{ + fprintf(stderr, "%s:%d: %s: ", input_name ? input_name : "stdin", line_number, t); + vfprintf(stderr, s, ap); +#ifdef WANT_NEAR_INDICATION + { + char *cpy; + if(n) + { + cpy = xstrdup(n); + make_print(cpy); + fprintf(stderr, " near '%s'", cpy); + free(cpy); + } + } +#endif + fprintf(stderr, "\n"); +} + + +int yyerror(const char *s, ...) +{ + va_list ap; + va_start(ap, s); + generic_msg(s, "Error", yytext, ap); + va_end(ap); + exit(1); + return 1; +} + +int yywarning(const char *s, ...) +{ + va_list ap; + va_start(ap, s); + generic_msg(s, "Warning", yytext, ap); + va_end(ap); + return 0; +} + +void internal_error(const char *file, int line, const char *s, ...) +{ + va_list ap; + va_start(ap, s); + fprintf(stderr, "Internal error (please report) %s %d: ", file, line); + vfprintf(stderr, s, ap); + va_end(ap); + exit(3); +} + +void error(const char *s, ...) +{ + va_list ap; + va_start(ap, s); + fprintf(stderr, "error: "); + vfprintf(stderr, s, ap); + va_end(ap); + exit(2); +} + +void warning(const char *s, ...) +{ + va_list ap; + va_start(ap, s); + fprintf(stderr, "warning: "); + vfprintf(stderr, s, ap); + va_end(ap); +} + +void chat(const char *s, ...) +{ + if(debuglevel & DEBUGLEVEL_CHAT) + { + va_list ap; + va_start(ap, s); + fprintf(stderr, "chat: "); + vfprintf(stderr, s, ap); + va_end(ap); + } +} + +char *dup_basename(const char *name, const char *ext) +{ + int namelen; + int extlen = strlen(ext); + char *base; + char *slash; + + if(!name) + name = "widl.tab"; + + slash = strrchr(name, '/'); + if (slash) + name = slash + 1; + + namelen = strlen(name); + + /* +4 for later extension and +1 for '\0' */ + base = (char *)xmalloc(namelen +4 +1); + strcpy(base, name); + if(!strcasecmp(name + namelen-extlen, ext)) + { + base[namelen - extlen] = '\0'; + } + return base; +} + +void *xmalloc(size_t size) +{ + void *res; + + assert(size > 0); + res = malloc(size); + if(res == NULL) + { + error("Virtual memory exhausted.\n"); + } + /* + * We set it to 0. + * This is *paramount* because we depend on it + * just about everywhere in the rest of the code. + */ + memset(res, 0, size); + return res; +} + + +void *xrealloc(void *p, size_t size) +{ + void *res; + + assert(size > 0); + res = realloc(p, size); + if(res == NULL) + { + error("Virtual memory exhausted.\n"); + } + return res; +} + +char *xstrdup(const char *str) +{ + char *s; + + assert(str != NULL); + s = (char *)xmalloc(strlen(str)+1); + return strcpy(s, str); +} diff --git a/reactos/tools/widl/utils.h b/reactos/tools/widl/utils.h new file mode 100644 index 00000000000..a32ce0ce189 --- /dev/null +++ b/reactos/tools/widl/utils.h @@ -0,0 +1,45 @@ +/* + * Utility routines' prototypes etc. + * + * Copyright 1998 Bertho A. Stultiens (BS) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_UTILS_H +#define __WIDL_UTILS_H + +#include "widltypes.h" + +#include /* size_t */ + +void *xmalloc(size_t); +void *xrealloc(void *, size_t); +char *xstrdup(const char *str); + +#ifndef __GNUC__ +#define __attribute__(X) +#endif + +int yyerror(const char *s, ...) __attribute__((format (printf, 1, 2))); +int yywarning(const char *s, ...) __attribute__((format (printf, 1, 2))); +void internal_error(const char *file, int line, const char *s, ...) __attribute__((format (printf, 3, 4))); +void error(const char *s, ...) __attribute__((format (printf, 1, 2))); +void warning(const char *s, ...) __attribute__((format (printf, 1, 2))); +void chat(const char *s, ...) __attribute__((format (printf, 1, 2))); + +char *dup_basename(const char *name, const char *ext); + +#endif diff --git a/reactos/tools/widl/widl.c b/reactos/tools/widl/widl.c new file mode 100644 index 00000000000..973522d0830 --- /dev/null +++ b/reactos/tools/widl/widl.c @@ -0,0 +1,305 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * based on WRC code by Bertho Stultiens + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include + +#define WIDL_FULLVERSION "0.1" + +#include "widl.h" +#include "utils.h" +#include "parser.h" +#include "proxy.h" +#include "wine/wpp.h" + +/* future options to reserve characters for: */ +/* a = alignment of structures */ +/* A = ACF input filename */ +/* c = client stub only? */ +/* C = client stub filename */ +/* J = do not search standard include path */ +/* O = generate interpreted stubs */ +/* p = proxy only? */ +/* P = proxy filename */ +/* s = server stub only? */ +/* S = server stub filename */ +/* u = UUID file only? */ +/* U = UUID filename */ +/* w = select win16/win32 output (?) */ + +static char usage[] = +"Usage: widl [options...] infile.idl\n" +" -d n Set debug level to 'n'\n" +" -D id[=val] Define preprocessor identifier id=val\n" +" -E Preprocess only\n" +" -h Generate headers\n" +" -H file Name of header file (default is infile.h)\n" +" -I path Set include search dir to path (multiple -I allowed)\n" +" -N Do not preprocess input\n" +" -t Generate typelib\n" +" -T file Name of typelib file (default is infile.tlb)\n" +" -V Print version and exit\n" +" -W Enable pedantic warnings\n" +"Debug level 'n' is a bitmask with following meaning:\n" +" * 0x01 Tell which resource is parsed (verbose mode)\n" +" * 0x02 Dump internal structures\n" +" * 0x04 Create a parser trace (yydebug=1)\n" +" * 0x08 Preprocessor messages\n" +" * 0x10 Preprocessor lex messages\n" +" * 0x20 Preprocessor yacc trace\n" +; + +static const char version_string[] = "Wine IDL Compiler Version " WIDL_FULLVERSION "\n" + "Copyright 2002 Ove Kaaven\n"; + +int win32 = 1; +int debuglevel = DEBUGLEVEL_NONE; + +int pedantic = 0; +static int do_everything = 1; +int preprocess_only = 0; +int do_header = 0; +int do_typelib = 0; +int do_proxies = 0; +int no_preprocess = 0; + +char *input_name; +char *header_name; +char *header_token; +char *typelib_name; +char *proxy_name; +char *proxy_token; +char *temp_name; + +int line_number = 1; + +FILE *header; +FILE *proxy; + +time_t now; + +int getopt (int argc, char *const *argv, const char *optstring); +static void rm_tempfile(void); +static void segvhandler(int sig); + +static char *make_token(const char *name) +{ + char *token; + char *slash; + int i; + + slash = strrchr(name, '/'); + if (slash) name = slash + 1; + + token = xstrdup(name); + for (i=0; token[i]; i++) { + if (!isalnum(token[i])) token[i] = '_'; + else token[i] = toupper(token[i]); + } + return token; +} + +int main(int argc,char *argv[]) +{ + extern char* optarg; + extern int optind; + int optc; + int ret = 0; + + signal(SIGSEGV, segvhandler); + + now = time(NULL); + + while((optc = getopt(argc, argv, "d:D:EhH:I:NtT:VW")) != EOF) { + switch(optc) { + case 'd': + debuglevel = strtol(optarg, NULL, 0); + break; + case 'D': + wpp_add_cmdline_define(optarg); + break; + case 'E': + do_everything = 0; + preprocess_only = 1; + break; + case 'h': + do_everything = 0; + do_header = 1; + break; + case 'H': + header_name = strdup(optarg); + break; + case 'I': + wpp_add_include_path(optarg); + break; + case 'N': + no_preprocess = 1; + break; + case 't': + do_everything = 0; + do_typelib = 1; + break; + case 'T': + typelib_name = strdup(optarg); + break; + case 'V': + printf(version_string); + return 0; + case 'W': + pedantic = 1; + break; + default: + fprintf(stderr, usage); + return 1; + } + } + + if(do_everything) { + do_header = do_typelib = do_proxies = 1; + } + if(optind < argc) { + input_name = xstrdup(argv[optind]); + } + else { + fprintf(stderr, usage); + return 1; + } + + if(debuglevel) + { + setbuf(stdout,0); + setbuf(stderr,0); + } + + yydebug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0; + yy_flex_debug = debuglevel & DEBUGLEVEL_TRACE ? 1 : 0; + + wpp_set_debug( (debuglevel & DEBUGLEVEL_PPLEX) != 0, + (debuglevel & DEBUGLEVEL_PPTRACE) != 0, + (debuglevel & DEBUGLEVEL_PPMSG) != 0 ); + + if (!header_name && do_header) { + header_name = dup_basename(input_name, ".idl"); + strcat(header_name, ".h"); + } + + if (!typelib_name && do_typelib) { + typelib_name = dup_basename(input_name, ".idl"); + strcat(typelib_name, ".tlb"); + } + + if (!proxy_name && do_proxies) { + proxy_name = dup_basename(input_name, ".idl"); + proxy_token = xstrdup(proxy_name); + strcat(proxy_name, "_p.c"); + } + + wpp_add_cmdline_define("__WIDL__"); + + atexit(rm_tempfile); + if (!no_preprocess) + { + chat("Starting preprocess\n"); + + if (!preprocess_only) + { + ret = wpp_parse_temp( input_name, header_name, &temp_name ); + } + else + { + ret = wpp_parse( input_name, stdout ); + } + + if(ret) exit(1); + if(preprocess_only) exit(0); + if(!(yyin = fopen(temp_name, "r"))) { + fprintf(stderr, "Could not open %s for input\n", temp_name); + return 1; + } + } + else { + if(!(yyin = fopen(input_name, "r"))) { + fprintf(stderr, "Could not open %s for input\n", input_name); + return 1; + } + } + + if(do_header) { + header_token = make_token(header_name); + + if(!(header = fopen(header_name, "w"))) { + fprintf(stderr, "Could not open %s for output\n", header_name); + return 1; + } + fprintf(header, "/*** Autogenerated by WIDL %s from %s - Do not edit ***/\n", WIDL_FULLVERSION, input_name); + fprintf(header, "#include \n" ); + fprintf(header, "#include \n\n" ); + fprintf(header, "#ifndef __WIDL_%s\n", header_token); + fprintf(header, "#define __WIDL_%s\n", header_token); + fprintf(header, "#ifdef __cplusplus\n"); + fprintf(header, "extern \"C\" {\n"); + fprintf(header, "#endif\n"); + } + + ret = yyparse(); + + if(do_header) { + fprintf(header, "#ifdef __cplusplus\n"); + fprintf(header, "}\n"); + fprintf(header, "#endif\n"); + fprintf(header, "#endif /* __WIDL_%s */\n", header_token); + fclose(header); + } + + fclose(yyin); + + if(ret) { + exit(1); + } + header_name = NULL; + return 0; +} + +static void rm_tempfile(void) +{ + abort_import(); + if(temp_name) + unlink(temp_name); + if (header_name) + unlink( header_name ); +} + +static void segvhandler(int sig) +{ + fprintf(stderr, "\n%s:%d: Oops, segment violation\n", input_name, line_number); + fflush(stdout); + fflush(stderr); + abort(); +} diff --git a/reactos/tools/widl/widl.h b/reactos/tools/widl/widl.h new file mode 100644 index 00000000000..e951699ba98 --- /dev/null +++ b/reactos/tools/widl/widl.h @@ -0,0 +1,57 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_WIDL_H +#define __WIDL_WIDL_H + +#include "widltypes.h" + +#include + +#define WIDL_FULLVERSION "0.1" + +extern int debuglevel; +#define DEBUGLEVEL_NONE 0x0000 +#define DEBUGLEVEL_CHAT 0x0001 +#define DEBUGLEVEL_DUMP 0x0002 +#define DEBUGLEVEL_TRACE 0x0004 +#define DEBUGLEVEL_PPMSG 0x0008 +#define DEBUGLEVEL_PPLEX 0x0010 +#define DEBUGLEVEL_PPTRACE 0x0020 + +extern int win32; +extern int pedantic; +extern int do_header; +extern int do_typelib; +extern int do_proxies; + +extern char *input_name; +extern char *header_name; +extern char *typelib_name; +extern char *proxy_name; +extern char *proxy_token; +extern time_t now; + +extern int line_number; +extern int char_number; + +extern FILE* header; + +#endif diff --git a/reactos/tools/widl/widl.man b/reactos/tools/widl/widl.man new file mode 100644 index 00000000000..9e449309e03 --- /dev/null +++ b/reactos/tools/widl/widl.man @@ -0,0 +1,71 @@ +.TH WIDL 1 "March 2004" "Wine Manpage" "Wine Developers Manual" +.SH NAME +widl \- Wine Interface Definition Language Compiler +.SH SYNOPSIS +.BR "widl "\fI[options]\fR " \fIinfile.idl\fR" +.SH DESCRIPTION +.B widl +is a Wine tool which purpose is to compile Interface Definition Language (IDL) files. +.PP +.SH OPTIONS +.B Help mode: +.nf +No options are used. +The program prints the help info and then exits. +.PP +.B General options: +.IP \fB-V\fR +Print version number and exits from the program. +.PP +.B Header options: +.IP \fB-h\fR +Generate header files. +.IP "\fB-H \fIfile\fR" +Name of header file to generate. The default header +filename is infile.h. +.PP +.B Type library options: +.IP \fB-t\fR +Generate a type library. +.IP "\fB-T \fIfile\fR" +Define the name of the type library to be generated. +The default filename is infile.tlb. +.PP +.B Preprocessor options: +.IP "\fB-I \fIpath\fR" +Add a header search dir to path. Multiple search +dirs are allowed. +.IP "\fB-D \fIid[=val]\fR" +Define preprocessor identifier id value. +.IP \fB-E\fR +Preprocess only. +.IP \fB-N\fR +Do not preprocess input. +.PP +.B Debug options: +.IP \fB-W\fR +Enable pedantic warnings. +.IP "\fB-d \fIn\fR" +.nf +Set debug level to n. +n may be '0x01', '0x02', '0x04', '0x08', '0x10' or '0x20'. +(See section \fBDebug\fR) +.PP +.SH Debug +Debug level 'n' is a bitmask with the following meaning: + * 0x01 Tell which resource is parsed (verbose mode) + * 0x02 Dump internal structures + * 0x04 Create a parser trace (yydebug=1) + * 0x08 Preprocessor messages + * 0x10 Preprocessor lex messages + * 0x20 Preprocessor yacc trace +.SH BUGS +Typelib generation doesn't work at the moment. It is still under development. +.SH AUTHORS +.B widl +was written by Ove Kaaven. This man page was written by Hannu +Valtonen. +.SH "SEE ALSO" +The Winelib User Guide +.nf +The Wine Developers Guide diff --git a/reactos/tools/widl/widltypes.h b/reactos/tools/widl/widltypes.h new file mode 100644 index 00000000000..5f142225e37 --- /dev/null +++ b/reactos/tools/widl/widltypes.h @@ -0,0 +1,258 @@ +/* + * IDL Compiler + * + * Copyright 2002 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WIDL_WIDLTYPES_H +#define __WIDL_WIDLTYPES_H + +#include +#include "guiddef.h" +#include "wine/rpcfc.h" + +#ifndef UUID_DEFINED +#define UUID_DEFINED +typedef GUID UUID; +#endif + +#define TRUE 1 +#define FALSE 0 + +typedef struct _attr_t attr_t; +typedef struct _expr_t expr_t; +typedef struct _type_t type_t; +typedef struct _typeref_t typeref_t; +typedef struct _var_t var_t; +typedef struct _func_t func_t; +typedef struct _ifref_t ifref_t; +typedef struct _class_t class_t; +typedef struct _typelib_entry_t typelib_entry_t; +typedef struct _typelib_t typelib_t; + +#define DECL_LINK(type) \ + type *l_next; \ + type *l_prev; + +#define LINK(x,y) do { x->l_next = y; if (y) y->l_prev = x; } while (0) + +#define INIT_LINK(x) do { x->l_next = NULL; x->l_prev = NULL; } while (0) +#define NEXT_LINK(x) ((x)->l_next) +#define PREV_LINK(x) ((x)->l_prev) + +enum attr_type +{ + ATTR_ASYNC, + ATTR_CALLAS, + ATTR_CASE, + ATTR_CONTEXTHANDLE, + ATTR_CONTROL, + ATTR_DEFAULT, + ATTR_DEFAULTVALUE_EXPR, + ATTR_DEFAULTVALUE_STRING, + ATTR_DLLNAME, + ATTR_DUAL, + ATTR_ENDPOINT, + ATTR_ENTRY_STRING, + ATTR_ENTRY_ORDINAL, + ATTR_HANDLE, + ATTR_HELPCONTEXT, + ATTR_HELPFILE, + ATTR_HELPSTRING, + ATTR_HELPSTRINGCONTEXT, + ATTR_HELPSTRINGDLL, + ATTR_HIDDEN, + ATTR_ID, + ATTR_IDEMPOTENT, + ATTR_IIDIS, + ATTR_IN, + ATTR_INPUTSYNC, + ATTR_LENGTHIS, + ATTR_LOCAL, + ATTR_NONCREATABLE, + ATTR_OBJECT, + ATTR_ODL, + ATTR_OLEAUTOMATION, + ATTR_OPTIONAL, + ATTR_OUT, + ATTR_POINTERDEFAULT, + ATTR_POINTERTYPE, + ATTR_PROPGET, + ATTR_PROPPUT, + ATTR_PROPPUTREF, + ATTR_PUBLIC, + ATTR_READONLY, + ATTR_RESTRICTED, + ATTR_RETVAL, + ATTR_SIZEIS, + ATTR_SOURCE, + ATTR_STRING, + ATTR_SWITCHIS, + ATTR_SWITCHTYPE, + ATTR_TRANSMITAS, + ATTR_UUID, + ATTR_V1ENUM, + ATTR_VARARG, + ATTR_VERSION, + ATTR_WIREMARSHAL, + ATTR_DISPINTERFACE +}; + +enum expr_type +{ + EXPR_VOID, + EXPR_NUM, + EXPR_HEXNUM, + EXPR_IDENTIFIER, + EXPR_NEG, + EXPR_NOT, + EXPR_PPTR, + EXPR_CAST, + EXPR_SIZEOF, + EXPR_SHL, + EXPR_SHR, + EXPR_MUL, + EXPR_DIV, + EXPR_ADD, + EXPR_SUB, + EXPR_AND, + EXPR_OR, + EXPR_COND, +}; + +enum type_kind +{ + TKIND_ENUM = 0, + TKIND_RECORD, + TKIND_MODULE, + TKIND_INTERFACE, + TKIND_DISPATCH, + TKIND_COCLASS, + TKIND_ALIAS, + TKIND_UNION, + TKIND_MAX +}; + +struct _attr_t { + enum attr_type type; + union { + unsigned long ival; + void *pval; + } u; + /* parser-internal */ + DECL_LINK(attr_t) +}; + +struct _expr_t { + enum expr_type type; + expr_t *ref; + union { + long lval; + char *sval; + expr_t *ext; + typeref_t *tref; + } u; + expr_t *ext2; + int is_const; + long cval; + /* parser-internal */ + DECL_LINK(expr_t) +}; + +struct _type_t { + char *name; + unsigned char type; + struct _type_t *ref; + char *rname; + attr_t *attrs; + func_t *funcs; + var_t *fields; + int ignore, is_const, sign; + int defined, written; + int typelib_idx; + /* parser-internal */ + DECL_LINK(type_t) +}; + +struct _typeref_t { + char *name; + type_t *ref; + int uniq; +}; + +struct _var_t { + char *name; + int ptr_level; + expr_t *array; + type_t *type; + var_t *args; /* for function pointers */ + char *tname; + attr_t *attrs; + expr_t *eval; + long lval; + + /* parser-internal */ + DECL_LINK(var_t) +}; + +struct _func_t { + var_t *def; + var_t *args; + int ignore, idx; + + /* parser-internal */ + DECL_LINK(func_t) +}; + +struct _ifref_t { + type_t *iface; + attr_t *attrs; + + /* parser-internal */ + DECL_LINK(ifref_t) +}; + +struct _class_t { + char *name; + attr_t *attrs; + ifref_t *ifaces; + + /* parser-internal */ + DECL_LINK(class_t) +}; + +struct _typelib_entry_t { + enum type_kind kind; + union { + class_t *class; + type_t *interface; + type_t *module; + type_t *structure; + type_t *enumeration; + var_t *tdef; + } u; + DECL_LINK(typelib_entry_t) +}; + +struct _typelib_t { + char *name; + char *filename; + attr_t *attrs; + typelib_entry_t *entry; +}; + +#endif diff --git a/reactos/tools/widl/write_msft.c b/reactos/tools/widl/write_msft.c new file mode 100644 index 00000000000..d475afa3725 --- /dev/null +++ b/reactos/tools/widl/write_msft.c @@ -0,0 +1,2403 @@ +/* + * Typelib v2 (MSFT) generation + * + * Copyright 2004 Alastair Bridgewater + * 2004, 2005 Huw Davies + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * -------------------------------------------------------------------------------------- + * Known problems: + * + * Badly incomplete. + * + * Only works on little-endian systems. + * + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winnls.h" + +#include "wine/unicode.h" + +#include "widltypes.h" +#include "typelib.h" +#include "typelib_struct.h" +#include "utils.h" +#include "hash.h" + +enum MSFT_segment_index { + MSFT_SEG_TYPEINFO = 0, /* type information */ + MSFT_SEG_IMPORTINFO, /* import information */ + MSFT_SEG_IMPORTFILES, /* import filenames */ + MSFT_SEG_REFERENCES, /* references (?) */ + MSFT_SEG_GUIDHASH, /* hash table for guids? */ + MSFT_SEG_GUID, /* guid storage */ + MSFT_SEG_NAMEHASH, /* hash table for names */ + MSFT_SEG_NAME, /* name storage */ + MSFT_SEG_STRING, /* string storage */ + MSFT_SEG_TYPEDESC, /* type descriptions */ + MSFT_SEG_ARRAYDESC, /* array descriptions */ + MSFT_SEG_CUSTDATA, /* custom data */ + MSFT_SEG_CUSTDATAGUID, /* custom data guids */ + MSFT_SEG_UNKNOWN, /* ??? */ + MSFT_SEG_UNKNOWN2, /* ??? */ + MSFT_SEG_MAX /* total number of segments */ +}; + +typedef struct tagMSFT_ImpFile { + int guid; + LCID lcid; + int version; + char filename[0]; /* preceeded by two bytes of encoded (length << 2) + flags in the low two bits. */ +} MSFT_ImpFile; + +typedef struct _msft_typelib_t +{ + typelib_t *typelib; + MSFT_Header typelib_header; + MSFT_pSeg typelib_segdir[MSFT_SEG_MAX]; + char *typelib_segment_data[MSFT_SEG_MAX]; + int typelib_segment_block_length[MSFT_SEG_MAX]; + + INT typelib_typeinfo_offsets[0x200]; /* Hope that's enough. */ + + INT *typelib_namehash_segment; + INT *typelib_guidhash_segment; + + INT help_string_dll_offset; + + struct _msft_typeinfo_t *typeinfos; + struct _msft_typeinfo_t *last_typeinfo; +} msft_typelib_t; + +typedef struct _msft_typeinfo_t +{ + msft_typelib_t *typelib; + MSFT_TypeInfoBase *typeinfo; + + int var_data_allocated; + int *var_data; + + int func_data_allocated; + int *func_data; + + int vars_allocated; + int *var_indices; + int *var_names; + int *var_offsets; + + int funcs_allocated; + int *func_indices; + int *func_names; + int *func_offsets; + + int datawidth; + + struct _msft_typeinfo_t *next_typeinfo; +} msft_typeinfo_t; + + + +/*================== Internal functions ===================================*/ + +/**************************************************************************** + * ctl2_init_header + * + * Initializes the type library header of a new typelib. + */ +static void ctl2_init_header( + msft_typelib_t *typelib) /* [I] The typelib to initialize. */ +{ + typelib->typelib_header.magic1 = 0x5446534d; + typelib->typelib_header.magic2 = 0x00010002; + typelib->typelib_header.posguid = -1; + typelib->typelib_header.lcid = 0x0409; /* or do we use the current one? */ + typelib->typelib_header.lcid2 = 0x0; + typelib->typelib_header.varflags = 0x40; + typelib->typelib_header.version = 0; + typelib->typelib_header.flags = 0; + typelib->typelib_header.nrtypeinfos = 0; + typelib->typelib_header.helpstring = -1; + typelib->typelib_header.helpstringcontext = 0; + typelib->typelib_header.helpcontext = 0; + typelib->typelib_header.nametablecount = 0; + typelib->typelib_header.nametablechars = 0; + typelib->typelib_header.NameOffset = -1; + typelib->typelib_header.helpfile = -1; + typelib->typelib_header.CustomDataOffset = -1; + typelib->typelib_header.res44 = 0x20; + typelib->typelib_header.res48 = 0x80; + typelib->typelib_header.dispatchpos = -1; + typelib->typelib_header.res50 = 0; +} + +/**************************************************************************** + * ctl2_init_segdir + * + * Initializes the segment directory of a new typelib. + */ +static void ctl2_init_segdir( + msft_typelib_t *typelib) /* [I] The typelib to initialize. */ +{ + int i; + MSFT_pSeg *segdir; + + segdir = &typelib->typelib_segdir[MSFT_SEG_TYPEINFO]; + + for (i = 0; i < 15; i++) { + segdir[i].offset = -1; + segdir[i].length = 0; + segdir[i].res08 = -1; + segdir[i].res0c = 0x0f; + } +} + +/**************************************************************************** + * ctl2_hash_guid + * + * Generates a hash key from a GUID. + * + * RETURNS + * + * The hash key for the GUID. + */ +static int ctl2_hash_guid( + REFGUID guid) /* [I] The guid to hash. */ +{ + int hash; + int i; + + hash = 0; + for (i = 0; i < 8; i ++) { + hash ^= ((const short *)guid)[i]; + } + + return hash & 0x1f; +} + +/**************************************************************************** + * ctl2_find_guid + * + * Locates a guid in a type library. + * + * RETURNS + * + * The offset into the GUID segment of the guid, or -1 if not found. + */ +static int ctl2_find_guid( + msft_typelib_t *typelib, /* [I] The typelib to operate against. */ + int hash_key, /* [I] The hash key for the guid. */ + REFGUID guid) /* [I] The guid to find. */ +{ + int offset; + MSFT_GuidEntry *guidentry; + + offset = typelib->typelib_guidhash_segment[hash_key]; + while (offset != -1) { + guidentry = (MSFT_GuidEntry *)&typelib->typelib_segment_data[MSFT_SEG_GUID][offset]; + + if (!memcmp(guidentry, guid, sizeof(GUID))) return offset; + + offset = guidentry->next_hash; + } + + return offset; +} + +/**************************************************************************** + * ctl2_find_name + * + * Locates a name in a type library. + * + * RETURNS + * + * The offset into the NAME segment of the name, or -1 if not found. + * + * NOTES + * + * The name must be encoded as with ctl2_encode_name(). + */ +static int ctl2_find_name( + msft_typelib_t *typelib, /* [I] The typelib to operate against. */ + char *name) /* [I] The encoded name to find. */ +{ + int offset; + int *namestruct; + + offset = typelib->typelib_namehash_segment[name[2] & 0x7f]; + while (offset != -1) { + namestruct = (int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][offset]; + + if (!((namestruct[2] ^ *((int *)name)) & 0xffff00ff)) { + /* hash codes and lengths match, final test */ + if (!strncasecmp(name+4, (void *)(namestruct+3), name[0])) break; + } + + /* move to next item in hash bucket */ + offset = namestruct[1]; + } + + return offset; +} + +/**************************************************************************** + * ctl2_encode_name + * + * Encodes a name string to a form suitable for storing into a type library + * or comparing to a name stored in a type library. + * + * RETURNS + * + * The length of the encoded name, including padding and length+hash fields. + * + * NOTES + * + * Will throw an exception if name or result are NULL. Is not multithread + * safe in the slightest. + */ +static int ctl2_encode_name( + msft_typelib_t *typelib, /* [I] The typelib to operate against (used for LCID only). */ + const char *name, /* [I] The name string to encode. */ + char **result) /* [O] A pointer to a pointer to receive the encoded name. */ +{ + int length; + static char converted_name[0x104]; + int offset; + int value; + + length = strlen(name); + memcpy(converted_name + 4, name, length); + converted_name[0] = length & 0xff; + + converted_name[length + 4] = 0; + + converted_name[1] = 0x00; + + value = lhash_val_of_name_sys(typelib->typelib_header.varflags & 0x0f, typelib->typelib_header.lcid, converted_name + 4); + + converted_name[2] = value; + converted_name[3] = value >> 8; + + for (offset = (4 - length) & 3; offset; offset--) converted_name[length + offset + 3] = 0x57; + + *result = converted_name; + + return (length + 7) & ~3; +} + +/**************************************************************************** + * ctl2_encode_string + * + * Encodes a string to a form suitable for storing into a type library or + * comparing to a string stored in a type library. + * + * RETURNS + * + * The length of the encoded string, including padding and length fields. + * + * NOTES + * + * Will throw an exception if string or result are NULL. Is not multithread + * safe in the slightest. + */ +static int ctl2_encode_string( + msft_typelib_t *typelib, /* [I] The typelib to operate against (not used?). */ + const char *string, /* [I] The string to encode. */ + char **result) /* [O] A pointer to a pointer to receive the encoded string. */ +{ + int length; + static char converted_string[0x104]; + int offset; + + length = strlen(string); + memcpy(converted_string + 2, string, length); + converted_string[0] = length & 0xff; + converted_string[1] = (length >> 8) & 0xff; + + if(length < 3) { /* strings of this length are padded with upto 8 bytes incl the 2 byte length */ + for(offset = 0; offset < 4; offset++) + converted_string[length + offset + 2] = 0x57; + length += 4; + } + for (offset = (4 - (length + 2)) & 3; offset; offset--) converted_string[length + offset + 1] = 0x57; + + *result = converted_string; + + return (length + 5) & ~3; +} + +/**************************************************************************** + * ctl2_alloc_segment + * + * Allocates memory from a segment in a type library. + * + * RETURNS + * + * Success: The offset within the segment of the new data area. + * Failure: -1 (this is invariably an out of memory condition). + * + * BUGS + * + * Does not (yet) handle the case where the allocated segment memory needs to grow. + */ +static int ctl2_alloc_segment( + msft_typelib_t *typelib, /* [I] The type library in which to allocate. */ + enum MSFT_segment_index segment, /* [I] The segment in which to allocate. */ + int size, /* [I] The amount to allocate. */ + int block_size) /* [I] Initial allocation block size, or 0 for default. */ +{ + int offset; + + if(!typelib->typelib_segment_data[segment]) { + if (!block_size) block_size = 0x2000; + + typelib->typelib_segment_block_length[segment] = block_size; + typelib->typelib_segment_data[segment] = xmalloc(block_size); + if (!typelib->typelib_segment_data[segment]) return -1; + memset(typelib->typelib_segment_data[segment], 0x57, block_size); + } + + while ((typelib->typelib_segdir[segment].length + size) > typelib->typelib_segment_block_length[segment]) { + char *block; + + block_size = typelib->typelib_segment_block_length[segment]; + block = realloc(typelib->typelib_segment_data[segment], block_size << 1); + if (!block) return -1; + + if (segment == MSFT_SEG_TYPEINFO) { + /* TypeInfos have a direct pointer to their memory space, so we have to fix them up. */ + msft_typeinfo_t *typeinfo; + + for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + typeinfo->typeinfo = (void *)&block[((char *)typeinfo->typeinfo) - typelib->typelib_segment_data[segment]]; + } + } + + memset(block + block_size, 0x57, block_size); + typelib->typelib_segment_block_length[segment] = block_size << 1; + typelib->typelib_segment_data[segment] = block; + } + + offset = typelib->typelib_segdir[segment].length; + typelib->typelib_segdir[segment].length += size; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_typeinfo + * + * Allocates and initializes a typeinfo structure in a type library. + * + * RETURNS + * + * Success: The offset of the new typeinfo. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_typeinfo( + msft_typelib_t *typelib, /* [I] The type library to allocate in. */ + int nameoffset) /* [I] The offset of the name for this typeinfo. */ +{ + int offset; + MSFT_TypeInfoBase *typeinfo; + + offset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEINFO, sizeof(MSFT_TypeInfoBase), 0); + if (offset == -1) return -1; + + typelib->typelib_typeinfo_offsets[typelib->typelib_header.nrtypeinfos++] = offset; + + typeinfo = (void *)(typelib->typelib_segment_data[MSFT_SEG_TYPEINFO] + offset); + + typeinfo->typekind = (typelib->typelib_header.nrtypeinfos - 1) << 16; + typeinfo->memoffset = -1; /* should be EOF if no elements */ + typeinfo->res2 = 0; + typeinfo->res3 = -1; + typeinfo->res4 = 3; + typeinfo->res5 = 0; + typeinfo->cElement = 0; + typeinfo->res7 = 0; + typeinfo->res8 = 0; + typeinfo->res9 = 0; + typeinfo->resA = 0; + typeinfo->posguid = -1; + typeinfo->flags = 0; + typeinfo->NameOffset = nameoffset; + typeinfo->version = 0; + typeinfo->docstringoffs = -1; + typeinfo->helpstringcontext = 0; + typeinfo->helpcontext = 0; + typeinfo->oCustData = -1; + typeinfo->cbSizeVft = 0; + typeinfo->cImplTypes = 0; + typeinfo->size = 0; + typeinfo->datatype1 = -1; + typeinfo->datatype2 = 0; + typeinfo->res18 = 0; + typeinfo->res19 = -1; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_guid + * + * Allocates and initializes a GUID structure in a type library. Also updates + * the GUID hash table as needed. + * + * RETURNS + * + * Success: The offset of the new GUID. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_guid( + msft_typelib_t *typelib, /* [I] The type library to allocate in. */ + MSFT_GuidEntry *guid) /* [I] The GUID to store. */ +{ + int offset; + MSFT_GuidEntry *guid_space; + int hash_key; + + hash_key = ctl2_hash_guid(&guid->guid); + + offset = ctl2_find_guid(typelib, hash_key, &guid->guid); + if (offset != -1) return offset; + + offset = ctl2_alloc_segment(typelib, MSFT_SEG_GUID, sizeof(MSFT_GuidEntry), 0); + if (offset == -1) return -1; + + guid_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_GUID] + offset); + *guid_space = *guid; + + guid_space->next_hash = typelib->typelib_guidhash_segment[hash_key]; + typelib->typelib_guidhash_segment[hash_key] = offset; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_name + * + * Allocates and initializes a name within a type library. Also updates the + * name hash table as needed. + * + * RETURNS + * + * Success: The offset within the segment of the new name. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_name( + msft_typelib_t *typelib, /* [I] The type library to allocate in. */ + const char *name) /* [I] The name to store. */ +{ + int length; + int offset; + MSFT_NameIntro *name_space; + char *encoded_name; + + length = ctl2_encode_name(typelib, name, &encoded_name); + + offset = ctl2_find_name(typelib, encoded_name); + if (offset != -1) return offset; + + offset = ctl2_alloc_segment(typelib, MSFT_SEG_NAME, length + 8, 0); + if (offset == -1) return -1; + + name_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_NAME] + offset); + name_space->hreftype = -1; + name_space->next_hash = -1; + memcpy(&name_space->namelen, encoded_name, length); + + if (typelib->typelib_namehash_segment[encoded_name[2] & 0x7f] != -1) + name_space->next_hash = typelib->typelib_namehash_segment[encoded_name[2] & 0x7f]; + + typelib->typelib_namehash_segment[encoded_name[2] & 0x7f] = offset; + + typelib->typelib_header.nametablecount += 1; + typelib->typelib_header.nametablechars += *encoded_name; + + return offset; +} + +/**************************************************************************** + * ctl2_alloc_string + * + * Allocates and initializes a string in a type library. + * + * RETURNS + * + * Success: The offset within the segment of the new string. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int ctl2_alloc_string( + msft_typelib_t *typelib, /* [I] The type library to allocate in. */ + const char *string) /* [I] The string to store. */ +{ + int length; + int offset; + char *string_space; + char *encoded_string; + + length = ctl2_encode_string(typelib, string, &encoded_string); + + for (offset = 0; offset < typelib->typelib_segdir[MSFT_SEG_STRING].length; + offset += ((((typelib->typelib_segment_data[MSFT_SEG_STRING][offset + 1] << 8) & 0xff) + | (typelib->typelib_segment_data[MSFT_SEG_STRING][offset + 0] & 0xff)) + 5) & ~3) { + if (!memcmp(encoded_string, typelib->typelib_segment_data[MSFT_SEG_STRING] + offset, length)) return offset; + } + + offset = ctl2_alloc_segment(typelib, MSFT_SEG_STRING, length, 0); + if (offset == -1) return -1; + + string_space = typelib->typelib_segment_data[MSFT_SEG_STRING] + offset; + memcpy(string_space, encoded_string, length); + + return offset; +} + +/**************************************************************************** + * alloc_importinfo + * + * Allocates and initializes an import information structure in a type library. + * + * RETURNS + * + * Success: The offset of the new importinfo. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int alloc_importinfo( + msft_typelib_t *typelib, /* [I] The type library to allocate in. */ + MSFT_ImpInfo *impinfo) /* [I] The import information to store. */ +{ + int offset; + MSFT_ImpInfo *impinfo_space; + + for (offset = 0; + offset < typelib->typelib_segdir[MSFT_SEG_IMPORTINFO].length; + offset += sizeof(MSFT_ImpInfo)) { + if (!memcmp(&(typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO][offset]), + impinfo, sizeof(MSFT_ImpInfo))) { + return offset; + } + } + + offset = ctl2_alloc_segment(typelib, MSFT_SEG_IMPORTINFO, sizeof(MSFT_ImpInfo), 0); + if (offset == -1) return -1; + + impinfo_space = (void *)(typelib->typelib_segment_data[MSFT_SEG_IMPORTINFO] + offset); + *impinfo_space = *impinfo; + + return offset; +} + +/**************************************************************************** + * alloc_importfile + * + * Allocates and initializes an import file definition in a type library. + * + * RETURNS + * + * Success: The offset of the new importinfo. + * Failure: -1 (this is invariably an out of memory condition). + */ +static int alloc_importfile( + msft_typelib_t *typelib, /* [I] The type library to allocate in. */ + int guidoffset, /* [I] The offset to the GUID for the imported library. */ + int major_version, /* [I] The major version number of the imported library. */ + int minor_version, /* [I] The minor version number of the imported library. */ + const char *filename) /* [I] The filename of the imported library. */ +{ + int length; + int offset; + MSFT_ImpFile *importfile; + char *encoded_string; + + length = ctl2_encode_string(typelib, filename, &encoded_string); + + encoded_string[0] <<= 2; + encoded_string[0] |= 1; + + for (offset = 0; offset < typelib->typelib_segdir[MSFT_SEG_IMPORTFILES].length; + offset += ((((typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xd] << 8) & 0xff) + | (typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset + 0xc] & 0xff)) >> 2) + 0xc) { + if (!memcmp(encoded_string, typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES] + offset + 0xc, length)) return offset; + } + + offset = ctl2_alloc_segment(typelib, MSFT_SEG_IMPORTFILES, length + 0xc, 0); + if (offset == -1) return -1; + + importfile = (MSFT_ImpFile *)&typelib->typelib_segment_data[MSFT_SEG_IMPORTFILES][offset]; + importfile->guid = guidoffset; + importfile->lcid = typelib->typelib_header.lcid2; + importfile->version = major_version | (minor_version << 16); + memcpy(&importfile->filename, encoded_string, length); + + return offset; +} + +static void add_structure_typeinfo(msft_typelib_t *typelib, type_t *structure); +static void add_interface_typeinfo(msft_typelib_t *typelib, type_t *interface); + +/**************************************************************************** + * encode_type + * + * Encodes a type, storing information in the TYPEDESC and ARRAYDESC + * segments as needed. + * + * RETURNS + * + * Success: 0. + * Failure: -1. + */ +static int encode_type( + msft_typelib_t *typelib, /* [I] The type library in which to encode the TYPEDESC. */ + int vt, /* [I] vt to encode */ + type_t *type, /* [I] type */ + int *encoded_type, /* [O] The encoded type description. */ + int *width, /* [O] The width of the type, or NULL. */ + int *alignment, /* [O] The alignment of the type, or NULL. */ + int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */ +{ + int default_type; + int scratch; + int typeoffset; + int *typedata; + int target_type; + int child_size = 0; + + chat("encode_type vt %d type %p\n", vt, type); + + default_type = 0x80000000 | (vt << 16) | vt; + if (!width) width = &scratch; + if (!alignment) alignment = &scratch; + if (!decoded_size) decoded_size = &scratch; + + + switch (vt) { + case VT_I1: + case VT_UI1: + *encoded_type = default_type; + *width = 1; + *alignment = 1; + break; + + case VT_INT: + *encoded_type = 0x80000000 | (VT_I4 << 16) | VT_INT; + if ((typelib->typelib_header.varflags & 0x0f) == SYS_WIN16) { + *width = 2; + *alignment = 2; + } else { + *width = 4; + *alignment = 4; + } + break; + + case VT_UINT: + *encoded_type = 0x80000000 | (VT_UI4 << 16) | VT_UINT; + if ((typelib->typelib_header.varflags & 0x0f) == SYS_WIN16) { + *width = 2; + *alignment = 2; + } else { + *width = 4; + *alignment = 4; + } + break; + + case VT_UI2: + case VT_I2: + case VT_BOOL: + *encoded_type = default_type; + *width = 2; + *alignment = 2; + break; + + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_ERROR: + case VT_BSTR: + case VT_HRESULT: + *encoded_type = default_type; + *width = 4; + *alignment = 4; + break; + + case VT_R8: + *encoded_type = default_type; + *width = 8; + *alignment = 8; + break; + + case VT_CY: + *encoded_type = default_type; + *width = 8; + *alignment = 8; + break; + + case VT_VOID: + *encoded_type = 0x80000000 | (VT_EMPTY << 16) | vt; + *width = 0; + *alignment = 1; + break; + + case VT_UNKNOWN: + case VT_DISPATCH: + *encoded_type = default_type; + *width = 4; + *alignment = 4; + break; + + case VT_VARIANT: + *encoded_type = default_type; + break; + + case VT_PTR: + { + int next_vt; + while((next_vt = get_type_vt(type->ref)) == 0) { + if(type->ref == NULL) { + next_vt = VT_VOID; + break; + } + type = type->ref; + } + + encode_type(typelib, next_vt, type->ref, &target_type, NULL, NULL, &child_size); + if(type->ref->type == RPC_FC_IP) { + chat("encode_type: skipping ptr\n"); + *encoded_type = target_type; + *width = 4; + *alignment = 4; + *decoded_size = child_size; + break; + } + + for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break; + } + + if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + int mix_field; + + if (target_type & 0x80000000) { + mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF; + } else { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; + mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; + } + + typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (mix_field << 16) | VT_PTR; + typedata[1] = target_type; + } + + *encoded_type = typeoffset; + + *width = 4; + *alignment = 4; + *decoded_size = 8 /*sizeof(TYPEDESC)*/ + child_size; + break; + } +#if 0 + + + case VT_SAFEARRAY: + /* FIXME: Make with the error checking. */ + FIXME("SAFEARRAY vartype, may not work correctly.\n"); + + ctl2_encode_typedesc(typelib, tdesc->u.lptdesc, &target_type, NULL, NULL, &child_size); + + for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if (((typedata[0] & 0xffff) == VT_SAFEARRAY) && (typedata[1] == target_type)) break; + } + + if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + int mix_field; + + if (target_type & 0x80000000) { + mix_field = ((target_type >> 16) & VT_TYPEMASK) | VT_ARRAY; + } else { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; + mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; + } + + typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (mix_field << 16) | VT_SAFEARRAY; + typedata[1] = target_type; + } + + *encoded_tdesc = typeoffset; + + *width = 4; + *alignment = 4; + *decoded_size = sizeof(TYPEDESC) + child_size; + break; + + +#endif + + case VT_USERDEFINED: + { + int typeinfo_offset; + chat("encode_type: VT_USERDEFINED - type %p name = %s type->type %d idx %d\n", type, + type->name, type->type, type->typelib_idx); + + if(type->typelib_idx == -1) { + chat("encode_type: trying to ref not added type\n"); + switch(type->type) { + case RPC_FC_STRUCT: + add_structure_typeinfo(typelib, type); + break; + case RPC_FC_IP: + add_interface_typeinfo(typelib, type); + break; + case 0: + error("encode_type: VT_USERDEFINED - can't yet add typedef's on the fly\n"); + default: + error("encode_type: VT_USERDEFINED - unhandled type %d\n", type->type); + } + } + + typeinfo_offset = typelib->typelib_typeinfo_offsets[type->typelib_idx]; + for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if ((typedata[0] == ((0x7fff << 16) | VT_USERDEFINED)) && (typedata[1] == typeinfo_offset)) break; + } + + if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (0x7fff << 16) | VT_USERDEFINED; + typedata[1] = typeinfo_offset; + } + + *encoded_type = typeoffset; + *width = 0; + *alignment = 1; + + if(type->type == RPC_FC_IP) { + for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if ((typedata[0] == ((0x7fff << 16) | VT_PTR)) && (typedata[1] == *encoded_type)) break; + } + if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (0x7fff << 16) | VT_PTR; + typedata[1] = *encoded_type; + } + *encoded_type = typeoffset; + *width = 4; + *alignment = 4; + *decoded_size += 8; + } + break; + } + + default: + error("encode_type: unrecognized type %d.\n", vt); + *encoded_type = default_type; + *width = 0; + *alignment = 1; + break; + } + + return 0; +} + +static void dump_type(type_t *t) +{ + chat("dump_type: %p name %s type %d ref %p rname %s attrs %p\n", t, t->name, t->type, t->ref, t->rname, t->attrs); + if(t->ref) dump_type(t->ref); +} + +static int encode_var( + msft_typelib_t *typelib, /* [I] The type library in which to encode the TYPEDESC. */ + var_t *var, /* [I] The type description to encode. */ + int *encoded_type, /* [O] The encoded type description. */ + int *width, /* [O] The width of the type, or NULL. */ + int *alignment, /* [O] The alignment of the type, or NULL. */ + int *decoded_size) /* [O] The total size of the unencoded TYPEDESCs, including nested descs. */ +{ + int typeoffset; + int *typedata; + int target_type; + int child_size; + int vt; + int scratch; + type_t *type; + + if (!width) width = &scratch; + if (!alignment) alignment = &scratch; + if (!decoded_size) decoded_size = &scratch; + *decoded_size = 0; + + chat("encode_var: var %p var->tname %s var->type %p var->ptr_level %d var->type->ref %p\n", var, var->tname, var->type, var->ptr_level, var->type->ref); + if(var->ptr_level) { + int skip_ptr; + var->ptr_level--; + skip_ptr = encode_var(typelib, var, &target_type, NULL, NULL, &child_size); + var->ptr_level++; + + if(skip_ptr == 2) { + chat("encode_var: skipping ptr\n"); + *encoded_type = target_type; + *decoded_size = child_size; + *width = 4; + *alignment = 4; + return 0; + } + + for (typeoffset = 0; typeoffset < typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length; typeoffset += 8) { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + if (((typedata[0] & 0xffff) == VT_PTR) && (typedata[1] == target_type)) break; + } + + if (typeoffset == typelib->typelib_segdir[MSFT_SEG_TYPEDESC].length) { + int mix_field; + + if (target_type & 0x80000000) { + mix_field = ((target_type >> 16) & 0x3fff) | VT_BYREF; + } else { + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][target_type]; + mix_field = ((typedata[0] >> 16) == 0x7fff)? 0x7fff: 0x7ffe; + } + + typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (mix_field << 16) | VT_PTR; + typedata[1] = target_type; + } + + *encoded_type = typeoffset; + + *width = 4; + *alignment = 4; + *decoded_size = 8 /*sizeof(TYPEDESC)*/ + child_size; + return 0; + } + + if(var->array) { + expr_t *dim = var->array; + expr_t *array_save; + int num_dims = 1, elements = 1, arrayoffset; + int *arraydata; + + while(NEXT_LINK(dim)) { + dim = NEXT_LINK(dim); + num_dims++; + } + chat("array with %d dimensions\n", num_dims); + array_save = var->array; + var->array = NULL; + encode_var(typelib, var, &target_type, width, alignment, NULL); + var->array = array_save; + arrayoffset = ctl2_alloc_segment(typelib, MSFT_SEG_ARRAYDESC, (2 + 2 * num_dims) * sizeof(long), 0); + arraydata = (void *)&typelib->typelib_segment_data[MSFT_SEG_ARRAYDESC][arrayoffset]; + + arraydata[0] = target_type; + arraydata[1] = num_dims; + arraydata[1] |= ((num_dims * 2 * sizeof(long)) << 16); + + arraydata += 2; + while(dim) { + arraydata[0] = dim->cval; + arraydata[1] = 0; + arraydata += 2; + elements *= dim->cval; + dim = PREV_LINK(dim); + } + + typeoffset = ctl2_alloc_segment(typelib, MSFT_SEG_TYPEDESC, 8, 0); + typedata = (void *)&typelib->typelib_segment_data[MSFT_SEG_TYPEDESC][typeoffset]; + + typedata[0] = (0x7ffe << 16) | VT_CARRAY; + typedata[1] = arrayoffset; + + *encoded_type = typeoffset; + *width = *width * elements; + *decoded_size = 20 /*sizeof(ARRAYDESC)*/ + (num_dims - 1) * 8 /*sizeof(SAFEARRAYBOUND)*/; + return 0; + } + dump_type(var->type); + + vt = get_var_vt(var); + type = var->type; + while(!vt) { + if(type->ref == NULL) { + vt = VT_VOID; + break; + } + type = type->ref; + vt = get_type_vt(type); + } + encode_type(typelib, vt, type, encoded_type, width, alignment, decoded_size); + if(type->type == RPC_FC_IP) return 2; + return 0; +} + + +static void write_value(msft_typelib_t* typelib, int *out, int vt, void *value) +{ + switch(vt) { + case VT_I2: + case VT_I4: + case VT_R4: + case VT_BOOL: + case VT_I1: + case VT_UI1: + case VT_UI2: + case VT_UI4: + case VT_INT: + case VT_UINT: + case VT_HRESULT: + { + unsigned long *lv = value; + if((*lv & 0x3ffffff) == *lv) { + *out = 0x80000000; + *out |= vt << 26; + *out |= *lv; + } else { + int offset = ctl2_alloc_segment(typelib, MSFT_SEG_CUSTDATA, 8, 0); + *((unsigned short *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = vt; + memcpy(&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2], value, 4); + *((unsigned short *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+6]) = 0x5757; + *out = offset; + } + return; + } + case VT_BSTR: + { + char *s = (char *) value; + int len = strlen(s), seg_len = (len + 6 + 3) & ~0x3; + int offset = ctl2_alloc_segment(typelib, MSFT_SEG_CUSTDATA, seg_len, 0); + *((unsigned short *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset]) = vt; + *((unsigned int *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+2]) = len; + memcpy(&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+6], value, len); + len += 6; + while(len < seg_len) { + *((char *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATA][offset+len]) = 0x57; + len++; + } + *out = offset; + return; + } + + default: + warning("can't write value of type %d yet\n", vt); + } + return; +} + +static HRESULT set_custdata(msft_typelib_t *typelib, REFGUID guid, + int vt, void *value, int *offset) +{ + MSFT_GuidEntry guidentry; + int guidoffset; + int custoffset; + int *custdata; + int data_out; + + guidentry.guid = *guid; + + guidentry.hreftype = -1; + guidentry.next_hash = -1; + + guidoffset = ctl2_alloc_guid(typelib, &guidentry); + if (guidoffset == -1) return E_OUTOFMEMORY; + write_value(typelib, &data_out, vt, value); + + custoffset = ctl2_alloc_segment(typelib, MSFT_SEG_CUSTDATAGUID, 12, 0); + if (custoffset == -1) return E_OUTOFMEMORY; + + custdata = (int *)&typelib->typelib_segment_data[MSFT_SEG_CUSTDATAGUID][custoffset]; + custdata[0] = guidoffset; + custdata[1] = data_out; + custdata[2] = *offset; + *offset = custoffset; + + return S_OK; +} + +static HRESULT add_func_desc(msft_typeinfo_t* typeinfo, func_t *func, int index) +{ + int offset, name_offset; + int *typedata, typedata_size; + int i, id, next_idx; + int decoded_size, extra_attr = 0; + int num_params = 0, num_defaults = 0; + var_t *arg, *last_arg = NULL; + char *namedata; + attr_t *attr; + unsigned int funcflags = 0, callconv = 4 /* CC_STDCALL */; + unsigned int funckind, invokekind = 1 /* INVOKE_FUNC */; + int help_context = 0, help_string_context = 0, help_string_offset = -1; + int entry = -1, entry_is_ord = 0; + + chat("add_func_desc(%p,%d)\n", typeinfo, index); + + id = ((0x6000 | (typeinfo->typeinfo->datatype2 & 0xffff)) << 16) | index; + + switch(typeinfo->typeinfo->typekind & 15) { + case TKIND_DISPATCH: + funckind = 0x4; /* FUNC_DISPATCH */ + break; + case TKIND_MODULE: + funckind = 0x3; /* FUNC_STATIC */ + break; + default: + funckind = 0x1; /* FUNC_PUREVIRTUAL */ + break; + } + + for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_LOCAL) { + chat("add_func_desc: skipping local function\n"); + return S_FALSE; + } + } + + for(arg = func->args; arg; arg = NEXT_LINK(arg)) { + last_arg = arg; + num_params++; + for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_DEFAULTVALUE_EXPR || attr->type == ATTR_DEFAULTVALUE_STRING) { + num_defaults++; + break; + } + } + } + + chat("add_func_desc: num of params %d\n", num_params); + + name_offset = ctl2_alloc_name(typeinfo->typelib, func->def->name); + + for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) { + expr_t *expr = attr->u.pval; + switch(attr->type) { + case ATTR_ENTRY_ORDINAL: + extra_attr = max(extra_attr, 3); + entry = expr->cval; + entry_is_ord = 1; + break; + case ATTR_ENTRY_STRING: + extra_attr = max(extra_attr, 3); + entry = ctl2_alloc_string(typeinfo->typelib, attr->u.pval); + break; + case ATTR_HELPCONTEXT: + extra_attr = max(extra_attr, 1); + help_context = expr->u.lval; + break; + case ATTR_HELPSTRING: + extra_attr = max(extra_attr, 2); + help_string_offset = ctl2_alloc_string(typeinfo->typelib, attr->u.pval); + break; + case ATTR_HELPSTRINGCONTEXT: + extra_attr = max(extra_attr, 6); + help_string_context = expr->u.lval; + break; + case ATTR_HIDDEN: + funcflags |= 0x40; /* FUNCFLAG_FHIDDEN */ + break; + case ATTR_ID: + id = expr->u.lval; + break; + case ATTR_OUT: + break; + case ATTR_PROPGET: + invokekind = 0x2; /* INVOKE_PROPERTYGET */ + break; + case ATTR_PROPPUT: + invokekind = 0x4; /* INVOKE_PROPERTYPUT */ + break; + case ATTR_PROPPUTREF: + invokekind = 0x8; /* INVOKE_PROPERTYPUTREF */ + break; + case ATTR_RESTRICTED: + funcflags |= 0x1; /* FUNCFLAG_FRESTRICTED */ + break; + default: + warning("add_func_desc: ignoring attr %d\n", attr->type); + break; + } + } + + switch(invokekind) { + case 0x2: /* INVOKE_PROPERTYGET */ + if((num_params != 0 && (typeinfo->typeinfo->typekind & 15) == TKIND_DISPATCH) + || (num_params != 1 && (typeinfo->typeinfo->typekind & 15) == TKIND_INTERFACE)) { + error("expecting no args on a propget func\n"); + return S_FALSE; + } + break; + case 0x4: /* INVOKE_PROPERTYPUT */ + case 0x8: /* INVOKE_PROPERTYPUTREF */ + if(num_params != 1) { + error("expecting one arg on a propput func\n"); + return S_FALSE; + } + break; + default: + break; + } + + /* allocate type data space for us */ + typedata_size = 0x18 + extra_attr * sizeof(int) + (num_params * (num_defaults ? 16 : 12)); + + if (!typeinfo->func_data) { + typeinfo->func_data = xmalloc(0x100); + typeinfo->func_data_allocated = 0x100; + typeinfo->func_data[0] = 0; + } + + if(typeinfo->func_data[0] + typedata_size + sizeof(int) > typeinfo->func_data_allocated) { + typeinfo->func_data_allocated = max(typeinfo->func_data_allocated * 2, + typeinfo->func_data[0] + typedata_size + sizeof(int)); + typeinfo->func_data = xrealloc(typeinfo->func_data, typeinfo->func_data_allocated); + } + + offset = typeinfo->func_data[0]; + typeinfo->func_data[0] += typedata_size; + typedata = typeinfo->func_data + (offset >> 2) + 1; + + + /* find func with the same name - if it exists use its id */ + for(i = 0; i < (typeinfo->typeinfo->cElement & 0xffff); i++) { + if(name_offset == typeinfo->func_names[i]) { + id = typeinfo->func_indices[i]; + break; + } + } + + /* find the first func with the same id and link via the hiword of typedata[4] */ + next_idx = index; + for(i = 0; i < (typeinfo->typeinfo->cElement & 0xffff); i++) { + if(id == typeinfo->func_indices[i]) { + next_idx = typeinfo->func_data[(typeinfo->func_offsets[i] >> 2) + 1 + 4] >> 16; + typeinfo->func_data[(typeinfo->func_offsets[i] >> 2) + 1 + 4] &= 0xffff; + typeinfo->func_data[(typeinfo->func_offsets[i] >> 2) + 1 + 4] |= (index << 16); + break; + } + } + + /* fill out the basic type information */ + typedata[0] = typedata_size | (index << 16); + encode_var(typeinfo->typelib, func->def, &typedata[1], NULL, NULL, &decoded_size); + typedata[2] = funcflags; + typedata[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size) << 16) | typeinfo->typeinfo->cbSizeVft; + typedata[4] = (next_idx << 16) | (callconv << 8) | (invokekind << 3) | funckind; + if(num_defaults) typedata[4] |= 0x1000; + if(entry_is_ord) typedata[4] |= 0x2000; + typedata[5] = num_params; + + /* NOTE: High word of typedata[3] is total size of FUNCDESC + size of all ELEMDESCs for params + TYPEDESCs for pointer params and return types. */ + /* That is, total memory allocation required to reconstitute the FUNCDESC in its entirety. */ + typedata[3] += (16 /*sizeof(ELEMDESC)*/ * num_params) << 16; + typedata[3] += (24 /*sizeof(PARAMDESCEX)*/ * num_defaults) << 16; + + switch(extra_attr) { + case 6: typedata[11] = help_string_context; + case 5: typedata[10] = -1; + case 4: typedata[9] = -1; + case 3: typedata[8] = entry; + case 2: typedata[7] = help_string_offset; + case 1: typedata[6] = help_context; + case 0: + break; + default: + warning("unknown number of optional attrs\n"); + } + + for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) { + attr_t *attr; + int paramflags = 0; + int *paramdata = typedata + 6 + extra_attr + (num_defaults ? num_params : 0) + i * 3; + int *defaultdata = num_defaults ? typedata + 6 + extra_attr + i : NULL; + + if(defaultdata) *defaultdata = -1; + + encode_var(typeinfo->typelib, arg, paramdata, NULL, NULL, &decoded_size); + for(attr = arg->attrs; attr; attr = NEXT_LINK(attr)) { + switch(attr->type) { + case ATTR_DEFAULTVALUE_EXPR: + { + expr_t *expr = (expr_t *)attr->u.pval; + paramflags |= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */ + chat("default value %ld\n", expr->cval); + write_value(typeinfo->typelib, defaultdata, (*paramdata >> 16) & 0x1ff, &expr->cval); + break; + } + case ATTR_DEFAULTVALUE_STRING: + { + char *s = (char *)attr->u.pval; + paramflags |= 0x30; /* PARAMFLAG_FHASDEFAULT | PARAMFLAG_FOPT */ + chat("default value '%s'\n", s); + write_value(typeinfo->typelib, defaultdata, (*paramdata >> 16) & 0x1ff, s); + break; + } + case ATTR_IN: + paramflags |= 0x01; /* PARAMFLAG_FIN */ + break; + case ATTR_OPTIONAL: + paramflags |= 0x10; /* PARAMFLAG_FOPT */ + break; + case ATTR_OUT: + paramflags |= 0x02; /* PARAMFLAG_FOUT */ + break; + case ATTR_RETVAL: + paramflags |= 0x08; /* PARAMFLAG_FRETVAL */ + typedata[4] |= 0x4000; + break; + default: + chat("unhandled param attr %d\n", attr->type); + break; + } + } + paramdata[1] = -1; + paramdata[2] = paramflags; + typedata[3] += decoded_size << 16; + } + + if(typeinfo->funcs_allocated == 0) { + typeinfo->funcs_allocated = 10; + typeinfo->func_indices = xmalloc(typeinfo->funcs_allocated * sizeof(int)); + typeinfo->func_names = xmalloc(typeinfo->funcs_allocated * sizeof(int)); + typeinfo->func_offsets = xmalloc(typeinfo->funcs_allocated * sizeof(int)); + } + if(typeinfo->funcs_allocated == (typeinfo->typeinfo->cElement & 0xffff)) { + typeinfo->funcs_allocated *= 2; + typeinfo->func_indices = xrealloc(typeinfo->func_indices, typeinfo->funcs_allocated * sizeof(int)); + typeinfo->func_names = xrealloc(typeinfo->func_names, typeinfo->funcs_allocated * sizeof(int)); + typeinfo->func_offsets = xrealloc(typeinfo->func_offsets, typeinfo->funcs_allocated * sizeof(int)); + } + + /* update the index data */ + typeinfo->func_indices[typeinfo->typeinfo->cElement & 0xffff] = id; + typeinfo->func_offsets[typeinfo->typeinfo->cElement & 0xffff] = offset; + typeinfo->func_names[typeinfo->typeinfo->cElement & 0xffff] = name_offset; + + /* ??? */ + if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x20; + typeinfo->typeinfo->res2 <<= 1; + /* ??? */ + if (index < 2) typeinfo->typeinfo->res2 += num_params << 4; + + if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0; + typeinfo->typeinfo->res3 += 0x38 + num_params * 0x10; + if(num_defaults) typeinfo->typeinfo->res3 += num_params * 0x4; + + /* adjust size of VTBL */ + if(funckind != 0x3 /* FUNC_STATIC */) + typeinfo->typeinfo->cbSizeVft += 4; + + /* Increment the number of function elements */ + typeinfo->typeinfo->cElement += 1; + + namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + name_offset; + if (*((INT *)namedata) == -1) { + *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16]; + if((typeinfo->typeinfo->typekind & 15) == TKIND_MODULE) + namedata[9] |= 0x10; + } else + namedata[9] &= ~0x10; + + if((typeinfo->typeinfo->typekind & 15) == TKIND_MODULE) + namedata[9] |= 0x20; + + if(invokekind != 0x4 /* INVOKE_PROPERTYPUT */ && invokekind != 0x8 /* INVOKE_PROPERTYPUTREF */) { + /* don't give the arg of a [propput*] func a name */ + for (arg = last_arg, i = 0; arg; arg = PREV_LINK(arg), i++) { + int *paramdata = typedata + 6 + extra_attr + (num_defaults ? num_params : 0) + i * 3; + offset = ctl2_alloc_name(typeinfo->typelib, arg->name); + paramdata[1] = offset; + } + } + return S_OK; +} + +static HRESULT add_var_desc(msft_typeinfo_t *typeinfo, UINT index, var_t* var) +{ + int offset, typedata_size, id; + INT *typedata; + int var_datawidth; + int var_alignment; + int var_type_size, var_kind = 0 /* VAR_PERINSTANCE */; + int alignment; + int varflags = 0; + attr_t *attr; + char *namedata; + int var_num = (typeinfo->typeinfo->cElement >> 16) & 0xffff; + + chat("add_var_desc(%d,%s) array %p\n", index, var->name, var->array); + + id = 0x40000000 + index; + + for(attr = var->attrs; attr; attr = NEXT_LINK(attr)) { + expr_t *expr = attr->u.pval; + switch(attr->type) { + case ATTR_HIDDEN: + varflags |= 0x40; /* VARFLAG_FHIDDEN */ + break; + case ATTR_ID: + id = expr->u.lval; + break; + case ATTR_READONLY: + varflags |= 0x01; /* VARFLAG_FREADONLY */ + break; + case ATTR_RESTRICTED: + varflags |= 0x80; /* VARFLAG_FRESTRICTED */ + break; + case ATTR_SOURCE: + varflags |= 0x02; /* VARFLAG_FSOURCE */ + break; + default: + warning("AddVarDesc: unhandled attr type %d\n", attr->type); + break; + } + } + + /* allocate type data space for us */ + typedata_size = 0x14; + + if (!typeinfo->var_data) { + typeinfo->var_data = xmalloc(0x100); + typeinfo->var_data_allocated = 0x100; + typeinfo->var_data[0] = 0; + } + + if(typeinfo->var_data[0] + typedata_size + sizeof(int) > typeinfo->var_data_allocated) { + typeinfo->var_data_allocated = max(typeinfo->var_data_allocated * 2, + typeinfo->var_data[0] + typedata_size + sizeof(int)); + typeinfo->var_data = xrealloc(typeinfo->var_data, typeinfo->var_data_allocated); + } + + offset = typeinfo->var_data[0]; + typeinfo->var_data[0] += typedata_size; + typedata = typeinfo->var_data + (offset >> 2) + 1; + + /* fill out the basic type information */ + typedata[0] = typedata_size | (index << 16); + typedata[2] = varflags; + typedata[3] = (36 /*sizeof(VARDESC)*/ << 16) | 0; + + if(typeinfo->vars_allocated == 0) { + typeinfo->vars_allocated = 10; + typeinfo->var_indices = xmalloc(typeinfo->vars_allocated * sizeof(int)); + typeinfo->var_names = xmalloc(typeinfo->vars_allocated * sizeof(int)); + typeinfo->var_offsets = xmalloc(typeinfo->vars_allocated * sizeof(int)); + } + if(typeinfo->vars_allocated == var_num) { + typeinfo->vars_allocated *= 2; + typeinfo->var_indices = xrealloc(typeinfo->var_indices, typeinfo->vars_allocated * sizeof(int)); + typeinfo->var_names = xrealloc(typeinfo->var_names, typeinfo->vars_allocated * sizeof(int)); + typeinfo->var_offsets = xrealloc(typeinfo->var_offsets, typeinfo->vars_allocated * sizeof(int)); + } + /* update the index data */ + typeinfo->var_indices[var_num] = id; + typeinfo->var_names[var_num] = -1; + typeinfo->var_offsets[var_num] = offset; + + /* figure out type widths and whatnot */ + encode_var(typeinfo->typelib, var, &typedata[1], &var_datawidth, + &var_alignment, &var_type_size); + + /* pad out starting position to data width */ + typeinfo->datawidth += var_alignment - 1; + typeinfo->datawidth &= ~(var_alignment - 1); + + switch(typeinfo->typeinfo->typekind & 0xf) { + case TKIND_ENUM: + write_value(typeinfo->typelib, &typedata[4], VT_I4, &var->lval); + var_kind = 2; /* VAR_CONST */ + var_type_size += 16; /* sizeof(VARIANT) */ + typeinfo->datawidth = var_datawidth; + break; + case TKIND_RECORD: + typedata[4] = typeinfo->datawidth; + typeinfo->datawidth += var_datawidth; + break; + case TKIND_DISPATCH: + var_kind = 3; /* VAR_DISPATCH */ + typeinfo->datawidth = 4; + var_alignment = 4; + break; + default: + error("add_var_desc: unhandled type kind %d\n", typeinfo->typeinfo->typekind & 0xf); + break; + } + + /* add type description size to total required allocation */ + typedata[3] += var_type_size << 16 | var_kind; + + /* fix type alignment */ + alignment = (typeinfo->typeinfo->typekind >> 11) & 0x1f; + if (alignment < var_alignment) { + alignment = var_alignment; + typeinfo->typeinfo->typekind &= ~0xffc0; + typeinfo->typeinfo->typekind |= alignment << 11 | alignment << 6; + } + + /* ??? */ + if (!typeinfo->typeinfo->res2) typeinfo->typeinfo->res2 = 0x1a; + if ((index == 0) || (index == 1) || (index == 2) || (index == 4) || (index == 9)) { + typeinfo->typeinfo->res2 <<= 1; + } + + /* ??? */ + if (typeinfo->typeinfo->res3 == -1) typeinfo->typeinfo->res3 = 0; + typeinfo->typeinfo->res3 += 0x2c; + + /* increment the number of variable elements */ + typeinfo->typeinfo->cElement += 0x10000; + + /* pad data width to alignment */ + typeinfo->typeinfo->size = (typeinfo->datawidth + (alignment - 1)) & ~(alignment - 1); + + offset = ctl2_alloc_name(typeinfo->typelib, var->name); + if (offset == -1) return E_OUTOFMEMORY; + + namedata = typeinfo->typelib->typelib_segment_data[MSFT_SEG_NAME] + offset; + if (*((INT *)namedata) == -1) { + *((INT *)namedata) = typeinfo->typelib->typelib_typeinfo_offsets[typeinfo->typeinfo->typekind >> 16]; + if((typeinfo->typeinfo->typekind & 15) != TKIND_DISPATCH) + namedata[9] |= 0x10; + } else + namedata[9] &= ~0x10; + + if ((typeinfo->typeinfo->typekind & 15) == TKIND_ENUM) { + namedata[9] |= 0x20; + } + typeinfo->var_names[var_num] = offset; + + return S_OK; +} + +static HRESULT add_impl_type(msft_typeinfo_t *typeinfo, type_t *ref) +{ + if(ref->typelib_idx == -1) + add_interface_typeinfo(typeinfo->typelib, ref); + if(ref->typelib_idx == -1) + error("add_impl_type: unable to add inherited interface\n"); + + typeinfo->typeinfo->datatype1 = typeinfo->typelib->typelib_typeinfo_offsets[ref->typelib_idx]; + typeinfo->typeinfo->cImplTypes++; + return S_OK; +} + +static msft_typeinfo_t *create_msft_typeinfo(msft_typelib_t *typelib, enum type_kind kind, + char *name, attr_t *attr, int idx) +{ + msft_typeinfo_t *msft_typeinfo; + int nameoffset; + int typeinfo_offset; + MSFT_TypeInfoBase *typeinfo; + MSFT_GuidEntry guidentry; + + chat("create_msft_typeinfo: name %s kind %d\n", name, kind); + + msft_typeinfo = xmalloc(sizeof(*msft_typeinfo)); + + msft_typeinfo->typelib = typelib; + + nameoffset = ctl2_alloc_name(typelib, name); + typeinfo_offset = ctl2_alloc_typeinfo(typelib, nameoffset); + typeinfo = (MSFT_TypeInfoBase *)&typelib->typelib_segment_data[MSFT_SEG_TYPEINFO][typeinfo_offset]; + + typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset + 9] = 0x38; + *((int *)&typelib->typelib_segment_data[MSFT_SEG_NAME][nameoffset]) = typeinfo_offset; + + msft_typeinfo->typeinfo = typeinfo; + + typeinfo->typekind |= kind | 0x20; + + if(kind == TKIND_COCLASS) + typeinfo->flags |= 0x2; /* TYPEFLAG_FCANCREATE */ + + for( ; attr; attr = NEXT_LINK(attr)) { + switch(attr->type) { + case ATTR_DISPINTERFACE: + break; + + case ATTR_DLLNAME: + { + int offset = ctl2_alloc_string(typelib, attr->u.pval); + typeinfo->datatype1 = offset; + break; + } + case ATTR_HELPCONTEXT: + { + expr_t *expr = (expr_t*)attr->u.pval; + typeinfo->helpcontext = expr->cval; + break; + } + case ATTR_HELPSTRING: + { + int offset = ctl2_alloc_string(typelib, attr->u.pval); + if (offset == -1) break; + typeinfo->docstringoffs = offset; + break; + } + case ATTR_HELPSTRINGCONTEXT: + { + expr_t *expr = (expr_t*)attr->u.pval; + typeinfo->helpstringcontext = expr->cval; + break; + } + case ATTR_HIDDEN: + typeinfo->flags |= 0x10; /* TYPEFLAG_FHIDDEN */ + break; + + case ATTR_NONCREATABLE: + typeinfo->flags &= ~0x2; /* TYPEFLAG_FCANCREATE */ + break; + + case ATTR_ODL: + break; + + case ATTR_PUBLIC: + break; + + case ATTR_RESTRICTED: + typeinfo->flags |= 0x200; /* TYPEFLAG_FRESTRICTED */ + break; + + case ATTR_UUID: + guidentry.guid = *(GUID*)attr->u.pval; + guidentry.hreftype = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16]; + guidentry.next_hash = -1; + typeinfo->posguid = ctl2_alloc_guid(typelib, &guidentry); +#if 0 + if (IsEqualIID(guid, &IID_IDispatch)) { + typelib->typelib_header.dispatchpos = typelib->typelib_typeinfo_offsets[typeinfo->typekind >> 16]; + } +#endif + break; + + case ATTR_VERSION: + typeinfo->version = attr->u.ival; + break; + + default: + warning("create_msft_typeinfo: ignoring attr %d\n", attr->type); + break; + } + } + + if (typelib->last_typeinfo) typelib->last_typeinfo->next_typeinfo = msft_typeinfo; + typelib->last_typeinfo = msft_typeinfo; + if (!typelib->typeinfos) typelib->typeinfos = msft_typeinfo; + + + return msft_typeinfo; +} + +static void add_dispatch(msft_typelib_t *typelib) +{ + int guid_offset, impfile_offset; + MSFT_GuidEntry guidentry; + MSFT_ImpInfo impinfo; + GUID stdole = {0x00020430,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; + GUID iid_idispatch = {0x00020400,0x0000,0x0000,{0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; + + if(typelib->typelib_header.dispatchpos != -1) return; + + guidentry.guid = stdole; + guidentry.hreftype = 2; + guidentry.next_hash = -1; + guid_offset = ctl2_alloc_guid(typelib, &guidentry); + impfile_offset = alloc_importfile(typelib, guid_offset, 2, 0, "stdole2.tlb"); + + guidentry.guid = iid_idispatch; + guidentry.hreftype = 1; + guidentry.next_hash = -1; + impinfo.res0 = 0x301 << 16; + impinfo.oImpFile = impfile_offset; + impinfo.oGuid = ctl2_alloc_guid(typelib, &guidentry); + typelib->typelib_header.dispatchpos = alloc_importinfo(typelib, &impinfo) | 0x01; + + typelib->typelib_header.res50 = 1; + +} + +static void add_dispinterface_typeinfo(msft_typelib_t *typelib, type_t *dispinterface) +{ + int idx = 0; + func_t *func; + var_t *var; + msft_typeinfo_t *msft_typeinfo; + + dispinterface->typelib_idx = typelib->typelib_header.nrtypeinfos; + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_DISPATCH, dispinterface->name, + dispinterface->attrs, typelib->typelib_header.nrtypeinfos); + + msft_typeinfo->typeinfo->size = 4; + msft_typeinfo->typeinfo->typekind |= 0x2100; + + msft_typeinfo->typeinfo->flags |= 0x1000; /* TYPEFLAG_FDISPATCHABLE */ + add_dispatch(typelib); + msft_typeinfo->typeinfo->cImplTypes = 1; + + /* count the no of funcs, as the variable indicies come after the funcs */ + if((func = dispinterface->funcs)) { + idx++; + while(NEXT_LINK(func)) { + func = NEXT_LINK(func); + idx++; + } + } + + if((var = dispinterface->fields)) { + while(NEXT_LINK(var)) var = NEXT_LINK(var); + while(var) { + add_var_desc(msft_typeinfo, idx, var); + idx++; + var = PREV_LINK(var); + } + } + + idx = 0; + /* the func count above has already left us pointing at the first func */ + while(func) { + if(add_func_desc(msft_typeinfo, func, idx) == S_OK) + idx++; + func = PREV_LINK(func); + } +} + +static void add_interface_typeinfo(msft_typelib_t *typelib, type_t *interface) +{ + int idx = 0; + func_t *func; + type_t *ref; + msft_typeinfo_t *msft_typeinfo; + int num_parents = 0, num_funcs = 0; + attr_t *attr; + + for(attr = interface->attrs; attr; attr = NEXT_LINK(attr)) + if(attr->type == ATTR_DISPINTERFACE) + return add_dispinterface_typeinfo(typelib, interface); + + /* midl adds the parent interface first, unless the parent itself + has no parent (i.e. it stops before IUnknown). */ + + if(interface->ref && interface->ref->ref && interface->ref->typelib_idx == -1) + add_interface_typeinfo(typelib, interface->ref); + + interface->typelib_idx = typelib->typelib_header.nrtypeinfos; + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_INTERFACE, interface->name, interface->attrs, + typelib->typelib_header.nrtypeinfos); + msft_typeinfo->typeinfo->size = 4; + msft_typeinfo->typeinfo->typekind |= 0x2200; + + if(interface->ref) + add_impl_type(msft_typeinfo, interface->ref); + + /* count the number of inherited interfaces and non-local functions */ + for(ref = interface->ref; ref; ref = ref->ref) { + num_parents++; + for(func = ref->funcs; func; func = NEXT_LINK(func)) { + attr_t *attr; + for(attr = func->def->attrs; attr; attr = NEXT_LINK(attr)) + if(attr->type == ATTR_LOCAL) + break; + if(!attr) + num_funcs++; + } + } + msft_typeinfo->typeinfo->datatype2 = num_funcs << 16 | num_parents; + msft_typeinfo->typeinfo->cbSizeVft = num_funcs * 4; + + if((func = interface->funcs)) { + while(NEXT_LINK(func)) func = NEXT_LINK(func); + while(func) { + if(add_func_desc(msft_typeinfo, func, idx) == S_OK) + idx++; + func = PREV_LINK(func); + } + } +} + +static void add_structure_typeinfo(msft_typelib_t *typelib, type_t *structure) +{ + int idx = 0; + var_t *cur = structure->fields; + msft_typeinfo_t *msft_typeinfo; + + structure->typelib_idx = typelib->typelib_header.nrtypeinfos; + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_RECORD, structure->name, structure->attrs, + typelib->typelib_header.nrtypeinfos); + msft_typeinfo->typeinfo->size = 0; + + while(NEXT_LINK(cur)) cur = NEXT_LINK(cur); + while(cur) { + add_var_desc(msft_typeinfo, idx, cur); + idx++; + cur = PREV_LINK(cur); + } +} + +static void add_enum_typeinfo(msft_typelib_t *typelib, type_t *enumeration) +{ + int idx = 0; + var_t *cur = enumeration->fields; + msft_typeinfo_t *msft_typeinfo; + + enumeration->typelib_idx = typelib->typelib_header.nrtypeinfos; + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_ENUM, enumeration->name, enumeration->attrs, + typelib->typelib_header.nrtypeinfos); + msft_typeinfo->typeinfo->size = 0; + + while(NEXT_LINK(cur)) cur = NEXT_LINK(cur); + while(cur) { + add_var_desc(msft_typeinfo, idx, cur); + idx++; + cur = PREV_LINK(cur); + } +} + +static void add_typedef_typeinfo(msft_typelib_t *typelib, var_t *tdef) +{ + msft_typeinfo_t *msft_typeinfo; + int alignment; + attr_t *attrs; + + tdef->type->typelib_idx = typelib->typelib_header.nrtypeinfos; + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_ALIAS, tdef->name, tdef->type->attrs, + typelib->typelib_header.nrtypeinfos); + attrs = tdef->type->attrs; + tdef->type->attrs = NULL; + encode_var(typelib, tdef, &msft_typeinfo->typeinfo->datatype1, &msft_typeinfo->typeinfo->size, + &alignment, &msft_typeinfo->typeinfo->datatype2); + tdef->type->attrs = attrs; + msft_typeinfo->typeinfo->typekind |= (alignment << 11 | alignment << 6); +} + +static void add_coclass_typeinfo(msft_typelib_t *typelib, class_t *cls) +{ + msft_typeinfo_t *msft_typeinfo; + ifref_t *iref; + int num_ifaces = 0, offset, i; + MSFT_RefRecord *ref, *first = NULL, *first_source = NULL; + int have_default = 0, have_default_source = 0; + attr_t *attr; + + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_COCLASS, cls->name, cls->attrs, + typelib->typelib_header.nrtypeinfos); + + if((iref = cls->ifaces)) { + num_ifaces++; + while(NEXT_LINK(iref)) { + iref = NEXT_LINK(iref); + num_ifaces++; + } + } + + offset = msft_typeinfo->typeinfo->datatype1 = ctl2_alloc_segment(typelib, MSFT_SEG_REFERENCES, + num_ifaces * sizeof(*ref), 0); + for(i = 0; i < num_ifaces; i++) { + if(iref->iface->typelib_idx == -1) + add_interface_typeinfo(typelib, iref->iface); + ref = (MSFT_RefRecord*) (typelib->typelib_segment_data[MSFT_SEG_REFERENCES] + offset + i * sizeof(*ref)); + ref->reftype = typelib->typelib_typeinfo_offsets[iref->iface->typelib_idx]; + ref->flags = 0; + ref->oCustData = -1; + ref->onext = -1; + if(i < num_ifaces - 1) + ref->onext = offset + (i + 1) * sizeof(*ref); + + for(attr = iref->attrs; attr; attr = NEXT_LINK(attr)) { + switch(attr->type) { + case ATTR_DEFAULT: + ref->flags |= 0x1; /* IMPLTYPEFLAG_FDEFAULT */ + break; + case ATTR_RESTRICTED: + ref->flags |= 0x4; /* IMPLTYPEFLAG_FRESTRICTED */ + break; + case ATTR_SOURCE: + ref->flags |= 0x2; /* IMPLTYPEFLAG_FSOURCE */ + break; + default: + warning("add_coclass_typeinfo: unhandled attr %d\n", attr->type); + } + } + if(ref->flags & 0x1) { /* IMPLTYPEFLAG_FDEFAULT */ + if(ref->flags & 0x2) /* IMPLTYPEFLAG_SOURCE */ + have_default_source = 1; + else + have_default = 1; + } + + /* If the interface is non-restricted and we haven't already had one then + remember it so that we can use it as a default later */ + if((ref->flags & 0x4) == 0) { /* IMPLTYPEFLAG_FRESTRICTED */ + if(ref->flags & 0x2) { /* IMPLTYPEFLAG_FSOURCE */ + if(!first_source) + first_source = ref; + } + else if(!first) + first = ref; + } + iref = PREV_LINK(iref); + } + + /* If we haven't had a default interface, then set the default flags on the + first ones */ + if(!have_default && first) + first->flags |= 0x1; + if(!have_default_source && first_source) + first_source->flags |= 0x1; + + msft_typeinfo->typeinfo->cImplTypes = num_ifaces; + msft_typeinfo->typeinfo->size = 4; + msft_typeinfo->typeinfo->typekind |= 0x2200; +} + +static void add_module_typeinfo(msft_typelib_t *typelib, type_t *module) +{ + int idx = 0; + func_t *func; + msft_typeinfo_t *msft_typeinfo; + + module->typelib_idx = typelib->typelib_header.nrtypeinfos; + msft_typeinfo = create_msft_typeinfo(typelib, TKIND_MODULE, module->name, module->attrs, + typelib->typelib_header.nrtypeinfos); + msft_typeinfo->typeinfo->typekind |= 0x0a00; + + if((func = module->funcs)) { + while(NEXT_LINK(func)) func = NEXT_LINK(func); + while(func) { + if(add_func_desc(msft_typeinfo, func, idx) == S_OK) + idx++; + func = PREV_LINK(func); + } + } + msft_typeinfo->typeinfo->size = idx; +} + +static void add_entry(msft_typelib_t *typelib, typelib_entry_t *entry) +{ + switch(entry->kind) { + case TKIND_INTERFACE: + add_interface_typeinfo(typelib, entry->u.interface); + break; + + case TKIND_RECORD: + add_structure_typeinfo(typelib, entry->u.structure); + break; + + case TKIND_ENUM: + add_enum_typeinfo(typelib, entry->u.enumeration); + break; + + case TKIND_ALIAS: + add_typedef_typeinfo(typelib, entry->u.tdef); + break; + + case TKIND_COCLASS: + add_coclass_typeinfo(typelib, entry->u.class); + break; + + case TKIND_MODULE: + add_module_typeinfo(typelib, entry->u.module); + break; + + default: + error("add_entry: unhandled type %d\n", entry->kind); + break; + } +} + +static void set_name(msft_typelib_t *typelib) +{ + int offset; + + offset = ctl2_alloc_name(typelib, typelib->typelib->name); + if (offset == -1) return; + typelib->typelib_header.NameOffset = offset; + return; +} + +static void set_version(msft_typelib_t *typelib) +{ + long version = MAKELONG(0,0); + attr_t *attr; + + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_VERSION) { + version = attr->u.ival; + } + } + typelib->typelib_header.version = version; + return; +} + +static void set_guid(msft_typelib_t *typelib) +{ + MSFT_GuidEntry guidentry; + int offset; + attr_t *attr; + GUID guid = {0,0,0,{0,0,0,0,0,0}}; + + guidentry.guid = guid; + guidentry.hreftype = -2; + guidentry.next_hash = -1; + + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_UUID) { + guidentry.guid = *(GUID*)(attr->u.pval); + } + } + + offset = ctl2_alloc_guid(typelib, &guidentry); + + if (offset == -1) return; + + typelib->typelib_header.posguid = offset; + + return; +} + +static void set_doc_string(msft_typelib_t *typelib) +{ + attr_t *attr; + int offset; + + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_HELPSTRING) { + offset = ctl2_alloc_string(typelib, attr->u.pval); + if (offset == -1) return; + typelib->typelib_header.helpstring = offset; + } + } + return; +} + +static void set_help_file_name(msft_typelib_t *typelib) +{ + int offset; + attr_t *attr; + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_HELPFILE) { + offset = ctl2_alloc_string(typelib, attr->u.pval); + if (offset == -1) return; + typelib->typelib_header.helpfile = offset; + typelib->typelib_header.varflags |= 0x10; + } + } + return; +} + +static void set_help_context(msft_typelib_t *typelib) +{ + attr_t *attr; + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_HELPCONTEXT) { + expr_t *expr = (expr_t *)attr->u.pval; + typelib->typelib_header.helpcontext = expr->cval; + } + } + return; +} + +static void set_help_string_dll(msft_typelib_t *typelib) +{ + int offset; + attr_t *attr; + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_HELPSTRINGDLL) { + offset = ctl2_alloc_string(typelib, attr->u.pval); + if (offset == -1) return; + typelib->help_string_dll_offset = offset; + typelib->typelib_header.varflags |= 0x100; + } + } + return; +} + +static void set_help_string_context(msft_typelib_t *typelib) +{ + attr_t *attr; + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + if(attr->type == ATTR_HELPSTRINGCONTEXT) { + expr_t *expr = (expr_t *)attr->u.pval; + typelib->typelib_header.helpstringcontext = expr->cval; + } + } + return; +} + +static void set_lcid(msft_typelib_t *typelib) +{ + typelib->typelib_header.lcid2 = 0x0; + return; +} + +static void set_lib_flags(msft_typelib_t *typelib) +{ + attr_t *attr; + + typelib->typelib_header.flags = 0; + for(attr = typelib->typelib->attrs; attr; attr = NEXT_LINK(attr)) { + switch(attr->type) { + case ATTR_CONTROL: + typelib->typelib_header.flags |= 0x02; /* LIBFLAG_FCONTROL */ + break; + case ATTR_HIDDEN: + typelib->typelib_header.flags |= 0x04; /* LIBFLAG_FHIDDEN */ + break; + case ATTR_RESTRICTED: + typelib->typelib_header.flags |= 0x01; /* LIBFLAG_FRESTRICTED */ + break; + default: + break; + } + } + return; +} + +static int ctl2_write_chunk(int fd, void *segment, int length) +{ + if (write(fd, segment, length) != length) { + close(fd); + return 0; + } + return -1; +} + +static int ctl2_write_segment(msft_typelib_t *typelib, int fd, int segment) +{ + if (write(fd, typelib->typelib_segment_data[segment], typelib->typelib_segdir[segment].length) + != typelib->typelib_segdir[segment].length) { + close(fd); + return 0; + } + + return -1; +} + +static void ctl2_finalize_typeinfos(msft_typelib_t *typelib, int filesize) +{ + msft_typeinfo_t *typeinfo; + + for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + typeinfo->typeinfo->memoffset = filesize; + if (typeinfo->func_data) + filesize += typeinfo->func_data[0] + ((typeinfo->typeinfo->cElement & 0xffff) * 12); + if (typeinfo->var_data) + filesize += typeinfo->var_data[0] + (((typeinfo->typeinfo->cElement >> 16) & 0xffff) * 12); + if (typeinfo->func_data || typeinfo->var_data) + filesize += 4; + } +} + +static int ctl2_finalize_segment(msft_typelib_t *typelib, int filepos, int segment) +{ + if (typelib->typelib_segdir[segment].length) { + typelib->typelib_segdir[segment].offset = filepos; + } else { + typelib->typelib_segdir[segment].offset = -1; + } + + return typelib->typelib_segdir[segment].length; +} + + +static void ctl2_write_typeinfos(msft_typelib_t *typelib, int fd) +{ + msft_typeinfo_t *typeinfo; + int typedata_size; + + for (typeinfo = typelib->typeinfos; typeinfo; typeinfo = typeinfo->next_typeinfo) { + if (!typeinfo->func_data && !typeinfo->var_data) continue; + typedata_size = 0; + if (typeinfo->func_data) + typedata_size = typeinfo->func_data[0]; + if (typeinfo->var_data) + typedata_size += typeinfo->var_data[0]; + ctl2_write_chunk(fd, &typedata_size, sizeof(int)); + if (typeinfo->func_data) + ctl2_write_chunk(fd, typeinfo->func_data + 1, typeinfo->func_data[0]); + if (typeinfo->var_data) + ctl2_write_chunk(fd, typeinfo->var_data + 1, typeinfo->var_data[0]); + if (typeinfo->func_indices) + ctl2_write_chunk(fd, typeinfo->func_indices, (typeinfo->typeinfo->cElement & 0xffff) * 4); + if (typeinfo->var_indices) + ctl2_write_chunk(fd, typeinfo->var_indices, (typeinfo->typeinfo->cElement >> 16) * 4); + if (typeinfo->func_names) + ctl2_write_chunk(fd, typeinfo->func_names, (typeinfo->typeinfo->cElement & 0xffff) * 4); + if (typeinfo->var_names) + ctl2_write_chunk(fd, typeinfo->var_names, (typeinfo->typeinfo->cElement >> 16) * 4); + if (typeinfo->func_offsets) + ctl2_write_chunk(fd, typeinfo->func_offsets, (typeinfo->typeinfo->cElement & 0xffff) * 4); + if (typeinfo->var_offsets) { + int add = 0, i, offset; + if(typeinfo->func_data) + add = typeinfo->func_data[0]; + for(i = 0; i < (typeinfo->typeinfo->cElement >> 16); i++) { + offset = typeinfo->var_offsets[i]; + offset += add; + ctl2_write_chunk(fd, &offset, 4); + } + } + } +} + +static int save_all_changes(msft_typelib_t *typelib) +{ + int retval; + int filepos; + int fd; + + chat("save_all_changes(%p)\n", typelib); + + retval = TYPE_E_IOERROR; + + fd = creat(typelib->typelib->filename, 0666); + if (fd == -1) return retval; + + filepos = sizeof(MSFT_Header) + sizeof(MSFT_SegDir); + if(typelib->typelib_header.varflags & 0x100) filepos += 4; /* helpstringdll */ + filepos += typelib->typelib_header.nrtypeinfos * 4; + + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEINFO); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUIDHASH); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_GUID); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTINFO); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_IMPORTFILES); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_REFERENCES); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAMEHASH); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_NAME); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_STRING); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_TYPEDESC); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_ARRAYDESC); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATA); + filepos += ctl2_finalize_segment(typelib, filepos, MSFT_SEG_CUSTDATAGUID); + + ctl2_finalize_typeinfos(typelib, filepos); + + if (!ctl2_write_chunk(fd, &typelib->typelib_header, sizeof(typelib->typelib_header))) return retval; + if(typelib->typelib_header.varflags & 0x100) + if (!ctl2_write_chunk(fd, &typelib->help_string_dll_offset, sizeof(typelib->help_string_dll_offset))) + return retval; + + if (!ctl2_write_chunk(fd, typelib->typelib_typeinfo_offsets, typelib->typelib_header.nrtypeinfos * 4)) return retval; + if (!ctl2_write_chunk(fd, &typelib->typelib_segdir, sizeof(typelib->typelib_segdir))) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEINFO )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUIDHASH )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_GUID )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTINFO )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_IMPORTFILES )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_REFERENCES )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAMEHASH )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_NAME )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_STRING )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_TYPEDESC )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_ARRAYDESC )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATA )) return retval; + if (!ctl2_write_segment(typelib, fd, MSFT_SEG_CUSTDATAGUID)) return retval; + + ctl2_write_typeinfos(typelib, fd); + + if (close(fd) == -1) return retval; + + retval = S_OK; + return retval; +} + +int create_msft_typelib(typelib_t *typelib) +{ + msft_typelib_t *msft; + int failed = 0; + typelib_entry_t *entry; + time_t cur_time; + unsigned int version = 5 << 24 | 1 << 16 | 164; /* 5.01.0164 */ + GUID midl_time_guid = {0xde77ba63,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}}; + GUID midl_version_guid = {0xde77ba64,0x517c,0x11d1,{0xa2,0xda,0x00,0x00,0xf8,0x77,0x3c,0xe9}}; + + msft = malloc(sizeof(*msft)); + if (!msft) return 0; + memset(msft, 0, sizeof(*msft)); + msft->typelib = typelib; + + ctl2_init_header(msft); + ctl2_init_segdir(msft); + + msft->typelib_header.varflags |= SYS_WIN32; + + /* + * The following two calls return an offset or -1 if out of memory. We + * specifically need an offset of 0, however, so... + */ + if (ctl2_alloc_segment(msft, MSFT_SEG_GUIDHASH, 0x80, 0x80)) { failed = 1; } + if (ctl2_alloc_segment(msft, MSFT_SEG_NAMEHASH, 0x200, 0x200)) { failed = 1; } + + if(failed) return 0; + + msft->typelib_guidhash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_GUIDHASH]; + msft->typelib_namehash_segment = (int *)msft->typelib_segment_data[MSFT_SEG_NAMEHASH]; + + memset(msft->typelib_guidhash_segment, 0xff, 0x80); + memset(msft->typelib_namehash_segment, 0xff, 0x200); + + set_lib_flags(msft); + set_lcid(msft); + set_help_file_name(msft); + set_doc_string(msft); + set_guid(msft); + set_version(msft); + set_name(msft); + set_help_context(msft); + set_help_string_dll(msft); + set_help_string_context(msft); + + /* midl adds two sets of custom data to the library: the current unix time + and midl's version number */ + cur_time = time(NULL); + set_custdata(msft, &midl_time_guid, VT_UI4, &cur_time, &msft->typelib_header.CustomDataOffset); + set_custdata(msft, &midl_version_guid, VT_UI4, &version, &msft->typelib_header.CustomDataOffset); + + for(entry = typelib->entry; entry && NEXT_LINK(entry); entry = NEXT_LINK(entry)) + ; + + for( ; entry; entry = PREV_LINK(entry)) + add_entry(msft, entry); + + save_all_changes(msft); + return 1; +}