-- v3: widl: Write the guid stream. widl: Write the blob stream. widl: Write the user string stream. widl: Write the string stream. widl: Initial support for generating Windows Runtime metadata.
From: Hans Leidekker hans@codeweavers.com
This adds a --winmd option that converts a runtime IDL file into a metadata file (.winmd). --- tools/widl/Makefile.in | 1 + tools/widl/metadata.c | 247 +++++++++++++++++++++++++++++++++++++++++ tools/widl/parser.y | 1 + tools/widl/widl.c | 26 ++++- tools/widl/widl.h | 3 + 5 files changed, 276 insertions(+), 2 deletions(-) create mode 100644 tools/widl/metadata.c
diff --git a/tools/widl/Makefile.in b/tools/widl/Makefile.in index 4caabd87ba7..39ed0ec7fbe 100644 --- a/tools/widl/Makefile.in +++ b/tools/widl/Makefile.in @@ -7,6 +7,7 @@ SOURCES = \ expr.c \ hash.c \ header.c \ + metadata.c \ parser.l \ parser.y \ ppl.l \ diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c new file mode 100644 index 00000000000..0b1fad7b1fe --- /dev/null +++ b/tools/widl/metadata.c @@ -0,0 +1,247 @@ +/* + * Copyright 2024, 2025 Hans Leidekker for CodeWeavers + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include <stdarg.h> +#include <stdio.h> + +#include "windef.h" +#include "winnt.h" + +#include "widl.h" +#include "utils.h" +#include "typetree.h" + +static const IMAGE_DOS_HEADER dos_header = +{ + .e_magic = IMAGE_DOS_SIGNATURE, + .e_lfanew = sizeof(dos_header), +}; + +#define FILE_ALIGNMENT 0x200 +#define SECTION_ALIGNMENT 0x1000 +static IMAGE_NT_HEADERS32 nt_header = +{ + .Signature = IMAGE_NT_SIGNATURE, + .FileHeader = + { + .Machine = IMAGE_FILE_MACHINE_I386, + .NumberOfSections = 1, + .TimeDateStamp = 0, + .PointerToSymbolTable = 0, + .NumberOfSymbols = 0, + .SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER32), + .Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_DLL + }, + .OptionalHeader = + { + .Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC, + .MajorLinkerVersion = 11, + .MinorLinkerVersion = 0, + .SizeOfCode = 0, + .SizeOfInitializedData = 0, + .SizeOfUninitializedData = 0, + .AddressOfEntryPoint = 0, + .BaseOfCode = 0, + .BaseOfData = 0, + .ImageBase = 0x400000, + .SectionAlignment = SECTION_ALIGNMENT, + .FileAlignment = FILE_ALIGNMENT, + .MajorOperatingSystemVersion = 6, + .MinorOperatingSystemVersion = 2, + .MajorImageVersion = 0, + .MinorImageVersion = 0, + .MajorSubsystemVersion = 6, + .MinorSubsystemVersion = 2, + .Win32VersionValue = 0, + .SizeOfImage = 0, + .SizeOfHeaders = FILE_ALIGNMENT, + .CheckSum = 0, + .Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI, + .DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | + IMAGE_DLLCHARACTERISTICS_NX_COMPAT, + .SizeOfStackReserve = 0x100000, + .SizeOfStackCommit = 0, + .SizeOfHeapReserve = 0x1000, + .SizeOfHeapCommit = 0, + .LoaderFlags = 0x100000, + .NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES, + .DataDirectory = + { + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { .VirtualAddress = SECTION_ALIGNMENT, .Size = sizeof(IMAGE_COR20_HEADER) }, { 0 } + } + } +}; + +static IMAGE_SECTION_HEADER section_header = +{ + .Name = ".text", + { .VirtualSize = 0 }, + .VirtualAddress = 0, + .SizeOfRawData = 0, + .PointerToRawData = 0, + .PointerToRelocations = 0, + .PointerToLinenumbers = 0, + .NumberOfRelocations = 0, + .NumberOfLinenumbers = 0, + .Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ +}; + +static IMAGE_COR20_HEADER cor_header = +{ + .cb = sizeof(IMAGE_COR20_HEADER), + .MajorRuntimeVersion = 2, + .MinorRuntimeVersion = 5, + .MetaData = { 0 }, + .Flags = COMIMAGE_FLAGS_ILONLY, + .EntryPointToken = 0, + .Resources = { 0 }, + .StrongNameSignature = { 0 }, + .CodeManagerTable = { 0 }, + .VTableFixups = { 0 }, + .ExportAddressTableJumps = { 0 }, + .ManagedNativeHeader = { 0 } +}; + +#define METADATA_MAGIC ('B' | ('S' << 8) | ('J' << 16) | ('B' << 24)) +static struct +{ + UINT signature; + USHORT major_version; + USHORT minor_version; + UINT reserved; + UINT length; + char version[20]; + USHORT flags; + USHORT num_streams; +} +metadata_header = +{ + METADATA_MAGIC, + 1, + 1, + 0, + 20, + "WindowsRuntime 1.4", + 0, + 0 +}; + +enum +{ + STREAM_TABLE, + STREAM_STRING, + STREAM_USERSTRING, + STREAM_GUID, + STREAM_BLOB, + STREAM_MAX +}; + +static struct +{ + UINT data_offset; + UINT data_size; + char name[12]; + UINT header_size; + const BYTE *data; +} +streams[] = +{ + { 0, 0, "#~", 12 }, + { 0, 0, "#Strings", 20 }, + { 0, 0, "#US", 12 }, + { 0, 0, "#GUID", 16 }, + { 0, 0, "#Blob", 16 } +}; + +static void write_headers( UINT image_size ) +{ + static const BYTE pad[8]; + UINT i, streams_size = 0; + USHORT num_streams = 0; + + put_data( &dos_header, sizeof(dos_header) ); + + image_size += nt_header.OptionalHeader.SizeOfHeaders + sizeof(section_header); + nt_header.OptionalHeader.SizeOfImage = (image_size + 0x1fff) & ~0x1fff; + + put_data( &nt_header, sizeof(nt_header) ); + + for (i = 0; i < STREAM_MAX; i++) + { + if (!streams[i].data_size) continue; + streams_size += streams[i].header_size + streams[i].data_size; + num_streams++; + } + + section_header.PointerToRawData = FILE_ALIGNMENT; + section_header.VirtualAddress = SECTION_ALIGNMENT; + section_header.Misc.VirtualSize = sizeof(cor_header) + sizeof(metadata_header) + streams_size + 8; + section_header.SizeOfRawData = (section_header.Misc.VirtualSize + FILE_ALIGNMENT - 1) & ~(FILE_ALIGNMENT - 1); + + put_data( §ion_header, sizeof(section_header) ); + + for (i = 0; i < FILE_ALIGNMENT - sizeof(dos_header) - sizeof(nt_header) - sizeof(section_header); i++) + put_data( pad, 1 ); + + cor_header.MetaData.VirtualAddress = section_header.VirtualAddress + sizeof(cor_header) + 8; + cor_header.MetaData.Size = sizeof(metadata_header) + streams_size; + + put_data( &cor_header, sizeof(cor_header) ); + put_data( pad, 8 ); + + metadata_header.num_streams = num_streams; + put_data( &metadata_header, sizeof(metadata_header) ); + for (i = 0; i < STREAM_MAX; i++) + { + if (!streams[i].data_size) continue; + put_data( &streams[i], streams[i].header_size ); + } +} + +static void write_streams( void ) +{ + UINT i; + for (i = 0; i < STREAM_MAX; i++) + { + if (!streams[i].data_size) continue; + put_data( streams[i].data, streams[i].data_size ); + } +} + +void write_metadata( const statement_list_t *stmts ) +{ + static const BYTE pad[FILE_ALIGNMENT]; + UINT image_size, file_size, i; + + if (!do_metadata) return; + + image_size = FILE_ALIGNMENT + sizeof(cor_header) + 8 + sizeof(metadata_header); + for (i = 0; i < STREAM_MAX; i++) image_size += streams[i].header_size + streams[i].data_size; + + init_output_buffer(); + + write_headers( image_size ); + write_streams( ); + + file_size = (image_size + FILE_ALIGNMENT - 1) & ~(FILE_ALIGNMENT - 1); + put_data( pad, file_size - image_size ); + + flush_output_buffer( metadata_name ); +} diff --git a/tools/widl/parser.y b/tools/widl/parser.y index 985f1108ce4..54b143637cf 100644 --- a/tools/widl/parser.y +++ b/tools/widl/parser.y @@ -379,6 +379,7 @@ input: gbl_statements m_acf { $1 = append_parameterized_type_stmts($1); write_typelib_regscript($1); write_dlldata($1); write_local_stubs($1); + write_metadata($1); (void)parser_nerrs; /* avoid unused variable warning */ } ; diff --git a/tools/widl/widl.c b/tools/widl/widl.c index b1ede89934f..19b85633831 100644 --- a/tools/widl/widl.c +++ b/tools/widl/widl.c @@ -77,6 +77,7 @@ static const char usage[] = " -W Enable pedantic warnings\n" " --win32, --win64 Set the target architecture (Win32 or Win64)\n" " --winrt Enable Windows Runtime mode\n" +" --winmd Generate metadata (implies --winrt)\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" @@ -105,6 +106,7 @@ int do_server = 0; int do_regscript = 0; int do_idfile = 0; int do_dlldata = 0; +int do_metadata = 0; static int no_preprocess = 0; int old_names = 0; int old_typelib = 0; @@ -120,6 +122,7 @@ char *header_name; char *local_stubs_name; char *header_token; char *typelib_name; +char *metadata_name; char *dlldata_name; char *proxy_name; char *proxy_token; @@ -168,6 +171,7 @@ enum { SYSROOT_OPTION, WIN32_OPTION, WIN64_OPTION, + WINMD_OPTION, };
static const char short_options[] = @@ -195,6 +199,7 @@ static const struct long_option long_options[] = { { "winrt", 0, RT_OPTION }, { "win32", 0, WIN32_OPTION }, { "win64", 0, WIN64_OPTION }, + { "winmd", 0, WINMD_OPTION }, { NULL } };
@@ -263,6 +268,7 @@ static void set_everything(int x) do_regscript = x; do_idfile = x; do_dlldata = x; + do_metadata = x; }
void start_cplusplus_guard(FILE *fp) @@ -519,6 +525,11 @@ static void option_callback( int optc, char *optarg ) case WIN64_OPTION: pointer_size = 8; break; + case WINMD_OPTION: + do_everything = 0; + winrt_mode = 1; + do_metadata = 1; + break; case PACKING_OPTION: packing = strtol(optarg, NULL, 0); if(packing != 2 && packing != 4 && packing != 8) @@ -719,11 +730,16 @@ int main(int argc,char *argv[])
/* if nothing specified, try to guess output type from the output file name */ if (output_name && do_everything && !do_header && !do_typelib && !do_proxies && - !do_client && !do_server && !do_regscript && !do_idfile && !do_dlldata) + !do_client && !do_server && !do_regscript && !do_idfile && !do_dlldata && !do_metadata) { do_everything = 0; if (strendswith( output_name, ".h" )) do_header = 1; else if (strendswith( output_name, ".tlb" )) do_typelib = 1; + else if (strendswith( output_name, ".winmd" )) + { + winrt_mode = 1; + do_metadata = 1; + } else if (strendswith( output_name, "_p.c" )) do_proxies = 1; else if (strendswith( output_name, "_c.c" )) do_client = 1; else if (strendswith( output_name, "_s.c" )) do_server = 1; @@ -740,10 +756,11 @@ int main(int argc,char *argv[]) }
if (do_header + do_typelib + do_proxies + do_client + - do_server + do_regscript + do_idfile + do_dlldata == 1 && output_name) + do_server + do_regscript + do_idfile + do_dlldata + do_metadata == 1 && output_name) { if (do_header && !header_name) header_name = output_name; else if (do_typelib && !typelib_name) typelib_name = output_name; + else if (do_metadata && !metadata_name) metadata_name = output_name; else if (do_proxies && !proxy_name) proxy_name = output_name; else if (do_client && !client_name) client_name = output_name; else if (do_server && !server_name) server_name = output_name; @@ -813,6 +830,9 @@ int main(int argc,char *argv[]) if (!idfile_name && do_idfile) idfile_name = replace_extension( get_basename(input_name), ".idl", "_i.c" );
+ if (!metadata_name && do_metadata) + metadata_name = replace_extension( get_basename(input_name), ".idl", ".winmd" ); + if (do_proxies) proxy_token = dup_basename_token(proxy_name,"_p.c"); if (do_client) client_token = dup_basename_token(client_name,"_c.c"); if (do_server) server_token = dup_basename_token(server_name,"_s.c"); @@ -857,6 +877,8 @@ static void rm_tempfile(void) unlink(proxy_name); if (do_typelib) unlink(typelib_name); + if (do_metadata) + unlink(metadata_name); remove_temp_files(); }
diff --git a/tools/widl/widl.h b/tools/widl/widl.h index 31bb2c83694..08071e8fdf8 100644 --- a/tools/widl/widl.h +++ b/tools/widl/widl.h @@ -39,6 +39,7 @@ extern int pedantic; extern int do_everything; extern int do_header; extern int do_typelib; +extern int do_metadata; extern int do_proxies; extern int do_client; extern int do_server; @@ -58,6 +59,7 @@ extern char *header_name; extern char *header_token; extern char *local_stubs_name; extern char *typelib_name; +extern char *metadata_name; extern char *dlldata_name; extern char *proxy_name; extern char *proxy_token; @@ -86,6 +88,7 @@ extern void write_typelib_regscript(const statement_list_t *stmts); extern void output_typelib_regscript( const typelib_t *typelib ); extern void write_local_stubs(const statement_list_t *stmts); extern void write_dlldata(const statement_list_t *stmts); +extern void write_metadata(const statement_list_t *stmts);
extern void start_cplusplus_guard(FILE *fp); extern void end_cplusplus_guard(FILE *fp);
From: Hans Leidekker hans@codeweavers.com
--- tools/widl/metadata.c | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+)
diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index 0b1fad7b1fe..c369a15ba09 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -215,6 +215,129 @@ static void write_headers( UINT image_size ) } }
+static struct buffer +{ + UINT offset; /* write position */ + UINT allocated; /* allocated size in bytes */ + UINT count; /* number of entries written */ + BYTE *ptr; +} strings, strings_idx; + +static void *grow_buffer( struct buffer *buf, UINT size ) +{ + UINT new_size; + + if (buf->allocated - buf->offset >= size) return buf->ptr; + + new_size = max( buf->offset + size, buf->allocated * 2 ); + buf->ptr = xrealloc( buf->ptr, new_size ); + buf->allocated = new_size; + return buf->ptr; +} + +struct index +{ + UINT offset; /* offset into corresponding data buffer */ + UINT size; /* size of data entry */ +}; + +static inline int cmp_data( const BYTE *data, UINT size, const BYTE *data2, UINT size2 ) +{ + if (size < size2) return -1; + else if (size > size2) return 1; + return memcmp( data, data2, size ); +} + +/* return index struct if found, NULL and insert index if not found */ +static const struct index *find_index( const struct buffer *buf_idx, const struct buffer *buf_data, const BYTE *data, + UINT size, UINT *insert_idx ) +{ + int i, c, min = 0, max = buf_idx->count - 1, len = 0; + const struct index *idx, *base = (const struct index *)buf_idx->ptr; + + while (min <= max) + { + i = (min + max) / 2; + idx = &base[i]; + + c = cmp_data( data, size, buf_data->ptr + idx->offset + len, idx->size ); + + if (c < 0) max = i - 1; + else if (c > 0) min = i + 1; + else return idx; + } + + if (insert_idx) *insert_idx = max + 1; + return NULL; +} + +static void insert_index( struct buffer *buf_idx, UINT idx, UINT offset, UINT size ) +{ + struct index new = { offset, size }, *base = grow_buffer( buf_idx, sizeof(new) ); + + memmove( &base[idx] + 1, &base[idx], (buf_idx->count - idx) * sizeof(new) ); + base[idx] = new; + buf_idx->offset += sizeof(new); + buf_idx->count++; +} + +static UINT add_string( const char *str ) +{ + UINT insert_idx, size, offset = strings.offset; + const struct index *idx; + + if (!str) return 0; + size = strlen( str ) + 1; + if ((idx = find_index( &strings_idx, &strings, (const BYTE *)str, size, &insert_idx ))) + return idx->offset; + + grow_buffer( &strings, size ); + memcpy( strings.ptr + offset, str, size ); + strings.offset += size; + strings.count++; + + insert_index( &strings_idx, insert_idx, offset, size ); + return offset; +} + +static void add_bytes( struct buffer *buf, const BYTE *data, UINT size ) +{ + grow_buffer( buf, size ); + memcpy( buf->ptr + buf->offset, data, size ); + buf->offset += size; +} + +static void build_table_stream( const statement_list_t *stmts ) +{ + add_string( "" ); +} + +static void build_streams( const statement_list_t *stmts ) +{ + static const BYTE pad[4]; + UINT i, len, offset = sizeof(metadata_header); + + build_table_stream( stmts ); + + len = (strings.offset + 3) & ~3; + add_bytes( &strings, pad, len - strings.offset ); + + streams[STREAM_STRING].data_size = strings.offset; + streams[STREAM_STRING].data = strings.ptr; + + for (i = 0; i < STREAM_MAX; i++) + { + if (!streams[i].data_size) continue; + offset += streams[i].header_size; + } + for (i = 0; i < STREAM_MAX; i++) + { + if (!streams[i].data_size) continue; + streams[i].data_offset = offset; + offset += streams[i].data_size; + } +} + static void write_streams( void ) { UINT i; @@ -232,6 +355,8 @@ void write_metadata( const statement_list_t *stmts )
if (!do_metadata) return;
+ build_streams( stmts ); + image_size = FILE_ALIGNMENT + sizeof(cor_header) + 8 + sizeof(metadata_header); for (i = 0; i < STREAM_MAX; i++) image_size += streams[i].header_size + streams[i].data_size;
From: Hans Leidekker hans@codeweavers.com
--- tools/widl/metadata.c | 105 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 5 deletions(-)
diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index c369a15ba09..fbc8d53815c 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -221,7 +221,7 @@ static struct buffer UINT allocated; /* allocated size in bytes */ UINT count; /* number of entries written */ BYTE *ptr; -} strings, strings_idx; +} strings, strings_idx, userstrings, userstrings_idx;
static void *grow_buffer( struct buffer *buf, UINT size ) { @@ -235,6 +235,52 @@ static void *grow_buffer( struct buffer *buf, UINT size ) return buf->ptr; }
+static UINT encode_int( UINT value, BYTE *encoded ) +{ + if (value < 0x80) + { + encoded[0] = value; + return 1; + } + if (value < 0x4000) + { + encoded[0] = value >> 8 | 0x80; + encoded[1] = value & 0xff; + return 2; + } + if (value < 0x20000000) + { + encoded[0] = value >> 24 | 0xc0; + encoded[1] = value >> 16 & 0xff; + encoded[2] = value >> 8 & 0xff; + encoded[3] = value & 0xff; + return 4; + } + fprintf( stderr, "Value too large to encode.\n" ); + exit( 1 ); +} + +static UINT decode_int( const BYTE *encoded, UINT *len ) +{ + if (!(encoded[0] & 0x80)) + { + *len = 1; + return encoded[0]; + } + if (!(encoded[0] & 0x40)) + { + *len = 2; + return ((encoded[0] & ~0xc0) << 8) + encoded[1]; + } + if (!(encoded[0] & 0x20)) + { + *len = 4; + return ((encoded[0] & ~0xe0) << 24) + (encoded[1] << 16) + (encoded[2] << 8) + encoded[3]; + } + fprintf( stderr, "Invalid encoding.\n" ); + exit( 1 ); +} + struct index { UINT offset; /* offset into corresponding data buffer */ @@ -250,17 +296,21 @@ static inline int cmp_data( const BYTE *data, UINT size, const BYTE *data2, UINT
/* return index struct if found, NULL and insert index if not found */ static const struct index *find_index( const struct buffer *buf_idx, const struct buffer *buf_data, const BYTE *data, - UINT size, UINT *insert_idx ) + UINT data_size, BOOL is_blob, UINT *insert_idx ) { - int i, c, min = 0, max = buf_idx->count - 1, len = 0; + int i, c, min = 0, max = buf_idx->count - 1; const struct index *idx, *base = (const struct index *)buf_idx->ptr; + UINT size, len = 0;
while (min <= max) { i = (min + max) / 2; idx = &base[i];
- c = cmp_data( data, size, buf_data->ptr + idx->offset + len, idx->size ); + if (is_blob) size = decode_int( buf_data->ptr + idx->offset, &len ); + else size = idx->size; + + c = cmp_data( data, data_size, buf_data->ptr + idx->offset + len, size );
if (c < 0) max = i - 1; else if (c > 0) min = i + 1; @@ -288,7 +338,7 @@ static UINT add_string( const char *str )
if (!str) return 0; size = strlen( str ) + 1; - if ((idx = find_index( &strings_idx, &strings, (const BYTE *)str, size, &insert_idx ))) + if ((idx = find_index( &strings_idx, &strings, (const BYTE *)str, size, FALSE, &insert_idx ))) return idx->offset;
grow_buffer( &strings, size ); @@ -300,6 +350,41 @@ static UINT add_string( const char *str ) return offset; }
+static inline int is_special_char( USHORT c ) +{ + return (c >= 0x100 || (c >= 0x01 && c <= 0x08) || (c >= 0x0e && c <= 0x1f) || c == 0x27 || c == 0x2d || c == 0x7f); +} + +static UINT add_userstring( const USHORT *str, UINT size ) +{ + BYTE encoded[4], terminal = 0; + UINT i, insert_idx, offset = userstrings.offset, len = encode_int( size + (str ? 1 : 0), encoded ); + const struct index *idx; + + if (!str && offset) return 0; + + if ((idx = find_index( &userstrings_idx, &userstrings, (const BYTE *)str, size, TRUE, &insert_idx ))) + return idx->offset; + + grow_buffer( &userstrings, len + size + 1 ); + memcpy( userstrings.ptr + userstrings.offset, encoded, len ); + userstrings.offset += len; + if (str) + { + for (i = 0; i < size / sizeof(USHORT); i++) + { + *(USHORT *)(userstrings.ptr + userstrings.offset) = str[i]; + userstrings.offset += sizeof(USHORT); + if (is_special_char( str[i] )) terminal = 1; + } + userstrings.ptr[userstrings.offset++] = terminal; + } + userstrings.count++; + + insert_index( &userstrings_idx, insert_idx, offset, size ); + return offset; +} + static void add_bytes( struct buffer *buf, const BYTE *data, UINT size ) { grow_buffer( buf, size ); @@ -309,7 +394,11 @@ static void add_bytes( struct buffer *buf, const BYTE *data, UINT size )
static void build_table_stream( const statement_list_t *stmts ) { + static const USHORT space = 0x20; + add_string( "" ); + add_userstring( NULL, 0 ); + add_userstring( &space, sizeof(space) ); }
static void build_streams( const statement_list_t *stmts ) @@ -325,6 +414,12 @@ static void build_streams( const statement_list_t *stmts ) streams[STREAM_STRING].data_size = strings.offset; streams[STREAM_STRING].data = strings.ptr;
+ len = (userstrings.offset + 3) & ~3; + add_bytes( &userstrings, pad, len - userstrings.offset ); + + streams[STREAM_USERSTRING].data_size = userstrings.offset; + streams[STREAM_USERSTRING].data = userstrings.ptr; + for (i = 0; i < STREAM_MAX; i++) { if (!streams[i].data_size) continue;
From: Hans Leidekker hans@codeweavers.com
--- tools/widl/metadata.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index fbc8d53815c..f090c01fc57 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -221,7 +221,7 @@ static struct buffer UINT allocated; /* allocated size in bytes */ UINT count; /* number of entries written */ BYTE *ptr; -} strings, strings_idx, userstrings, userstrings_idx; +} strings, strings_idx, userstrings, userstrings_idx, blobs, blobs_idx;
static void *grow_buffer( struct buffer *buf, UINT size ) { @@ -385,6 +385,29 @@ static UINT add_userstring( const USHORT *str, UINT size ) return offset; }
+static UINT add_blob( const BYTE *blob, UINT size ) +{ + BYTE encoded[4]; + UINT insert_idx, offset = blobs.offset, len = encode_int( size, encoded ); + const struct index *idx; + + if (!blob && offset) return 0; + if ((idx = find_index( &blobs_idx, &blobs, blob, size, TRUE, &insert_idx ))) return idx->offset; + + grow_buffer( &blobs, len + size ); + memcpy( blobs.ptr + blobs.offset, encoded, len ); + blobs.offset += len; + if (blob) + { + memcpy( blobs.ptr + blobs.offset, blob, size ); + blobs.offset += size; + } + blobs.count++; + + insert_index( &blobs_idx, insert_idx, offset, size ); + return offset; +} + static void add_bytes( struct buffer *buf, const BYTE *data, UINT size ) { grow_buffer( buf, size ); @@ -399,6 +422,7 @@ static void build_table_stream( const statement_list_t *stmts ) add_string( "" ); add_userstring( NULL, 0 ); add_userstring( &space, sizeof(space) ); + add_blob( NULL, 0 ); }
static void build_streams( const statement_list_t *stmts ) @@ -420,6 +444,12 @@ static void build_streams( const statement_list_t *stmts ) streams[STREAM_USERSTRING].data_size = userstrings.offset; streams[STREAM_USERSTRING].data = userstrings.ptr;
+ len = (blobs.offset + 3) & ~3; + add_bytes( &blobs, pad, len - blobs.offset ); + + streams[STREAM_BLOB].data_size = blobs.offset; + streams[STREAM_BLOB].data = blobs.ptr; + for (i = 0; i < STREAM_MAX; i++) { if (!streams[i].data_size) continue;
From: Hans Leidekker hans@codeweavers.com
--- tools/widl/metadata.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/tools/widl/metadata.c b/tools/widl/metadata.c index f090c01fc57..e60af138f5a 100644 --- a/tools/widl/metadata.c +++ b/tools/widl/metadata.c @@ -221,7 +221,7 @@ static struct buffer UINT allocated; /* allocated size in bytes */ UINT count; /* number of entries written */ BYTE *ptr; -} strings, strings_idx, userstrings, userstrings_idx, blobs, blobs_idx; +} strings, strings_idx, userstrings, userstrings_idx, blobs, blobs_idx, guids;
static void *grow_buffer( struct buffer *buf, UINT size ) { @@ -408,6 +408,14 @@ static UINT add_blob( const BYTE *blob, UINT size ) return offset; }
+static UINT add_guid( const GUID *guid ) +{ + grow_buffer( &guids, sizeof(*guid) ); + memcpy( guids.ptr + guids.offset, guid, sizeof(*guid) ); + guids.offset += sizeof(*guid); + return ++guids.count; +} + static void add_bytes( struct buffer *buf, const BYTE *data, UINT size ) { grow_buffer( buf, size ); @@ -417,12 +425,14 @@ static void add_bytes( struct buffer *buf, const BYTE *data, UINT size )
static void build_table_stream( const statement_list_t *stmts ) { + static const GUID guid = { 0x9ddc04c6, 0x04ca, 0x04cc, { 0x52, 0x85, 0x4b, 0x50, 0xb2, 0x60, 0x1d, 0xa8 } }; static const USHORT space = 0x20;
add_string( "" ); add_userstring( NULL, 0 ); add_userstring( &space, sizeof(space) ); add_blob( NULL, 0 ); + add_guid( &guid ); }
static void build_streams( const statement_list_t *stmts ) @@ -450,6 +460,9 @@ static void build_streams( const statement_list_t *stmts ) streams[STREAM_BLOB].data_size = blobs.offset; streams[STREAM_BLOB].data = blobs.ptr;
+ streams[STREAM_GUID].data_size = guids.offset; + streams[STREAM_GUID].data = guids.ptr; + for (i = 0; i < STREAM_MAX; i++) { if (!streams[i].data_size) continue;
v3: Use put_data() and fix blob search.
This merge request was approved by Rémi Bernon.
This merge request was approved by Huw Davies.
Alexandre Julliard (@julliard) commented about tools/widl/metadata.c:
+};
+static IMAGE_SECTION_HEADER section_header = +{
- .Name = ".text",
- { .VirtualSize = 0 },
- .VirtualAddress = 0,
- .SizeOfRawData = 0,
- .PointerToRawData = 0,
- .PointerToRelocations = 0,
- .PointerToLinenumbers = 0,
- .NumberOfRelocations = 0,
- .NumberOfLinenumbers = 0,
- .Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ
+};
If you are going to use designated initializers, it doesn't seem necessary to list all the zero fields. Particularly for `.DataDirectory`, it would be a lot more readable as `[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] = { ... }`.