/*
 * Dumping of LE binaries
 *
 * Copyright 2004 Robert Reif
 *
 * 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 "wine/port.h"

#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include "windef.h"
#include "winbase.h"
#include "winedump.h"

struct o32_obj
{
    unsigned long       o32_size;
    unsigned long       o32_base;
    unsigned long       o32_flags;
    unsigned long       o32_pagemap;
    unsigned long       o32_mapsize;
    char                o32_name[4];
};

struct o32_map
{
    unsigned short      o32_pagedataoffset;
    unsigned char       o32_pagesize;
    unsigned char       o32_pageflags;
};

struct b32_bundle
{
    unsigned char       b32_cnt;
    unsigned char       b32_type;
};

struct vxd_descriptor
{
    unsigned long       next;
    unsigned short      sdk_version;
    unsigned short      device_number;
    unsigned char       version_major;
    unsigned char       version_minor;
    unsigned short      flags;
    char                name[8];
    unsigned long       init_order;
    unsigned long       ctrl_ofs;
    unsigned long       v86_ctrl_ofs;
    unsigned long       pm_ctrl_ofs;
    unsigned long       v86_ctrl_csip;
    unsigned long       pm_ctrl_csip;
    unsigned long       rm_ref_data;
    unsigned long       service_table_ofs;
    unsigned long       service_table_size;
    unsigned long       win32_service_table_ofs;
    unsigned long       prev;
    unsigned long       size;
    unsigned long       reserved0;
    unsigned long       reserved1;
    unsigned long       reserved2;
};

static inline WORD get_word( const BYTE *ptr )
{
    return ptr[0] | (ptr[1] << 8);
}

static void dump_le_header( const IMAGE_VXD_HEADER *le )
{
    printf( "File header:\n" );
    printf( "    Magic:                                %04x (%c%c)\n",
            le->e32_magic, LOBYTE(le->e32_magic), HIBYTE(le->e32_magic));
    printf( "    Byte order:                           %s\n",
            le->e32_border == 0 ? "little-indian" : "big-endian");
    printf( "    Word order:                           %s\n",
            le->e32_worder ==  0 ? "little-indian" : "big-endian");
    printf( "    Executable format level:              %d\n",
            le->e32_level);
    printf( "    CPU type:                             %s\n",
            le->e32_cpu == 0x01 ? "Intel 80286" :
            le->e32_cpu == 0x02 ? "Intel 80386" :
            le->e32_cpu == 0x03 ? "Intel 80486" :
            le->e32_cpu == 0x04 ? "Intel 80586" :
            le->e32_cpu == 0x20 ? "Intel i860 (N10)" :
            le->e32_cpu == 0x21 ? "Intel i860 (N11)" :
            le->e32_cpu == 0x40 ? "MIPS Mark I" :
            le->e32_cpu == 0x41 ? "MIPS Mark II" :
            le->e32_cpu == 0x42 ? "MIPS Mark III" :
            "Unknown");
    printf( "    Target operating system:              %s\n",
            le->e32_os == 0x01 ? "OS/2" :
            le->e32_os == 0x02 ? "Windows" :
            le->e32_os == 0x03 ? "DOS 4.x" :
            le->e32_os == 0x04 ? "Windows 386" :
            "Unknown");
    printf( "    Module version:                       %d\n",
            le->e32_ver);
    printf( "    Module type flags:                    %08x\n",
            le->e32_mflags);
    if (le->e32_mflags & 0x8000)
    {
        if (le->e32_mflags & 0x0004)
            printf( "        Global initialization\n");
        else
            printf( "        Per-Process initialization\n");
        if (le->e32_mflags & 0x0010)
            printf( "        No internal fixup\n");
        if (le->e32_mflags & 0x0020)
            printf( "        No external fixup\n");
        if ((le->e32_mflags & 0x0700) == 0x0100)
            printf( "        Incompatible with PM windowing\n");
        else if ((le->e32_mflags & 0x0700) == 0x0200)
            printf( "        Compatible with PM windowing\n");
        else if ((le->e32_mflags & 0x0700) == 0x0300)
            printf( "        Uses PM windowing API\n");
        if (le->e32_mflags & 0x2000)
            printf( "        Module not loadable\n");
        if (le->e32_mflags & 0x8000)
            printf( "        Module is DLL\n");
    }
    printf( "    Number of memory pages:               %d\n",
            le->e32_mpages);
    printf( "    Initial object CS number:             %08x\n",
            le->e32_startobj);
    printf( "    Initial EIP:                          %08x\n",
            le->e32_eip);
    printf( "    Initial object SS number:             %08x\n",
            le->e32_stackobj);
    printf( "    Initial ESP:                          %08x\n",
            le->e32_esp);
    printf( "    Memory page size:                     %d\n",
            le->e32_pagesize);
    printf( "    Bytes on last page:                   %d\n",
            le->e32_lastpagesize);
    printf( "    Fix-up section size:                  %d\n",
            le->e32_fixupsize);
    printf( "    Fix-up section checksum:              %08x\n",
            le->e32_fixupsum);
    printf( "    Loader section size:                  %d\n",
            le->e32_ldrsize);
    printf( "    Loader section checksum:              %08x\n",
            le->e32_ldrsum);
    printf( "    Offset of object table:               %08x\n",
            le->e32_objtab);
    printf( "    Object table entries:                 %d\n",
            le->e32_objcnt);
    printf( "    Object page map offset:               %08x\n",
            le->e32_objmap);
    printf( "    Object iterate data map offset:       %08x\n",
            le->e32_itermap);
    printf( "    Resource table offset:                %08x\n",
            le->e32_rsrctab);
    printf( "    Resource table entries:               %d\n",
            le->e32_rsrccnt);
    printf( "    Resident names table offset:          %08x\n",
            le->e32_restab);
    printf( "    Entry table offset:                   %08x\n",
            le->e32_enttab);
    printf( "    Module directives table offset:       %08x\n",
            le->e32_dirtab);
    printf( "    Module directives entries:            %d\n",
            le->e32_dircnt);
    printf( "    Fix-up page table offset:             %08x\n",
            le->e32_fpagetab);
    printf( "    Fix-up record table offset:           %08x\n",
            le->e32_frectab);
    printf( "    Imported modules name table offset:   %08x\n",
            le->e32_impmod);
    printf( "    Imported modules count:               %d\n",
            le->e32_impmodcnt);
    printf( "    Imported procedure name table offset: %08x\n",
            le->e32_impproc);
    printf( "    Per-page checksum table offset:       %08x\n",
            le->e32_pagesum);
    printf( "    Data pages offset from top of table:  %08x\n",
            le->e32_datapage);
    printf( "    Preload page count:                   %08x\n",
            le->e32_preload);
    printf( "    Non-resident names table offset:      %08x\n",
            le->e32_nrestab);
    printf( "    Non-resident names table length:      %d\n",
            le->e32_cbnrestab);
    printf( "    Non-resident names table checksum:    %08x\n",
            le->e32_nressum);
    printf( "    Automatic data object:                %08x\n",
            le->e32_autodata);
    printf( "    Debug information offset:             %08x\n",
            le->e32_debuginfo);
    printf( "    Debug information length:             %d\n",
            le->e32_debuglen);
    printf( "    Preload instance pages number:        %d\n",
            le->e32_instpreload);
    printf( "    Demand instance pages number:         %d\n",
            le->e32_instdemand);
    printf( "    Extra heap allocation:                %d\n",
            le->e32_heapsize);
    printf( "    VxD resource table offset:            %08x\n",
            le->e32_winresoff);
    printf( "    Size of VxD resource table:           %d\n",
            le->e32_winreslen);
    printf( "    VxD identifier:                       %x\n",
            le->e32_devid);
    printf( "    VxD DDK version:                      %x\n",
            le->e32_ddkver);
}

static void dump_le_objects( const IMAGE_VXD_HEADER *le )
{
    const struct o32_obj *pobj;
    unsigned int i;

    printf("\nObject table:\n");
    pobj = (const struct o32_obj *)((const unsigned char *)le + le->e32_objtab);
    for (i = 0; i < le->e32_objcnt; i++)
    {
        unsigned int j;
        const struct o32_map *pmap=0;

        printf("    Obj. Rel.Base Codesize Flags    Tableidx Tablesize Name\n");
        printf("    %04X %08lx %08lx %08lx %08lx %08lx  ", i + 1,
               pobj->o32_base, pobj->o32_size, pobj->o32_flags,
               pobj->o32_pagemap, pobj->o32_mapsize);
        for (j = 0; j < 4; j++)
        {
           if  (isprint(pobj->o32_name[j]))
                printf("%c", pobj->o32_name[j]);
           else
                printf(".");
        }
        printf("\n");

        if(pobj->o32_flags & 0x0001)
            printf("\tReadable\n");
        if(pobj->o32_flags & 0x0002)
            printf("\tWritable\n");
        if(pobj->o32_flags & 0x0004)
            printf("\tExecutable\n");
        if(pobj->o32_flags & 0x0008)
            printf("\tResource\n");
        if(pobj->o32_flags & 0x0010)
            printf("\tDiscardable\n");
        if(pobj->o32_flags & 0x0020)
            printf("\tShared\n");
        if(pobj->o32_flags & 0x0040)
            printf("\tPreloaded\n");
        if(pobj->o32_flags & 0x0080)
            printf("\tInvalid\n");
        if(pobj->o32_flags & 0x2000)
            printf("\tUse 32\n");

        printf("    Page tables:\n");
        printf("        Tableidx Offset Flags\n");
        pmap = (const struct o32_map *)((const unsigned char *)le + le->e32_objmap);
        pmap = &(pmap[pobj->o32_pagemap - 1]);
        for (j = 0; j < pobj->o32_mapsize; j++)
        {
            printf("        %08lx %06x %02x\n",
                   pobj->o32_pagemap + j,
                   (pmap->o32_pagedataoffset << 8) + pmap->o32_pagesize,
                   (int)pmap->o32_pageflags);
            pmap++;
        }
        pobj++;
    }
}

static void dump_le_names( const IMAGE_VXD_HEADER *le )
{
    const unsigned char *pstr = (const unsigned char *)le + le->e32_restab;

    printf( "\nResident name table:\n" );
    while (*pstr)
    {
        printf( " %4d: %*.*s\n", get_word(pstr + *pstr + 1), *pstr, *pstr,
                pstr + 1 );
        pstr += *pstr + 1 + sizeof(WORD);
    }
    if (le->e32_cbnrestab)
    {
        printf( "\nNon-resident name table:\n" );
        pstr = PRD(le->e32_nrestab, 0);
        while (*pstr)
        {
            printf( " %4d: %*.*s\n", get_word(pstr + *pstr + 1), *pstr, *pstr,
                    pstr + 1 );
            pstr += *pstr + 1 + sizeof(WORD);
        }
    }
}

static void dump_le_resources( const IMAGE_VXD_HEADER *le )
{
    printf( "\nResources:\n" );
    printf( "    Not Implemented\n" );
}

static void dump_le_modules( const IMAGE_VXD_HEADER *le )
{
    printf( "\nImported modulename table:\n" );
    printf( "    Not Implemented\n" );
}

static void dump_le_entries( const IMAGE_VXD_HEADER *le )
{
    printf( "\nEntry table:\n" );
    printf( "    Not Implemented\n" );
}

static void dump_le_fixups( const IMAGE_VXD_HEADER *le )
{
    printf( "\nFixup table:\n" );
    printf( "    Not Implemented\n" );
}

static void dump_le_VxD( const IMAGE_VXD_HEADER *le )
{
    printf( "\nVxD descriptor:\n" );
    printf( "    Not Implemented\n" );
}

void le_dump( void )
{
    const IMAGE_DOS_HEADER *dos;
    const IMAGE_VXD_HEADER *le;

    dos = PRD(0, sizeof(*dos));
    if (!dos) return;
    le = PRD(dos->e_lfanew, sizeof(*le));

    dump_le_header( le );
    dump_le_objects( le );
    dump_le_resources( le );
    dump_le_names( le );
    dump_le_entries( le );
    dump_le_modules( le );
    dump_le_fixups( le );
    dump_le_VxD( le );
}