From 95266a585cb4c924250c900a3b8c3c63ebbf0699 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Tue, 19 Jan 2016 18:44:00 +0800
Subject: widl: Add support for inherited interfaces to SLTG typelib generator.

---
 tools/widl/write_sltg.c | 90 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 73 insertions(+), 17 deletions(-)

diff --git a/tools/widl/write_sltg.c b/tools/widl/write_sltg.c
index 556816f..c8a8cfb 100644
--- a/tools/widl/write_sltg.c
+++ b/tools/widl/write_sltg.c
@@ -225,6 +225,22 @@ struct sltg_function
 #endif
 };
 
+struct sltg_impl_info
+{
+    short res00;
+    short next;
+    short res04;
+    char impltypeflags;
+    char res07;
+    short res08;
+    short ref;
+    short res0c;
+    short res0e;
+    short res10;
+    short res12;
+    short pos;
+};
+
 #include "poppack.h"
 
 static void add_structure_typeinfo(struct sltg_typelib *typelib, type_t *type);
@@ -1311,18 +1327,39 @@ static int add_func_desc(struct sltg_typelib *typelib, struct sltg_data *data, v
     return data->size - old_size;
 }
 
+static void write_impl_href(struct sltg_data *data, short href)
+{
+    struct sltg_impl_info impl_info;
+
+    impl_info.res00 = 0x004a;
+    impl_info.next = -1;
+    impl_info.res04 = -1;
+    impl_info.impltypeflags = 0;
+    impl_info.res07 = 0x80;
+    impl_info.res08 = 0x0012;
+    impl_info.ref = href;
+    impl_info.res0c = 0x4001;
+    impl_info.res0e = -2; /* 0xfffe */
+    impl_info.res10 = -1;
+    impl_info.res12 = 0x001d;
+    impl_info.pos = 0;
+
+    append_data(data, &impl_info, sizeof(impl_info));
+}
+
 static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
 {
     const statement_t *stmt_func;
     importinfo_t *ref_importinfo = NULL;
-    type_t *inherit;
+    short inherit_href = -1;
     struct sltg_data data;
     struct sltg_hrefmap hrefmap;
     const char *index_name;
     struct sltg_typeinfo_header ti;
     struct sltg_member_header member;
     struct sltg_tail tail;
-    int member_offset, base_offset, func_count, func_data_size, i;
+    int member_offset, base_offset, func_data_size, i;
+    int func_count, inherited_func_count = 0;
 
     if (iface->typelib_idx != -1) return;
 
@@ -1340,13 +1377,16 @@ static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
         return;
     }
 
-    inherit = type_iface_get_inherit(iface);
+    hrefmap.href_count = 0;
+    hrefmap.href = NULL;
 
-    if (inherit)
+    if (type_iface_get_inherit(iface))
     {
-        chat("add_interface_typeinfo: inheriting from base interface %s\n", inherit->name);
+        type_t *inherit;
 
-        warning("inheriting from base interface %s is not implemented\n", inherit->name);
+        inherit = type_iface_get_inherit(iface);
+
+        chat("add_interface_typeinfo: inheriting from base interface %s\n", inherit->name);
 
         ref_importinfo = find_importinfo(typelib->typelib, inherit->name);
 
@@ -1355,6 +1395,14 @@ static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
 
         if (ref_importinfo)
             error("support for imported interfaces is not implemented\n");
+
+        inherit_href = local_href(&hrefmap, inherit->typelib_idx);
+
+        while (inherit)
+        {
+            inherited_func_count += list_count(type_iface_get_stmts(inherit));
+            inherit = type_iface_get_inherit(inherit);
+        }
     }
 
     /* check typelib_idx again, it could have been added while resolving the parent interface */
@@ -1363,9 +1411,6 @@ static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
     iface->typelib_idx = typelib->n_file_blocks;
 
     /* pass 1: calculate function descriptions data size */
-    hrefmap.href_count = 0;
-    hrefmap.href = NULL;
-
     init_sltg_data(&data);
 
     STATEMENTS_FOR_EACH_FUNC(stmt_func, type_iface_get_stmts(iface))
@@ -1388,19 +1433,21 @@ static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
     write_hrefmap(&data, &hrefmap);
 
     member_offset = data.size;
+    base_offset = 0;
 
     member.res00 = 0x0001;
     member.res02 = 0xffff;
     member.res04 = 0x01;
     member.extra = func_data_size;
+    if (inherit_href != -1)
+    {
+        member.extra += sizeof(struct sltg_impl_info);
+        base_offset += sizeof(struct sltg_impl_info);
+    }
     append_data(&data, &member, sizeof(member));
 
-    base_offset = 0;
-
-    /* inheriting from base interface is not implemented yet
-    if (type_iface_get_inherit(iface))
-        add_impl_type(typeinfo, type_iface_get_inherit(iface), ref_importinfo);
-    */
+    if (inherit_href != -1)
+        write_impl_href(&data, inherit_href);
 
     i = 0;
 
@@ -1408,7 +1455,8 @@ static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
     {
         if (i == func_count - 1) i |= 0x80000000;
 
-        base_offset += add_func_desc(typelib, &data, stmt_func->u.var, i, base_offset, &hrefmap);
+        base_offset += add_func_desc(typelib, &data, stmt_func->u.var,
+                                     inherited_func_count + i, base_offset, &hrefmap);
         i++;
     }
 
@@ -1419,10 +1467,18 @@ static void add_interface_typeinfo(struct sltg_typelib *typelib, type_t *iface)
     tail.funcs_bytes = func_data_size;
     tail.cbSizeInstance = pointer_size;
     tail.cbAlignment = pointer_size;
-    tail.cbSizeVft = func_count * pointer_size;
+    tail.cbSizeVft = (inherited_func_count + func_count) * pointer_size;
     tail.type_bytes = data.size - member_offset - sizeof(member);
     tail.res24 = 0;
     tail.res26 = 0;
+    if (inherit_href != -1)
+    {
+        tail.cImplTypes++;
+        tail.impls_off = 0;
+        tail.impls_bytes = 0;
+
+        tail.funcs_off += sizeof(struct sltg_impl_info);
+    }
     append_data(&data, &tail, sizeof(tail));
 
     add_block(typelib, data.data, data.size, index_name);
-- 
2.6.4

