From: Vijay Kiran Kamuju Subject: [PATCH 2/4] oleaut32: Implement decoding of SLTG help strings. Message-Id: Date: Thu, 11 Jun 2020 13:12:03 +0200 Tested using builtin oleview and ole1 typelib from older DDks. oleview now shows the helpstrings for SLTG interfaces and coclasses. From: Dmitry Timoshkov Signed-off-by: Vijay Kiran Kamuju From 0da242c4c0341e040ea2d1a0d116d48224701504 Mon Sep 17 00:00:00 2001 Date: Thu, 11 Jun 2020 13:00:40 +0200 Subject: [PATCH 2/4] oleaut32: Implement decoding of SLTG help strings. Based on patch by Sebastian Lackner Tested using builtin oleview and ole1 typelib from older DDks. oleview now shows the helpstrings for SLTG interfaces and coclasses. From: Dmitry Timoshkov Signed-off-by: Vijay Kiran Kamuju --- dlls/oleaut32/typelib.c | 128 ++++++++++++++++++++++++++++++++-------- dlls/oleaut32/typelib.h | 4 +- 2 files changed, 107 insertions(+), 25 deletions(-) diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c index 1f2c6e182c..9b0cc06d39 100644 --- a/dlls/oleaut32/typelib.c +++ b/dlls/oleaut32/typelib.c @@ -3688,6 +3688,87 @@ static BOOL TLB_GUIDFromString(const char *str, GUID *guid) return TRUE; } +struct bitstream +{ + const BYTE *buffer; + DWORD length; + WORD current; +}; + +static const char *lookup_code(const BYTE *table, DWORD table_size, struct bitstream *bits) +{ + const BYTE *p = table; + + while (p < table + table_size && *p == 0x80) + { + if (p + 2 >= table + table_size) return NULL; + + if (!(bits->current & 0xff)) + { + if (!bits->length) return NULL; + bits->current = (*bits->buffer << 8) | 1; + bits->buffer++; + bits->length--; + } + + if (bits->current & 0x8000) + { + p += 3; + } + else + { + p = table + (*(p + 2) | (*(p + 1) << 8)); + } + + bits->current <<= 1; + } + + if (p + 1 < table + table_size && *(p + 1)) + { + /* FIXME: Whats the meaning of *p? */ + const BYTE *q = p + 1; + while (q < table + table_size && *q) q++; + return (q < table + table_size) ? (const char *)(p + 1) : NULL; + } + + return NULL; +} + +static const TLBString *decode_string(const BYTE *table, const char *stream, DWORD stream_length, ITypeLibImpl *lib) +{ + DWORD buf_size, table_size; + const char *p; + struct bitstream bits; + BSTR buf; + TLBString *tlbstr; + + if (!stream_length) return NULL; + + bits.buffer = (const BYTE *)stream; + bits.length = stream_length; + bits.current = 0; + + buf_size = *(const WORD *)table; + table += sizeof(WORD); + table_size = *(const DWORD *)table; + table += sizeof(DWORD); + + buf = SysAllocStringLen(NULL, buf_size); + buf[0] = 0; + + while ((p = lookup_code(table, table_size, &bits))) + { + static const WCHAR spaceW[] = { ' ',0 }; + if (buf[0]) lstrcatW(buf, spaceW); + MultiByteToWideChar(CP_ACP, 0, p, -1, buf + lstrlenW(buf), buf_size - lstrlenW(buf)); + } + + tlbstr = TLB_append_str(&lib->string_list, buf); + SysFreeString(buf); + + return tlbstr; +} + static WORD SLTG_ReadString(const char *ptr, const TLBString **pStr, ITypeLibImpl *lib) { WORD bytelen; @@ -4376,17 +4457,17 @@ static void SLTG_ProcessModule(char *pBlk, ITypeInfoImpl *pTI, /* Because SLTG_OtherTypeInfo is such a painful struct, we make a more manageable copy of it into this */ typedef struct { - WORD small_no; char *index_name; char *other_name; WORD res1a; WORD name_offs; - WORD more_bytes; + WORD hlpstr_len; char *extra; WORD res20; DWORD helpcontext; WORD res26; GUID uuid; + WORD typekind; } SLTG_InternalOtherTypeInfo; /**************************************************************************** @@ -4405,8 +4486,8 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) LPVOID pBlk, pFirstBlk; SLTG_LibBlk *pLibBlk; SLTG_InternalOtherTypeInfo *pOtherTypeInfoBlks; - char *pAfterOTIBlks = NULL; char *pNameTable, *ptr; + const BYTE *hlp_strings; int i; DWORD len, order; ITypeInfoImpl **ppTypeInfoImpl; @@ -4477,50 +4558,50 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) pOtherTypeInfoBlks = heap_alloc_zero(sizeof(*pOtherTypeInfoBlks) * pTypeLibImpl->TypeInfoCount); - ptr = (char*)pLibBlk + len; for(i = 0; i < pTypeLibImpl->TypeInfoCount; i++) { WORD w, extra; len = 0; - pOtherTypeInfoBlks[i].small_no = *(WORD*)ptr; - - w = *(WORD*)(ptr + 2); + w = *(WORD*)ptr; if(w != 0xffff) { len += w; pOtherTypeInfoBlks[i].index_name = heap_alloc(w+1); - memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 4, w); + memcpy(pOtherTypeInfoBlks[i].index_name, ptr + 2, w); pOtherTypeInfoBlks[i].index_name[w] = '\0'; } - w = *(WORD*)(ptr + 4 + len); + w = *(WORD*)(ptr + 2 + len); if(w != 0xffff) { - TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 6 + len, w)); - len += w; + TRACE_(typelib)("\twith %s\n", debugstr_an(ptr + 4 + len, w)); pOtherTypeInfoBlks[i].other_name = heap_alloc(w+1); - memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 6 + len, w); + memcpy(pOtherTypeInfoBlks[i].other_name, ptr + 4 + len, w); pOtherTypeInfoBlks[i].other_name[w] = '\0'; + len += w; } - pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + len + 6); - pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + len + 8); - extra = pOtherTypeInfoBlks[i].more_bytes = *(WORD*)(ptr + 10 + len); + pOtherTypeInfoBlks[i].res1a = *(WORD*)(ptr + 4 + len); + pOtherTypeInfoBlks[i].name_offs = *(WORD*)(ptr + 6 + len); + extra = pOtherTypeInfoBlks[i].hlpstr_len = *(WORD*)(ptr + 8 + len); if(extra) { pOtherTypeInfoBlks[i].extra = heap_alloc(extra); - memcpy(pOtherTypeInfoBlks[i].extra, ptr + 12, extra); + memcpy(pOtherTypeInfoBlks[i].extra, ptr + 10 + len, extra); len += extra; } - pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 12 + len); - pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 14 + len); - pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 18 + len); - memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 20 + len, sizeof(GUID)); + pOtherTypeInfoBlks[i].res20 = *(WORD*)(ptr + 10 + len); + pOtherTypeInfoBlks[i].helpcontext = *(DWORD*)(ptr + 12 + len); + pOtherTypeInfoBlks[i].res26 = *(WORD*)(ptr + 16 + len); + memcpy(&pOtherTypeInfoBlks[i].uuid, ptr + 18 + len, sizeof(GUID)); + pOtherTypeInfoBlks[i].typekind = *(WORD*)(ptr + 18 + sizeof(GUID) + len); len += sizeof(SLTG_OtherTypeInfo); ptr += len; } - pAfterOTIBlks = ptr; + /* Get the next DWORD */ + len = *(DWORD*)ptr; - /* Skip this WORD and get the next DWORD */ - len = *(DWORD*)(pAfterOTIBlks + 2); + hlp_strings = (const BYTE *)ptr + sizeof(DWORD); + TRACE("max help string length %#x, help strings length %#x\n", + *(WORD *)hlp_strings, *(DWORD *)(hlp_strings + 2)); /* Now add this to pLibBLk look at what we're pointing at and possibly add 0x20, then add 0x216, sprinkle a bit a magic @@ -4586,6 +4667,7 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength) (*ppTypeInfoImpl)->index = i; (*ppTypeInfoImpl)->Name = SLTG_ReadName(pNameTable, pOtherTypeInfoBlks[i].name_offs, pTypeLibImpl); (*ppTypeInfoImpl)->dwHelpContext = pOtherTypeInfoBlks[i].helpcontext; + (*ppTypeInfoImpl)->DocString = decode_string(hlp_strings, pOtherTypeInfoBlks[i].extra, pOtherTypeInfoBlks[i].hlpstr_len, pTypeLibImpl); (*ppTypeInfoImpl)->guid = TLB_append_guid(&pTypeLibImpl->guid_list, &pOtherTypeInfoBlks[i].uuid, 2); (*ppTypeInfoImpl)->typeattr.typekind = pTIHeader->typekind; (*ppTypeInfoImpl)->typeattr.wMajorVerNum = pTIHeader->major_version; diff --git a/dlls/oleaut32/typelib.h b/dlls/oleaut32/typelib.h index 9c700b11a7..f33482a54a 100644 --- a/dlls/oleaut32/typelib.h +++ b/dlls/oleaut32/typelib.h @@ -386,18 +386,18 @@ typedef struct { /* 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 + WORD hlpstr_len; /* 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; + WORD typekind; } SLTG_OtherTypeInfo; /* Next we get WORD 0x0003 followed by a DWORD which if we add to -- 2.27.0