/*

    MARK40.C - marks Win32 executable to version 4.0

    Copyright (C) 1995-1996
	Rainer Schnitker, Heeper Str. 283, 33607 Bielefeld
	email: rainer@mathematik.uni-bielefeld.de

    All rights reserved

*/

#include <stdio.h>
#include <fcntl.h>
#include "port.h"
#include "ntbind.h"

static int modify_header(int pehandle, DWORD headoff)
{
    static FILEHDR         file_hdr;
    static NTOPTHDR        ntopt_hdr;

    lseek(pehandle, headoff, SEEK_SET);
    read(pehandle, &file_hdr, sizeof(FILEHDR));

    if (file_hdr.f_magic != 0x14C) {
        puts("no COFF header found");
        return (1);
    }

    read(pehandle, &ntopt_hdr, sizeof(NTOPTHDR));

    if (ntopt_hdr.Magic != 0x10b) {
        puts("no optional header found");
        return (1);
    }

    if (ntopt_hdr.CheckSum) {
        puts("can't handle checksum field != 0");
        return (1);
    }

    if (ntopt_hdr.MajorSubsystemVersion == 0x04) {
        puts("win32 file is already marked 4.0");
        return (1);
    } else
        puts("mark win32 file to 4.0");

    ntopt_hdr.MajorSubsystemVersion = 0x04;
    ntopt_hdr.MinorSubsystemVersion = 0x00;

    lseek(pehandle, headoff + sizeof(FILEHDR), SEEK_SET);
    write(pehandle, &ntopt_hdr, sizeof(NTOPTHDR));

    return 0;
}

static int skip_exe_hdr(int filehandle, DWORD * headoff)
{
    struct exe_hdr exehdr;

    read(filehandle, &exehdr, sizeof(struct exe_hdr));

    if (exehdr.signatur == 0x5a4d) {	/* falls exe-kopf */
        DWORD new_off;

        lseek(filehandle, 0x3C, SEEK_SET);
        read(filehandle, &new_off, sizeof(long));

        if (new_off) {
            DWORD pe_magic;
            lseek(filehandle, new_off, SEEK_SET);
            read(filehandle, &pe_magic, sizeof(pe_magic));
            if (pe_magic == 0x4550) {
                *headoff = new_off + 4;
                return 0;
            }
        }
    }   /* exe files */
    *headoff = 0;
    return -1;
}

int main(int argc, char **argv)
{
    int fhandle;
    DWORD headoff;

    if (argc < 2) {
        puts("mark40 marks win32 subsystem version to 4.0");
        puts("  usage: mark40 file");
        return (1);
    }

    if ((fhandle = open(argv[1], O_RDWR | O_BINARY)) == -1) {
        perror("open");
        return (1);
    }

    if (skip_exe_hdr(fhandle, &headoff) < 0) {
        puts("no a valid Win32 file");
        return (1);
    }

    modify_header(fhandle, headoff);

    close(fhandle);

    return 0;
}
