Exemple #1
0
static void output_bin_data( lan_blk_t *lbp )
{
    unsigned int offs = 4 * (lbp->nblk * 3 + 1);
    int i, j, k;

    put_dword( lbp->nblk );  /* NBlocks */
    for (i = 0; i < lbp->nblk; i++)
    {
        put_dword( lbp->blks[i].idlo );  /* Lo */
        put_dword( lbp->blks[i].idhi );  /* Hi */
        put_dword( offs );               /* Offs */
        offs += lbp->blks[i].size;
    }
    for (i = 0; i < lbp->nblk; i++)
    {
        block_t *blk = &lbp->blks[i];
        for (j = 0; j < blk->nmsg; j++)
        {
            int len = (2 * blk->msgs[j]->len + 3) & ~3;
            put_word( len + 4 );
            put_word( 1 );
            for (k = 0; k < blk->msgs[j]->len; k++) put_word( blk->msgs[j]->msg[k] );
            align_output( 4 );
        }
    }
}
Exemple #2
0
void write_res_file( const char *name )
{
    lan_blk_t *lbp;
    int i, j;

    init_output_buffer();

    put_dword( 0 );      /* ResSize */
    put_dword( 32 );     /* HeaderSize */
    put_word( 0xffff );  /* ResType */
    put_word( 0x0000 );
    put_word( 0xffff );  /* ResName */
    put_word( 0x0000 );
    put_dword( 0 );      /* DataVersion */
    put_word( 0 );       /* Memory options */
    put_word( 0 );       /* Language */
    put_dword( 0 );      /* Version */
    put_dword( 0 );      /* Characteristics */

    for (lbp = lanblockhead; lbp; lbp = lbp->next)
    {
        unsigned int data_size = 4 * (lbp->nblk * 3 + 1);
        unsigned int header_size = 5 * sizeof(unsigned int) + 6 * sizeof(unsigned short);

        for (i = 0; i < lbp->nblk; i++)
        {
            block_t *blk = &lbp->blks[i];
            for (j = 0; j < blk->nmsg; j++) data_size += 4 + ((blk->msgs[j]->len * 2 + 3) & ~3);
        }

        put_dword( data_size );     /* ResSize */
        put_dword( header_size );   /* HeaderSize */
        put_word( 0xffff );         /* ResType */
        put_word( 0x000b /*RT_MESSAGETABLE*/ );
        put_word( 0xffff );         /* ResName */
        put_word( 0x0001 );
        align_output( 4 );
        put_dword( 0 );             /* DataVersion */
        put_word( 0x30 );           /* Memory options */
        put_word( lbp->lan );       /* Language */
        put_dword( lbp->version );  /* Version */
        put_dword( 0 );             /* Characteristics */

        output_bin_data( lbp );
    }
    flush_output_buffer( name );
}
Exemple #3
0
/* output the resources into a .o file */
void output_res_o_file( DLLSPEC *spec )
{
    unsigned int i;
    char *res_file = NULL;
    int fd, err;

    if (!spec->nb_resources) fatal_error( "--resources mode needs at least one resource file as input\n" );
    if (!output_file_name) fatal_error( "No output file name specified\n" );

    byte_swapped = 0;
    init_output_buffer();

    put_dword( 0 );      /* ResSize */
    put_dword( 32 );     /* HeaderSize */
    put_word( 0xffff );  /* ResType */
    put_word( 0x0000 );
    put_word( 0xffff );  /* ResName */
    put_word( 0x0000 );
    put_dword( 0 );      /* DataVersion */
    put_word( 0 );       /* Memory options */
    put_word( 0 );       /* Language */
    put_dword( 0 );      /* Version */
    put_dword( 0 );      /* Characteristics */

    for (i = 0; i < spec->nb_resources; i++)
    {
        unsigned int header_size = get_resource_header_size( &spec->resources[i] );

        put_dword( spec->resources[i].data_size );
        put_dword( (header_size + 3) & ~3 );
        put_string( &spec->resources[i].type );
        put_string( &spec->resources[i].name );
        align_output( 4 );
        put_dword( 0 );
        put_word( spec->resources[i].mem_options );
        put_word( spec->resources[i].lang );
        put_dword( 0 );
        put_dword( 0 );
        put_data( spec->resources[i].data, spec->resources[i].data_size );
        align_output( 4 );
    }

    /* if the output file name is a .res too, don't run the results through windres */
    if (strendswith( output_file_name, ".res"))
    {
        flush_output_buffer();
        return;
    }

    res_file = get_temp_file_name( output_file_name, ".res" );
    if ((fd = open( res_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600 )) == -1)
        fatal_error( "Cannot create %s\n", res_file );
    if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
        fatal_error( "Error writing to %s\n", res_file );
    close( fd );
    free( output_buffer );

    if (res_file)
    {
        char *prog = find_tool( "windres", NULL );
        char *cmd = xmalloc( strlen(prog) + strlen(res_file) + strlen(output_file_name) + 9 );
        sprintf( cmd, "%s -i %s -o %s", prog, res_file, output_file_name );
        if (verbose) fprintf( stderr, "%s\n", cmd );
        err = system( cmd );
        if (err) fatal_error( "%s failed with status %d\n", prog, err );
        free( cmd );
        free( prog );
    }
    output_file_name = NULL;  /* so we don't try to assemble it */
}
Exemple #4
0
/* output the resource definitions in binary format */
void output_bin_resources( DLLSPEC *spec, unsigned int start_rva )
{
    int k, nb_id_types;
    unsigned int i, n, data_offset;
    struct res_tree *tree;
    struct res_type *type;
    struct res_name *name;
    const struct resource *res;

    if (!spec->nb_resources) return;

    tree = build_resource_tree( spec, &data_offset );
    init_output_buffer();

    /* output the resource directories */

    for (i = nb_id_types = 0, type = tree->types; i < tree->nb_types; i++, type++)
        if (!type->type->str) nb_id_types++;

    output_bin_res_dir( tree->nb_types - nb_id_types, nb_id_types );

    /* dump the type directory */

    for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
    {
        put_dword( type->name_offset );
        put_dword( type->dir_offset | 0x80000000 );
    }

    /* dump the names and languages directories */

    for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
    {
        output_bin_res_dir( type->nb_names - type->nb_id_names, type->nb_id_names );
        for (n = 0, name = type->names; n < type->nb_names; n++, name++)
        {
            put_dword( name->name_offset );
            put_dword( name->dir_offset | 0x80000000 );
        }

        for (n = 0, name = type->names; n < type->nb_names; n++, name++)
        {
            output_bin_res_dir( 0, name->nb_languages );
            for (k = 0, res = name->res; k < name->nb_languages; k++, res++)
            {
                put_dword( res->lang );
                put_dword( res->data_offset );
            }
        }
    }

    /* dump the resource data entries */

    for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
    {
        put_dword( data_offset + start_rva );
        put_dword( (res->data_size + 3) & ~3 );
        put_dword( 0 );
        put_dword( 0 );
        data_offset += (res->data_size + 3) & ~3;
    }

    /* dump the name strings */

    for (i = 0, type = tree->types; i < tree->nb_types; i++, type++)
    {
        if (type->type->str) output_bin_string( type->type->str );
        for (n = 0, name = type->names; n < type->nb_names; n++, name++)
            if (name->name->str) output_bin_string( name->name->str );
    }

    /* resource data */

    align_output( 4 );
    for (i = 0, res = spec->resources; i < spec->nb_resources; i++, res++)
    {
        put_data( res->data, res->data_size );
        align_output( 4 );
    }

    free_resource_tree( tree );
}
Exemple #5
0
/*******************************************************************
 *         output_fake_module
 *
 * Build a fake binary module from a spec file.
 */
void output_fake_module( DLLSPEC *spec )
{
    static const unsigned char dll_code_section[] = { 0x31, 0xc0,          /* xor %eax,%eax */
                                                      0xc2, 0x0c, 0x00 };  /* ret $12 */

    static const unsigned char exe_code_section[] = { 0xb8, 0x01, 0x00, 0x00, 0x00,  /* movl $1,%eax */
                                                      0xc2, 0x04, 0x00 };            /* ret $4 */

    static const char fakedll_signature[] = "Wine placeholder DLL";
    const unsigned int page_size = get_page_size();
    const unsigned int section_align = page_size;
    const unsigned int file_align = 0x200;
    const unsigned int reloc_size = 8;
    const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
    const unsigned int nb_sections = 2 + (spec->nb_resources != 0);
    const unsigned int text_size = (spec->characteristics & IMAGE_FILE_DLL) ?
                                    sizeof(dll_code_section) : sizeof(exe_code_section);
    unsigned char *resources;
    unsigned int resources_size;
    unsigned int image_size = 3 * section_align;

    resolve_imports( spec );
    output_bin_resources( spec, 3 * section_align );
    resources = output_buffer;
    resources_size = output_buffer_pos;
    if (resources_size) image_size += (resources_size + section_align - 1) & ~(section_align - 1);

    init_output_buffer();

    put_word( 0x5a4d );       /* e_magic */
    put_word( 0x40 );         /* e_cblp */
    put_word( 0x01 );         /* e_cp */
    put_word( 0 );            /* e_crlc */
    put_word( lfanew / 16 );  /* e_cparhdr */
    put_word( 0x0000 );       /* e_minalloc */
    put_word( 0xffff );       /* e_maxalloc */
    put_word( 0x0000 );       /* e_ss */
    put_word( 0x00b8 );       /* e_sp */
    put_word( 0 );            /* e_csum */
    put_word( 0 );            /* e_ip */
    put_word( 0 );            /* e_cs */
    put_word( lfanew );       /* e_lfarlc */
    put_word( 0 );            /* e_ovno */
    put_dword( 0 );           /* e_res */
    put_dword( 0 );
    put_word( 0 );            /* e_oemid */
    put_word( 0 );            /* e_oeminfo */
    put_dword( 0 );           /* e_res2 */
    put_dword( 0 );
    put_dword( 0 );
    put_dword( 0 );
    put_dword( 0 );
    put_dword( lfanew );

    put_data( fakedll_signature, sizeof(fakedll_signature) );
    align_output( 16 );

    put_dword( 0x4550 );                             /* Signature */
    switch(target_cpu)
    {
    case CPU_x86:     put_word( IMAGE_FILE_MACHINE_I386 ); break;
    case CPU_x86_64:  put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
    case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
    case CPU_SPARC:   put_word( IMAGE_FILE_MACHINE_SPARC ); break;
    case CPU_ARM:     put_word( IMAGE_FILE_MACHINE_ARMV7 ); break;
    }
    put_word( nb_sections );                         /* NumberOfSections */
    put_dword( 0 );                                  /* TimeDateStamp */
    put_dword( 0 );                                  /* PointerToSymbolTable */
    put_dword( 0 );                                  /* NumberOfSymbols */
    put_word( get_ptr_size() == 8 ?
              IMAGE_SIZEOF_NT_OPTIONAL64_HEADER :
              IMAGE_SIZEOF_NT_OPTIONAL32_HEADER );   /* SizeOfOptionalHeader */
    put_word( spec->characteristics );               /* Characteristics */
    put_word( get_ptr_size() == 8 ?
              IMAGE_NT_OPTIONAL_HDR64_MAGIC :
              IMAGE_NT_OPTIONAL_HDR32_MAGIC );       /* Magic */
    put_byte(  0 );                                  /* MajorLinkerVersion */
    put_byte(  0 );                                  /* MinorLinkerVersion */
    put_dword( text_size );                          /* SizeOfCode */
    put_dword( 0 );                                  /* SizeOfInitializedData */
    put_dword( 0 );                                  /* SizeOfUninitializedData */
    put_dword( section_align );                      /* AddressOfEntryPoint */
    put_dword( section_align );                      /* BaseOfCode */
    if (get_ptr_size() == 4) put_dword( 0 );         /* BaseOfData */
    put_pword( 0x10000000 );                         /* ImageBase */
    put_dword( section_align );                      /* SectionAlignment */
    put_dword( file_align );                         /* FileAlignment */
    put_word( 1 );                                   /* MajorOperatingSystemVersion */
    put_word( 0 );                                   /* MinorOperatingSystemVersion */
    put_word( 0 );                                   /* MajorImageVersion */
    put_word( 0 );                                   /* MinorImageVersion */
    put_word( spec->subsystem_major );               /* MajorSubsystemVersion */
    put_word( spec->subsystem_minor );               /* MinorSubsystemVersion */
    put_dword( 0 );                                  /* Win32VersionValue */
    put_dword( image_size );                         /* SizeOfImage */
    put_dword( file_align );                         /* SizeOfHeaders */
    put_dword( 0 );                                  /* CheckSum */
    put_word( spec->subsystem );                     /* Subsystem */
    put_word( spec->dll_characteristics );           /* DllCharacteristics */
    put_pword( (spec->stack_size ? spec->stack_size : 1024) * 1024 ); /* SizeOfStackReserve */
    put_pword( page_size );                          /* SizeOfStackCommit */
    put_pword( (spec->heap_size ? spec->heap_size : 1024) * 1024 );   /* SizeOfHeapReserve */
    put_pword( page_size );                          /* SizeOfHeapCommit */
    put_dword( 0 );                                  /* LoaderFlags */
    put_dword( 16 );                                 /* NumberOfRvaAndSizes */

    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT] */
    if (resources_size)   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE] */
    {
        put_dword( 3 * section_align );
        put_dword( resources_size );
    }
    else
    {
        put_dword( 0 );
        put_dword( 0 );
    }

    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY] */
    put_dword( 2 * section_align );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC] */
    put_dword( reloc_size );
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_GLOBALPTR] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR] */
    put_dword( 0 ); put_dword( 0 );   /* DataDirectory[15] */

    /* .text section */
    put_data( ".text\0\0", 8 );    /* Name */
    put_dword( section_align );    /* VirtualSize */
    put_dword( section_align );    /* VirtualAddress */
    put_dword( text_size );        /* SizeOfRawData */
    put_dword( file_align );       /* PointerToRawData */
    put_dword( 0 );                /* PointerToRelocations */
    put_dword( 0 );                /* PointerToLinenumbers */
    put_word( 0 );                 /* NumberOfRelocations */
    put_word( 0 );                 /* NumberOfLinenumbers */
    put_dword( 0x60000020 /* CNT_CODE|MEM_EXECUTE|MEM_READ */ ); /* Characteristics  */

    /* .reloc section */
    put_data( ".reloc\0", 8 );     /* Name */
    put_dword( section_align );    /* VirtualSize */
    put_dword( 2 * section_align );/* VirtualAddress */
    put_dword( reloc_size );       /* SizeOfRawData */
    put_dword( 2 * file_align );   /* PointerToRawData */
    put_dword( 0 );                /* PointerToRelocations */
    put_dword( 0 );                /* PointerToLinenumbers */
    put_word( 0 );                 /* NumberOfRelocations */
    put_word( 0 );                 /* NumberOfLinenumbers */
    put_dword( 0x42000040 /* CNT_INITIALIZED_DATA|MEM_DISCARDABLE|MEM_READ */ ); /* Characteristics */

    /* .rsrc section */
    if (resources_size)
    {
        put_data( ".rsrc\0\0", 8 );    /* Name */
        put_dword( (resources_size + section_align - 1) & ~(section_align - 1) ); /* VirtualSize */
        put_dword( 3 * section_align );/* VirtualAddress */
        put_dword( resources_size );   /* SizeOfRawData */
        put_dword( 3 * file_align );   /* PointerToRawData */
        put_dword( 0 );                /* PointerToRelocations */
        put_dword( 0 );                /* PointerToLinenumbers */
        put_word( 0 );                 /* NumberOfRelocations */
        put_word( 0 );                 /* NumberOfLinenumbers */
        put_dword( 0x40000040 /* CNT_INITIALIZED_DATA|MEM_READ */ ); /* Characteristics */
    }

    /* .text contents */
    align_output( file_align );
    if (spec->characteristics & IMAGE_FILE_DLL)
        put_data( dll_code_section, sizeof(dll_code_section) );
    else
        put_data( exe_code_section, sizeof(exe_code_section) );

    /* .reloc contents */
    align_output( file_align );
    put_dword( 0 );   /* VirtualAddress */
    put_dword( 0 );   /* SizeOfBlock */

    /* .rsrc contents */
    if (resources_size)
    {
        align_output( file_align );
        put_data( resources, resources_size );
    }
    flush_output_buffer();
}
Exemple #6
0
/*******************************************************************
 *         output_fake_module16
 *
 * Create a fake 16-bit binary module.
 */
void output_fake_module16( DLLSPEC *spec )
{
    static const unsigned char code_segment[] = { 0x90, 0xc3 };
    static const unsigned char data_segment[16] = { 0 };
    static const char fakedll_signature[] = "Wine placeholder DLL";
    const unsigned int cseg = 2;
    const unsigned int lfanew = (0x40 + sizeof(fakedll_signature) + 15) & ~15;
    const unsigned int segtab = lfanew + 0x40;

    unsigned int i, rsrctab, restab, namelen, modtab, imptab, enttab, cbenttab, codeseg, dataseg, rsrcdata;

    init_output_buffer();

    rsrctab = lfanew;
    restab = segtab + 8 * cseg;
    if (spec->nb_resources)
    {
        output_bin_res16_directory( spec, 0 );
        align_output( 2 );
        rsrctab = restab;
        restab += output_buffer_pos;
        free( output_buffer );
        init_output_buffer();
    }

    namelen  = strlen( spec->dll_name );
    modtab   = restab + ((namelen + 3) & ~1);
    imptab   = modtab;
    enttab   = modtab + 2;
    cbenttab = 1;
    codeseg  = (enttab + cbenttab + 1) & ~1;
    dataseg  = codeseg + sizeof(code_segment);
    rsrcdata = dataseg + sizeof(data_segment);

    init_output_buffer();

    put_word( 0x5a4d );       /* e_magic */
    put_word( 0x40 );         /* e_cblp */
    put_word( 0x01 );         /* e_cp */
    put_word( 0 );            /* e_crlc */
    put_word( lfanew / 16 );  /* e_cparhdr */
    put_word( 0x0000 );       /* e_minalloc */
    put_word( 0xffff );       /* e_maxalloc */
    put_word( 0x0000 );       /* e_ss */
    put_word( 0x00b8 );       /* e_sp */
    put_word( 0 );            /* e_csum */
    put_word( 0 );            /* e_ip */
    put_word( 0 );            /* e_cs */
    put_word( lfanew );       /* e_lfarlc */
    put_word( 0 );            /* e_ovno */
    put_dword( 0 );           /* e_res */
    put_dword( 0 );
    put_word( 0 );            /* e_oemid */
    put_word( 0 );            /* e_oeminfo */
    put_dword( 0 );           /* e_res2 */
    put_dword( 0 );
    put_dword( 0 );
    put_dword( 0 );
    put_dword( 0 );
    put_dword( lfanew );

    put_data( fakedll_signature, sizeof(fakedll_signature) );
    align_output( 16 );

    put_word( 0x454e );                    /* ne_magic */
    put_byte( 0 );                         /* ne_ver */
    put_byte( 0 );                         /* ne_rev */
    put_word( enttab - lfanew );           /* ne_enttab */
    put_word( cbenttab );                  /* ne_cbenttab */
    put_dword( 0 );                        /* ne_crc */
    put_word( NE_FFLAGS_SINGLEDATA |       /* ne_flags */
              ((spec->characteristics & IMAGE_FILE_DLL) ? NE_FFLAGS_LIBMODULE : 0) );
    put_word( 2 );                         /* ne_autodata */
    put_word( spec->heap_size );           /* ne_heap */
    put_word( 0 );                         /* ne_stack */
    put_word( 0 ); put_word( 0 );          /* ne_csip */
    put_word( 0 ); put_word( 2 );          /* ne_sssp */
    put_word( cseg );                      /* ne_cseg */
    put_word( 0 );                         /* ne_cmod */
    put_word( 0 );                         /* ne_cbnrestab */
    put_word( segtab - lfanew );           /* ne_segtab */
    put_word( rsrctab - lfanew );          /* ne_rsrctab */
    put_word( restab - lfanew );           /* ne_restab */
    put_word( modtab - lfanew );           /* ne_modtab */
    put_word( imptab - lfanew );           /* ne_imptab */
    put_dword( 0 );                        /* ne_nrestab */
    put_word( 0 );                         /* ne_cmovent */
    put_word( 0 );                         /* ne_align */
    put_word( 0 );                         /* ne_cres */
    put_byte( 2 /*NE_OSFLAGS_WINDOWS*/ );  /* ne_exetyp */
    put_byte( 8 /*NE_AFLAGS_FASTLOAD*/ );  /* ne_flagsothers */
    put_word( 0 );                         /* ne_pretthunks */
    put_word( 0 );                         /* ne_psegrefbytes */
    put_word( 0 );                         /* ne_swaparea */
    put_word( 0 );                         /* ne_expver */

    /* segment table */
    put_word( codeseg );
    put_word( sizeof(code_segment) );
    put_word( 0x2000 /* NE_SEGFLAGS_32BIT */ );
    put_word( sizeof(code_segment) );
    put_word( dataseg );
    put_word( sizeof(data_segment) );
    put_word( 0x0001 /* NE_SEGFLAGS_DATA */ );
    put_word( sizeof(data_segment) );

    /* resource directory */
    if (spec->nb_resources)
    {
        output_bin_res16_directory( spec, rsrcdata );
        align_output( 2 );
    }

    /* resident names table */
    put_byte( namelen );
    for (i = 0; i < namelen; i++) put_byte( toupper(spec->dll_name[i]) );
    put_byte( 0 );
    align_output( 2 );

    /* imported names table */
    put_word( 0 );

    /* entry table */
    put_byte( 0 );
    align_output( 2 );

    /* code segment */
    put_data( code_segment, sizeof(code_segment) );

    /* data segment */
    put_data( data_segment, sizeof(data_segment) );

    /* resource data */
    output_bin_res16_data( spec );

    flush_output_buffer();
}
Exemple #7
0
/* output the resources into a .o file */
void output_res_o_file( DLLSPEC *spec )
{
    unsigned int i;
    char *res_file = NULL;
    int fd;
    struct strarray *args;

    if (!spec->nb_resources) fatal_error( "--resources mode needs at least one resource file as input\n" );
    if (!output_file_name) fatal_error( "No output file name specified\n" );

    qsort( spec->resources, spec->nb_resources, sizeof(*spec->resources), cmp_res );
    remove_duplicate_resources( spec );

    byte_swapped = 0;
    init_output_buffer();

    put_dword( 0 );      /* ResSize */
    put_dword( 32 );     /* HeaderSize */
    put_word( 0xffff );  /* ResType */
    put_word( 0x0000 );
    put_word( 0xffff );  /* ResName */
    put_word( 0x0000 );
    put_dword( 0 );      /* DataVersion */
    put_word( 0 );       /* Memory options */
    put_word( 0 );       /* Language */
    put_dword( 0 );      /* Version */
    put_dword( 0 );      /* Characteristics */

    for (i = 0; i < spec->nb_resources; i++)
    {
        unsigned int header_size = get_resource_header_size( &spec->resources[i] );

        put_dword( spec->resources[i].data_size );
        put_dword( (header_size + 3) & ~3 );
        put_string( &spec->resources[i].type );
        put_string( &spec->resources[i].name );
        align_output( 4 );
        put_dword( 0 );
        put_word( spec->resources[i].mem_options );
        put_word( spec->resources[i].lang );
        put_dword( spec->resources[i].version );
        put_dword( 0 );
        put_data( spec->resources[i].data, spec->resources[i].data_size );
        align_output( 4 );
    }

    /* if the output file name is a .res too, don't run the results through windres */
    if (strendswith( output_file_name, ".res"))
    {
        flush_output_buffer();
        return;
    }

    res_file = get_temp_file_name( output_file_name, ".res" );
    if ((fd = open( res_file, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600 )) == -1)
        fatal_error( "Cannot create %s\n", res_file );
    if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
        fatal_error( "Error writing to %s\n", res_file );
    close( fd );
    free( output_buffer );

    args = find_tool( "windres", NULL );
    strarray_add( args, "-i", res_file, "-o", output_file_name, NULL );
    spawn( args );
    strarray_free( args );

    output_file_name = NULL;  /* so we don't try to assemble it */
}