#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>

struct file {
	int fd;
	int writeable;
	const char* filename;
};

static int apply_patch(int fd, off_t offset, const char* oldcode, const char* newcode, size_t codelen, int update) {
	char buf[4096];
	
	if (lseek(fd, offset, SEEK_SET) != offset) {
		return 20;
	}
	if ((size_t)read(fd, buf, codelen) != codelen) {
		return 21;
	}
	if (!memcmp(buf, newcode, codelen)) {
		return 1;
	}
	if (memcmp(buf, oldcode, codelen)) {
		return 10;
	}
	if (!update) {
		return 0;
	}
	if (lseek(fd, offset, SEEK_SET) != offset) {
		return 30;
	}
	if ((size_t)write(fd, newcode, codelen) != codelen) {
		return 40;
	}
	if (lseek(fd, offset, SEEK_SET) != offset) {
		return 41;
	}
	if ((size_t)read(fd, buf, codelen) != codelen) {
		return 42;
	}
	if (!memcmp(buf, newcode, codelen)) {
		return 0;
	}
	if (memcmp(buf, oldcode, codelen)) {
		return 43;
	}
	return 44;
}

static int trypatch(struct file* f, const char* name, ...) {
	va_list ap;
	off_t offset;
	int items = 0;
	int ret2 = 0;

	va_start(ap, name);
	while ((offset = va_arg(ap, off_t)) != 0) {
		const char* oldcode;
		const char* newcode;
		size_t sizecode;
		int ret;
		
		oldcode = va_arg(ap, const char*);
		newcode = va_arg(ap, const char*);
		sizecode = va_arg(ap, size_t);
		ret = apply_patch(f->fd, offset, oldcode, newcode, sizecode, 0);
		if (ret >= 10) {
			return ret;
		}
		ret2 += ret;
		items++;
	}
	va_end(ap);
	if (ret2 != items) {
		char* temporary;
		int wfd;
		struct stat stb;

		ret2 = 0;
		items = 0;
		if (fstat(f->fd, &stb) == -1) {
			return 35;
		}
		if (!f->writeable) {
			if (asprintf(&temporary, "%s.tmp", f->filename) == -1) {
				return 31;
			}
			wfd = open(temporary, O_RDWR | O_CREAT | O_TRUNC, 0600);
			if (wfd == -1) {
				free(temporary);
				return 32;
			}
			lseek(f->fd, 0, SEEK_SET);
			do {
				char buffer[4096];
				int r;
				
				r = read(f->fd, buffer, sizeof(buffer));
				if (r < 0) {
					close(wfd);
					unlink(temporary);
					free(temporary);
					return 33;
				}
				if (r == 0) {
					break;
				}
				if (write(wfd, buffer, r) != r) {
					close(wfd);
					unlink(temporary);
					free(temporary);
					return 34;
				}
			} while (1);
		} else {
			wfd = f->fd;
			temporary = NULL;
		}
		va_start(ap, name);
		while ((offset = va_arg(ap, off_t)) != 0) {
			const char* oldcode;
			const char* newcode;
			size_t sizecode;
			int ret;
		
			oldcode = va_arg(ap, const char*);
			newcode = va_arg(ap, const char*);
			sizecode = va_arg(ap, size_t);
			ret = apply_patch(wfd, offset, oldcode, newcode, sizecode, 1);
			if (ret >= 10) {
				if (temporary) {
					close(wfd);
					unlink(temporary);
					free(temporary);
				}
				if (ret < 30) {
					return 45;
				}
				return ret;
			}
			ret2 += ret;
			items++;
		}
		va_end(ap);
		if (fchown(wfd, stb.st_uid, stb.st_gid)) {
			if (temporary) {
				close(wfd);
				unlink(temporary);
				free(temporary);
				return 36;
			}
			return 46;
		}
		if (fchmod(wfd, stb.st_mode & 07777)) {
			if (temporary) {
				close(wfd);
				unlink(temporary);
				free(temporary);
				return 37;
			}
			return 47;
		}
		if (temporary) {
			close(wfd);
			if (rename(temporary, f->filename)) {
				free(temporary);
				return 38;
			}
			free(temporary);
		}
		if (ret2 == 0) {
			printf("%s, now patched\n", name);
			return 0;
		}
		if (ret2 < items) {
			printf("%s, was partially patched, now fully patched\n", name);
			return 0;
		}
	}
	printf("%s, already patched\n", name);
	return 0;
}

static int trypatch621(struct file* fd, const char* name) {
	static const char newcodeK25[] = 
"\x83\x3D\x98\x76\x26\x08\x04\x72\x20\x8B\x75\x08\x8B\x56\x0C\xC7\x42\x20\x24\x00\x00\x00";
	static const char oldcodeK25[] = 
"\x83\x3D\x98\x76\x26\x08\x04\x75\x20\x8B\x75\x08\x8B\x56\x0C\xC7\x42\x20\x24\x00\x00\x00";
	static const char newcodeMEM[] = 
"\x53\x83\xEC\x58\xB8\x74\x00\x00\x00\x89\xE3\xCD\x80\x85\xC0\x75"
"\x18\x8B\x4C\x24\x14\x8B\x54\x24\x10\x8B\x44\x24\x34\x83\xF8\x01"
"\x76\x11\x3D\x00\x10\x00\x00\x74\x10\x31\xC9\x31\xC0\xEB\x2E\xDA"
"\x88\x10\x08\xC1\xEA\x0C\xC1\xE9\x0C\x31\xC0\x81\xFA\xFF\x7F\x00"
"\x00\x76\x0C\x81\xC2\xFF\x1F\x00\x00\x81\xE2\x00\xE0\xFF\xFF\x81"
"\xC2\xFF\x07\x00\x00\x81\xE2\x00\xF8\xFF\xFF\x40\xB3\x99\x8B\x5C"
"\x24\x60\x89\x0B\x89\x53\x04\x83\xC4\x58\x5B\xC3";
	static const char oldcodeMEM[] = 
"\x55\x89\xE5\x83\xEC\x0C\x57\x56\x53\x81\xC4\x18\xFC\xFF\xFF\x89"
"\xE7\x89\xE3\x8B\x55\x08\xC7\x02\x80\x00\x00\x00\xC7\x42\x04\x00"
"\x00\x00\x00\xC7\x42\x08\x00\x00\x00\x00\x6A\x00\x68\x90\xB3\x1C"
"\x08\xE8\x06\xDB\xFF\xFF\x89\xC6\x83\xC4\x08\x83\xFE\xFF\x74\x76"
"\x68\xE7\x03\x00\x00\x57\x56\xE8\xA0\xCB\xFF\xFF\x83\xC4\x0C\x83"
"\xF8\xFF\x74\x5C\xC6\x04\x38\x00\xEB\x07\x89\xF6\x80\x3B\x00\x74"
"\x07\x8A\x03\x43\x3C\x0A\x75\xF4\x8D\x45\xF4\x50";
	static const char newcodeNICE[] =
"\xE8\xCA\x77\xFF\xFF\x31\xF6\x83\xC4\x08";
	static const char oldcodeNICE[] =
"\xE8\xCA\x77\xFF\xFF\x89\xC6\x83\xC4\x08";
	return trypatch(fd, name, (off_t)0x8EAD7, oldcodeK25,  newcodeK25,  sizeof(newcodeK25) - 1,
				  (off_t)0x0BE80, oldcodeMEM,  newcodeMEM,  sizeof(newcodeMEM) - 1,
				  (off_t)0x119AD, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0);
}

static int trypatch1133(struct file* fd, const char* name) {
	static const char newcodeMEM[] = 
"\x53\x83\xEC\x58\xB8\x74\x00\x00\x00\x89\xE3\xCD\x80\x85\xC0\x75"
"\x18\x8B\x4C\x24\x14\x8B\x54\x24\x10\x8B\x44\x24\x34\x83\xF8\x01"
"\x76\x11\x3D\x00\x10\x00\x00\x74\x10\x31\xC9\x31\xC0\xEB\x2E\xDA"
"\x88\x10\x08\xC1\xEA\x0C\xC1\xE9\x0C\x31\xC0\x81\xFA\xFF\x7F\x00"
"\x00\x76\x0C\x81\xC2\xFF\x1F\x00\x00\x81\xE2\x00\xE0\xFF\xFF\x81"
"\xC2\xFF\x07\x00\x00\x81\xE2\x00\xF8\xFF\xFF\x40\xB3\x99\x8B\x5C"
"\x24\x60\x89\x0B\x89\x53\x04\x83\xC4\x58\x5B\xC3";
	static const char oldcodeMEM[] = 
"\x55\x89\xE5\x83\xEC\x0C\x57\x56\x53\x81\xC4\x18\xFC\xFF\xFF\x89"
"\xE7\x89\xE3\x8B\x55\x08\xC7\x02\x80\x00\x00\x00\xC7\x42\x04\x00"
"\x00\x00\x00\xC7\x42\x08\x00\x00\x00\x00\x6A\x00\x68\xB4\xB5\x1C"
"\x08\xE8\x5E\xDA\xFF\xFF\x89\xC6\x83\xC4\x08\x83\xFE\xFF\x74\x76"
"\x68\xE7\x03\x00\x00\x57\x56\xE8\xF8\xCA\xFF\xFF\x83\xC4\x0C\x83"
"\xF8\xFF\x74\x5C\xC6\x04\x38\x00\xEB\x07\x89\xF6\x80\x3B\x00\x74"
"\x07\x8A\x03\x43\x3C\x0A\x75\xF4\x8D\x45\xF4\x50";
	static const char newcodeNICE[] =
"\xE8\xEE\x76\xFF\xFF\x31\xF6\x83\xC4\x08";
	static const char oldcodeNICE[] =
"\xE8\xEE\x76\xFF\xFF\x89\xC6\x83\xC4\x08";
	static const char newcodeNICE2[] =
"\xE8\x3B\x75\xFF\xFF\x31\xDB\x83\xC4\x04";
	static const char oldcodeNICE2[] =
"\xE8\x3B\x75\xFF\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeNICE3[] =
"\xE8\xD5\x74\xFF\xFF\x31\xDB\x83\xC4\x04";
	static const char oldcodeNICE3[] =
"\xE8\xD5\x74\xFF\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeK25[] =
"\x90\x90\x90\x90\x90\x33\xD2\x83\xC4\x04\x8B\x35"
"\xE0\x82\x26\x08\x83\xFE\x02\x72\x49\x75\x22\x8B\x35\xE4\x82\x26\x08\x0B\xF6\x90\x8B\x3D\xE8\x82"
"\x26\x08\x75\x1A\x83\xFF\x1D\x7E\x31\xB2\x20\xEB\x2D\x90\x90\x90\x3D\xE4\x82\x26\x08\xB2\x24\xEB"
"\x15\x3D\xE8\x82\x26\x08\x4E\x75\x09\x83\xFF\x7A\x7E\x14\xB2\x21\xEB\x04\xB2\x22\xEB\x20\x80\x3D"
"\xDC\x82\x26\x08\x00\x74\x03\x80\xCE\x10\x8B\x75\x08\x8B\x76\x0C\xEB\x05\x3D\xE4\x82\x26\x08\x89"
"\x56\x20\x0B\xD2\xEB\x7D\x4E\x74\xDD\x42\x4E\x74\xD9\xEB\xBE";
	static const char oldcodeK25[] =
"\xC7\x42\x20\x00\x00\x00\x00\x83\xC4\x04\x83\x3D"
"\xE0\x82\x26\x08\x02\x0F\x85\xCE\x00\x00\x00\x83\x3D\xE4\x82\x26\x08\x00\x75\x13\x83\x3D\xE8\x82"
"\x26\x08\x1D\x7E\x0A\x8B\x56\x0C\xC7\x42\x20\x20\x00\x00\x00\x83\x3D\xE4\x82\x26\x08\x01\x75\x29"
"\x83\x3D\xE8\x82\x26\x08\x7A\x7E\x20\x8B\x7D\x08\x8B\x57\x0C\xC7\x42\x20\x21\x00\x00\x00\x80\x3D"
"\xDC\x82\x26\x08\x00\x74\x0A\x8B\x57\x0C\x81\x4A\x20\x00\x10\x00\x00\x83\x3D\xE4\x82\x26\x08\x02"
"\x75\x20\x8B\x75\x08\x8B\x56\x0C\xC7\x42\x20\x22\x00\x00\x00";
	return trypatch(fd, name, (off_t)0x0BEA8, oldcodeMEM,  newcodeMEM,  sizeof(newcodeMEM) - 1,
				  (off_t)0x11A09, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0x11BBC, oldcodeNICE2, newcodeNICE2, sizeof(newcodeNICE2) - 1,
				  (off_t)0x11C22, oldcodeNICE3, newcodeNICE3, sizeof(newcodeNICE3) - 1,
				  (off_t)0x8EB88, oldcodeK25, newcodeK25, sizeof(newcodeK25) - 1,
				  (off_t)0);
}

static int trypatch1142(struct file* fd, const char* name) {
	static const char newcodeMEM[] = 
"\x53\x83\xEC\x58\xB8\x74\x00\x00\x00\x89\xE3\xCD\x80\x85\xC0\x75"
"\x18\x8B\x4C\x24\x14\x8B\x54\x24\x10\x8B\x44\x24\x34\x83\xF8\x01"
"\x76\x11\x3D\x00\x10\x00\x00\x74\x10\x31\xC9\x31\xC0\xEB\x2E\xDA"
"\x88\x10\x08\xC1\xEA\x0C\xC1\xE9\x0C\x31\xC0\x81\xFA\xFF\x7F\x00"
"\x00\x76\x0C\x81\xC2\xFF\x1F\x00\x00\x81\xE2\x00\xE0\xFF\xFF\x81"
"\xC2\xFF\x07\x00\x00\x81\xE2\x00\xF8\xFF\xFF\x40\xB3\x99\x8B\x5C"
"\x24\x60\x89\x0B\x89\x53\x04\x83\xC4\x58\x5B\xC3";
	static const char oldcodeMEM[] = 
"\x55\x89\xE5\x83\xEC\x0C\x57\x56\x53\x81\xC4\x18\xFC\xFF\xFF\x89"
"\xE7\x89\xE3\x8B\x55\x08\xC7\x02\x80\x00\x00\x00\xC7\x42\x04\x00"
"\x00\x00\x00\xC7\x42\x08\x00\x00\x00\x00\x6A\x00\x68\x7C\xC1\x1C"
"\x08\xE8\x5E\xDA\xFF\xFF\x89\xC6\x83\xC4\x08\x83\xFE\xFF\x74\x76"
"\x68\xE7\x03\x00\x00\x57\x56\xE8\xF8\xCA\xFF\xFF\x83\xC4\x0C\x83"
"\xF8\xFF\x74\x5C\xC6\x04\x38\x00\xEB\x07\x89\xF6\x80\x3B\x00\x74"
"\x07\x8A\x03\x43\x3C\x0A\x75\xF4\x8D\x45\xF4\x50";
	static const char newcodeNICE[] =
"\xE8\xA2\x76\xFF\xFF\x31\xF6\x83\xC4\x08";
	static const char oldcodeNICE[] =
"\xE8\xA2\x76\xFF\xFF\x89\xC6\x83\xC4\x08";
	static const char newcodeNICE2[] =
"\xE8\xEF\x74\xFF\xFF\x31\xDB\x83\xC4\x04";
	static const char oldcodeNICE2[] =
"\xE8\xEF\x74\xFF\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeNICE3[] =
"\xE8\x89\x74\xFF\xFF\x31\xDB\x83\xC4\x04";
	static const char oldcodeNICE3[] =
"\xE8\x89\x74\xFF\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeK25[] =
"\x90\x90\x90\x90\x90\x33\xD2\x83\xC4\x04\x8B\x35"
"\x84\x89\x26\x08\x83\xFE\x02\x72\x49\x75\x22\x8B\x35\x88\x89\x26\x08\x0B\xF6\x90\x8B\x3D\x8C\x89"
"\x26\x08\x75\x1A\x83\xFF\x1D\x7E\x31\xB2\x20\xEB\x2D\x90\x90\x90\x3D\x88\x89\x26\x08\xB2\x24\xEB"
"\x15\x3D\x8C\x89\x26\x08\x4E\x75\x09\x83\xFF\x7A\x7E\x14\xB2\x21\xEB\x04\xB2\x22\xEB\x20\x80\x3D"
"\x80\x89\x26\x08\x00\x74\x03\x80\xCE\x10\x8B\x75\x08\x8B\x76\x0C\xEB\x05\x3D\x88\x89\x26\x08\x89"
"\x56\x20\x0B\xD2\xEB\x7D\x4E\x74\xDD\x42\x4E\x74\xD9\xEB\xBE";
	static const char oldcodeK25[] =
"\xC7\x42\x20\x00\x00\x00\x00\x83\xC4\x04\x83\x3D"
"\x84\x89\x26\x08\x02\x0F\x85\xCE\x00\x00\x00\x83\x3D\x88\x89\x26\x08\x00\x75\x13\x83\x3D\x8C\x89"
"\x26\x08\x1D\x7E\x0A\x8B\x56\x0C\xC7\x42\x20\x20\x00\x00\x00\x83\x3D\x88\x89\x26\x08\x01\x75\x29"
"\x83\x3D\x8C\x89\x26\x08\x7A\x7E\x20\x8B\x7D\x08\x8B\x57\x0C\xC7\x42\x20\x21\x00\x00\x00\x80\x3D"
"\x80\x89\x26\x08\x00\x74\x0A\x8B\x57\x0C\x81\x4A\x20\x00\x10\x00\x00\x83\x3D\x88\x89\x26\x08\x02"
"\x75\x20\x8B\x75\x08\x8B\x56\x0C\xC7\x42\x20\x22\x00\x00\x00";
	return trypatch(fd, name, (off_t)0x0BEA8, oldcodeMEM,  newcodeMEM,  sizeof(newcodeMEM) - 1,
				  (off_t)0x11A55, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0x11C08, oldcodeNICE2, newcodeNICE2, sizeof(newcodeNICE2) - 1,
				  (off_t)0x11C6E, oldcodeNICE3, newcodeNICE3, sizeof(newcodeNICE3) - 1,
				  (off_t)0x8F664, oldcodeK25, newcodeK25, sizeof(newcodeK25) - 1,
				  (off_t)0);
}

static int trypatch1455(struct file* fd, const char* name) {
	static const char newcodeK25[] = 
"\x83\xF8\x04\x72\x1D\x8B\x57\x18\xC7\x42\x2C\x24\x00\x00\x00";
	static const char oldcodeK25[] = 
"\x83\xF8\x04\x75\x1D\x8B\x57\x18\xC7\x42\x2C\x24\x00\x00\x00";
	static const char newcodeMEM[] = 
"\x53\x83\xEC\x58\xB8\x74\x00\x00\x00\x89\xE3\xCD\x80\x85\xC0\x75"
"\x18\x8B\x4C\x24\x14\x8B\x54\x24\x10\x8B\x44\x24\x34\x83\xF8\x01"
"\x76\x11\x3D\x00\x10\x00\x00\x74\x10\x31\xC9\x31\xC0\xEB\x2E\xDA"
"\x88\x10\x08\xC1\xEA\x0C\xC1\xE9\x0C\x31\xC0\x81\xFA\xFF\x7F\x00"
"\x00\x76\x0C\x81\xC2\xFF\x1F\x00\x00\x81\xE2\x00\xE0\xFF\xFF\x81"
"\xC2\xFF\x07\x00\x00\x81\xE2\x00\xF8\xFF\xFF\x40\xB3\x99\x8B\x5C"
"\x24\x60\xC7\x03\x80\x00\x00\x00\x8B\x5C\x24\x64\x89\x13\x8B\x5C"
"\x24\x68\x89\x0B\x83\xC4\x58\x5B\xC3";
	static const char oldcodeMEM[] = 
"\x55\x89\xE5\x83\xEC\x0C\x57\x56\x53\x8B\x45\x08\x81\xC4\x18\xFC"
"\xFF\xFF\x89\xE3\xC7\x00\x80\x00\x00\x00\x8B\x4D\x0C\xC7\x01\x00"
"\x00\x00\x00\x8B\x7D\x10\xC7\x07\x00\x00\x00\x00\x6A\x00\x68\xDA"
"\x88\x10\x08\xE8\xC0\xD9\xF8\xFF\x89\xC6\x83\xC4\x08\x85\xF6\x7D"
"\x07\x31\xC0\xE9\x9A\x00\x00\x00\x68\xE7\x03\x00\x00\x53\x56\xE8"
"\x94\xD5\xF8\xFF\x83\xC4\x0C\x85\xC0\x7C\x37\xC6\x04\x18\x00\x8D"
"\x53\x01\x80\x3B\x0A\x74\x0C\x90\x8A\x02\x84\xC0\x74\x05\x42\x3C"
"\x0A\x75\xF5\x8D\x45\xF4\x50\x8D\x45";
	static const char newcodeNICE[] =
"\xE8\xE1\x04\xFF\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\xE1\x04\xFF\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x20F8C, oldcodeK25,  newcodeK25,  sizeof(newcodeK25) - 1,
				  (off_t)479300,  oldcodeMEM,  newcodeMEM,  sizeof(newcodeMEM) - 1,
				  (off_t)0x12396, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0);
}

static int trypatch1527(struct file* fd, const char* name) {
	static const char newcodeK25[] = 
"\x83\xF8\x04\x72\x1D\x8B\x57\x1C\xC7\x42\x24\x24\x00\x00\x00";
	static const char oldcodeK25[] = 
"\x83\xF8\x04\x75\x1D\x8B\x57\x1C\xC7\x42\x24\x24\x00\x00\x00";
	static const char newcodeMEM[] = 
"\x53\x83\xEC\x58\xB8\x74\x00\x00\x00\x89\xE3\xCD\x80\x85\xC0\x75"
"\x18\x8B\x4C\x24\x14\x8B\x54\x24\x10\x8B\x44\x24\x34\x83\xF8\x01"
"\x76\x11\x3D\x00\x10\x00\x00\x74\x10\x31\xC9\x31\xC0\xEB\x2E\xDA"
"\x88\x10\x08\xC1\xEA\x0C\xC1\xE9\x0C\x31\xC0\x81\xFA\xFF\x7F\x00"
"\x00\x76\x0C\x81\xC2\xFF\x1F\x00\x00\x81\xE2\x00\xE0\xFF\xFF\x81"
"\xC2\xFF\x07\x00\x00\x81\xE2\x00\xF8\xFF\xFF\x40\xB3\x99\x8B\x5C"
"\x24\x60\xC7\x03\x80\x00\x00\x00\x8B\x5C\x24\x64\x89\x13\x8B\x5C"
"\x24\x68\x89\x0B\x83\xC4\x58\x5B\xC3";
	static const char oldcodeMEM[] = 
"\x55\x89\xE5\x83\xEC\x0C\x57\x56\x53\x8B\x45\x08\x81\xC4\x18\xFC"
"\xFF\xFF\x89\xE3\xC7\x00\x80\x00\x00\x00\x8B\x4D\x0C\xC7\x01\x00"
"\x00\x00\x00\x8B\x7D\x10\xC7\x07\x00\x00\x00\x00\x6A\x00\x68\xAA"
"\x21\x0E\x08\xE8\x3C\x89\xFA\xFF\x89\xC6\x83\xC4\x08\x85\xF6\x7D"
"\x07\x31\xC0\xE9\x9A\x00\x00\x00\x68\xE7\x03\x00\x00\x53\x56\xE8"
"\xD0\x84\xFA\xFF\x83\xC4\x0C\x85\xC0\x7C\x37\xC6\x04\x18\x00\x8D"
"\x53\x01\x80\x3B\x0A\x74\x0C\x90\x8A\x02\x84\xC0\x74\x05\x42\x3C"
"\x0A\x75\xF5\x8D\x45\xF4\x50\x8D\x45";
	static const char newcodeNICE[] =
"\xE8\xE1\x14\xFF\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\xE1\x14\xFF\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeNICE2[] =
"\xE8\x4B\x15\xFF\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE2[] =
"\xE8\x4B\x15\xFF\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x1DD84, oldcodeK25,  newcodeK25,  sizeof(newcodeK25) - 1,
				  (off_t)0x5A208, oldcodeMEM,  newcodeMEM,  sizeof(newcodeMEM) - 1,
				  (off_t)0x114A6, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0x1143C, oldcodeNICE2, newcodeNICE2, sizeof(newcodeNICE2) - 1,
				  (off_t)0);
}

static int trypatch1690(struct file* fd, const char* name) {
	static const char newcodeMEM[] = 
"\x53\x83\xEC\x58\xB8\x74\x00\x00\x00\x89\xE3\xCD\x80\x85\xC0\x75"
"\x18\x8B\x4C\x24\x14\x8B\x54\x24\x10\x8B\x44\x24\x34\x83\xF8\x01"
"\x76\x11\x3D\x00\x10\x00\x00\x74\x10\x31\xC9\x31\xC0\xEB\x2E\xB0"
"\xD0\x12\x08\xC1\xEA\x0C\xC1\xE9\x0C\x31\xC0\x81\xFA\xFF\x7F\x00"
"\x00\x76\x0C\x81\xC2\xFF\x1F\x00\x00\x81\xE2\x00\xE0\xFF\xFF\x81"
"\xC2\xFF\x07\x00\x00\x81\xE2\x00\xF8\xFF\xFF\x40\xB3\x99\x8B\x5C"
"\x24\x60\xC7\x03\x80\x00\x00\x00\x8B\x5C\x24\x64\x89\x13\x8B\x5C"
"\x24\x68\x89\x0B\x83\xC4\x58\x5B\xC3";
	static const char oldcodeMEM[] = 
"\x55\x89\xE5\x83\xEC\x0C\x57\x56\x53\x8B\x45\x08\x81\xC4\x18\xFC"
"\xFF\xFF\x89\xE3\xC7\x00\x80\x00\x00\x00\x8B\x4D\x0C\xC7\x01\x00"
"\x00\x00\x00\x8B\x7D\x10\xC7\x07\x00\x00\x00\x00\x6A\x00\x68\xB0"
"\xD0\x12\x08\xE8\x04\x5B\xF7\xFF\x89\xC6\x83\xC4\x08\x85\xF6\x7D"
"\x07\x31\xC0\xE9\x9A\x00\x00\x00\x68\xE7\x03\x00\x00\x53\x56\xE8"
"\xB8\x56\xF7\xFF\x83\xC4\x0C\x85\xC0\x7C\x37\xC6\x04\x18\x00\x8D"
"\x53\x01\x80\x3B\x0A\x74\x0C\x90\x8A\x02\x84\xC0\x74\x05\x42\x3C"
"\x0A\x75\xF5\x8D\x45\xF4\x50\x8D\x45";
	static const char newcodeNICE[] =
"\xE8\x2C\xD5\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\x2C\xD5\xFE\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x1539B, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0x8CF60, oldcodeMEM,  newcodeMEM,  sizeof(newcodeMEM) - 1,
				  (off_t)0);
}

static int trypatch1732(struct file* fd, const char* name) {
	static const char newcodeNICE[] =
"\xE8\x4D\x00\xFF\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\x4D\x00\xFF\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x128AA, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0);
}

static int trypatch1746(struct file* fd, const char* name) {
	static const char newcodeNICE[] =
"\xE8\x49\x00\xFF\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\x49\x00\xFF\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x128AE, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0);
}

static int trypatch2129(struct file* fd, const char* name) {
	static const char newcodeNICE[] =
"\xE8\x73\xB9\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\x73\xB9\xFE\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeNICE2[] =
"\xE8\x09\xB9\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE2[] =
"\xE8\x09\xB9\xFE\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x18894, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0x188FE, oldcodeNICE2, newcodeNICE2, sizeof(newcodeNICE2) - 1,
				  (off_t)0);
}

static int trypatch2230(struct file* fd, const char* name) {
	static const char newcodeNICE[] =
"\xE8\xC7\xFF\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\xC7\xFF\xFE\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeNICE2[] =
"\xE8\x5D\xFF\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE2[] =
"\xE8\x5D\xFF\xFE\xFF\x89\xC3\x83\xC4\x04";
	return trypatch(fd, name, (off_t)0x12930, oldcodeNICE, newcodeNICE, sizeof(newcodeNICE) - 1,
				  (off_t)0x1299A, oldcodeNICE2, newcodeNICE2, sizeof(newcodeNICE2) - 1,
				  (off_t)0);
}

static int trypatch2242(struct file* fd, const char* name) {
	static const char newcodeNICE[] =
"\xE8\xC7\xFF\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE[] =
"\xE8\xC7\xFF\xFE\xFF\x89\xC3\x83\xC4\x04";
	static const char newcodeNICE2[] =
"\xE8\x5D\xFF\xFE\xFF\x33\xDB\x83\xC4\x04";
	static const char oldcodeNICE2[] =
"\xE8\x5D\xFF\xFE\xFF\x89\xC3\x83\xC4\x04";
	static const char oldcodeALLOCLOWMEM[] =
"\x8B\x47\x08\x85\xC0\x7D\x05\x05\xFF\x0F\x00\x00\xC1\xF8\x0C\x50"
"\xE8\x6F\xE1\x00\x00\x89\x45\xFC\x83\xC4\x04\x85\xC0\x0F\x84\xA9"
"\x00\x00\x00\xE8\xE8\xC6\xF9\xFF\x85\xC0\x0F\x94\xC3\x6A\x00\xE8"
"\xEC\xCD\xF9\xFF\x6A\x02\x68\x15\xA6\x10\x08\xE8\xC0\xCF\xF9\xFF"
"\x89\xC6\x83\xC4\x0C\x84\xDB\x74\x07\x6A\x00\xEB\x09\x8D\x76\x00"
"\xE8\xBB\xC7\xF9\xFF\x50\xE8\xC5\xCD\xF9\xFF\x83\xC4\x04\x85\xF6"
"\x7C\x62\xFF\x75\xFC\x56\x6A\x01\x6A\x03\xFF\x77\x08\xFF\x77\x04"
"\xE8\xFB\xC8\xF9\xFF\x89\xC3\x83\xC4\x18\x83\xFB\xFF\x74\x3C\x56"
"\xE8\x4B\xD0\xF9\xFF\x83\xC4\x04\x85\xC0\x7C\x1C\x8B\x55\xFC\x89"
"\x57\x14\x89\x5F\x04\xFF\x77\x08\x6A\x00\x53\xE8\xD0\xCC\xF9\xFF"
"\xB8\x01\x00\x00\x00\xEB\x27\x90\xBE\xFF\xFF\xFF\xFF\xFF\x77\x08"
"\xFF\x77\x04\xE8\x68\xC6\xF9\xFF\x83\xC4\x08\x56\xE8\x0F\xD0\xF9"
"\xFF\x83\xC4\x04\xFF\x75\xFC\xE8\x04\xE1\x00\x00";
	static const char newcodeALLOCLOWMEM[] =
"\x8B\x5F\x08\x81\xFB\x00\x10\x00\x00\x0F\x87\xBD\x00\x00\x00\xE8"
"\xFC\xC6\xF9\xFF\x8B\xF0\x0B\xC0\x74\x08\x6A\x00\xE8\xFF\xCD\xF9"
"\xFF\x58\x6A\x02\x68\x58\x12\x11\x08\xE8\xD2\xCF\xF9\xFF\x83\xC4"
"\x0C\x0B\xF6\x8B\xF0\x74\x0C\xE8\xD4\xC7\xF9\xFF\x50\xE8\xDE\xCD"
"\xF9\xFF\x58\x0B\xF6\x0F\x8C\x81\x00\x00\x00\x6A\x00\x56\x6A\x01"
"\x6A\x03\x53\xFF\x77\x04\xE8\x15\xC9\xF9\xFF\x56\x8B\xF0\xE8\x6D"
"\xD0\xF9\xFF\x83\xC4\x1C\x83\xFE\xFF\x74\x61\x89\x77\x04\x56\xE8"
"\xE0\xE0\x00\x00\x59\xA9\x00\x00\xC0\xFF\x75\x47\xC1\xE0\x0C\x89"
"\x47\x14\x56\xE8\xE4\xE0\x00\x00\x58\x53\x6A\x00\x56\xE8\xDE\xCC"
"\xF9\xFF\x83\xC4\x0C\xB8\x01\x00\x00\x00\xEB\x32\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x53\x56\xE8\x56\xC6\xF9\xFF\x58\x58";
	static const char oldcodeFREELOWMEM[] =
"\x74\x26\xFF\x73\x14\xE8";
	static const char newcodeFREELOWMEM[] =
"\xEB\x26\xFF\x73\x14\xE8";
	return trypatch(fd, name, (off_t)0x12930, oldcodeNICE,        newcodeNICE,        sizeof(newcodeNICE) - 1,
				  (off_t)0x1299A, oldcodeNICE2,       newcodeNICE2,       sizeof(newcodeNICE2) - 1,
				  (off_t)416460,  oldcodeALLOCLOWMEM, newcodeALLOCLOWMEM, sizeof(newcodeALLOCLOWMEM) - 1,
				  (off_t)0x65CE4, oldcodeFREELOWMEM,  newcodeFREELOWMEM,  sizeof(newcodeFREELOWMEM) - 1,
				  (off_t)0);
}

static int tryvmx8848(struct file* fd, const char* name) {
	static const char newcodeSIOCG[] =
"\xC7\x44\x24\x04\xFD\x99\x04\x80\x8B\x47\x04\x89\x04\x24";
	static const char oldcodeSIOCG[] =
"\xC7\x44\x24\x04\x40\x89\x00\x00\x8B\x47\x04\x89\x04\x24";
	return trypatch(fd, name, (off_t)0x6B95E, oldcodeSIOCG, newcodeSIOCG, sizeof(newcodeSIOCG) - 1,
				  (off_t)0);
}

static int tryvmxdebug8848(struct file* fd, const char* name) {
	static const char newcodeSIOCG[] =
"\xC7\x44\x24\x04\xFD\x99\x04\x80\x8B\x47\x04\x89\x04\x24";
	static const char oldcodeSIOCG[] =
"\xC7\x44\x24\x04\x40\x89\x00\x00\x8B\x47\x04\x89\x04\x24";
	return trypatch(fd, name, (off_t)0x7AF3E, oldcodeSIOCG, newcodeSIOCG, sizeof(newcodeSIOCG) - 1,
				  (off_t)0);
}

static int tryvmx19414(struct file* fd, const char* name) {
	static const char newcodeSIOCG[] =
"\xC7\x44\x24\x04\xFD\x99\x04\x80\x8B\x47\x04\x89\x04\x24";
	static const char oldcodeSIOCG[] =
"\xC7\x44\x24\x04\x40\x89\x00\x00\x8B\x47\x04\x89\x04\x24";
	return trypatch(fd, name, (off_t)0x6B96E, oldcodeSIOCG, newcodeSIOCG, sizeof(newcodeSIOCG) - 1,
				  (off_t)0);
}

static int tryvmxdebug19414(struct file* fd, const char* name) {
	static const char newcodeSIOCG[] =
"\xC7\x44\x24\x04\xFD\x99\x04\x80\x8B\x47\x04\x89\x04\x24";
	static const char oldcodeSIOCG[] =
"\xC7\x44\x24\x04\x40\x89\x00\x00\x8B\x47\x04\x89\x04\x24";
	return trypatch(fd, name, (off_t)0x7AF4E, oldcodeSIOCG, newcodeSIOCG, sizeof(newcodeSIOCG) - 1,
				  (off_t)0);
}

static int tryvmx9089(struct file* fd, const char* name) {
	static const char newcodeSIOCG[] =
"\xC7\x44\x24\x04\xFD\x99\x04\x80\x8B\x47\x04\x89\x04\x24";
	static const char oldcodeSIOCG[] =
"\xC7\x44\x24\x04\x40\x89\x00\x00\x8B\x47\x04\x89\x04\x24";
	return trypatch(fd, name, (off_t)0x6C6DE, oldcodeSIOCG, newcodeSIOCG, sizeof(newcodeSIOCG) - 1,
				  (off_t)0);
}

static int tryvmxdebug9089(struct file* fd, const char* name) {
	static const char newcodeSIOCG[] =
"\xC7\x44\x24\x04\xFD\x99\x04\x80\x8B\x47\x04\x89\x04\x24";
	static const char oldcodeSIOCG[] =
"\xC7\x44\x24\x04\x40\x89\x00\x00\x8B\x47\x04\x89\x04\x24";
	return trypatch(fd, name, (off_t)0x7C45E, oldcodeSIOCG, newcodeSIOCG, sizeof(newcodeSIOCG) - 1,
				  (off_t)0);
}

static int trybridge8848(struct file* fd, const char* name) {
	static const char newcodeSIOCS[] =
"\xC7\x44\x24\x04\xFE\x99\x08\x40\x89\x3C\x24\xE8";
	static const char oldcodeSIOCS[] =
"\xC7\x44\x24\x04\x41\x89\x00\x00\x89\x3C\x24\xE8";
	return trypatch(fd, name, (off_t)0x930, oldcodeSIOCS, newcodeSIOCS, sizeof(newcodeSIOCS) - 1,
				  (off_t)0);
}

static int trybridge8848_72(struct file* fd, const char* name) {
	static const char newcodeSIOCS[] =
"\xC7\x44\x24\x04\xFE\x99\x08\x40\x89\x3C\x24\xE8";
	static const char oldcodeSIOCS[] =
"\xC7\x44\x24\x04\xFD\x99\x08\x40\x89\x3C\x24\xE8";
	return trypatch(fd, name, (off_t)0x930, oldcodeSIOCS, newcodeSIOCS, sizeof(newcodeSIOCS) - 1,
				  (off_t)0);
}

struct vmp {
	const char* name;
	int (*fn)(struct file* fd, const char* name);
};

static const struct vmp pvmware[] = {
	{ "VMware Workstation 2.0.2 (build-621) [upgrade to 2.0.4 !]",	trypatch621  },
	{ "VMware Express 2.0.4 (build-1133)",				trypatch1133 },
	{ "VMware Workstation 2.0.4 (build-1142)",			trypatch1142 },
	{ "VMware Workstation 3.0.0 (build-1455) [upgrade to 3.2.1 !]",	trypatch1455 },
	{ "VMware GSX Server 1.0.3 (build-1527)",			trypatch1527 },
	{ "VMware Workstation 3.1.0 (build-1690) [upgrade to 3.2.1 !]",	trypatch1690 },
	{ "VMware Workstation 3.1.0 (build-1732) [upgrade to 3.2.1 !]",	trypatch1732 },
	{ "VMware Workstation 3.1.0 (build-1746) [upgrade to 3.2.1 !]",	trypatch1746 },
	{ "VMware GSX Server 2.0.x (build-2050 to build-2129) [upgrade to 2.5.1 !]", trypatch2129 },
	{ "VMware Workstation 3.2.1 (build-2242)",			trypatch2242 },
	{ "VMware Workstation 3.2.x (build-2230 to build-2242)",	trypatch2230 },
	{ NULL,								NULL }};

static const struct vmp pvmx[] = {
	{ "VMware Workstation 4.5.2 (build-8848) [upgrade to 4.5.3 !]",	tryvmx8848   },
	{ "VMware Workstation 4.5.3 (build-19414)",			tryvmx19414  },
	{ "VMware GSX Server 3.1.0 (build-9089)",			tryvmx9089   },
	{ NULL,								NULL }};

static const struct vmp pvmxdebug[] = {
	{ "VMware Workstation 4.5.2 (build-8848) [upgrade to 4.5.3 !]",	tryvmxdebug8848  },
	{ "VMware Workstation 4.5.3 (build-19414)",			tryvmxdebug19414 },
	{ "VMware GSX Server 3.1.0 (build-9089)",			tryvmxdebug9089  },
	{ NULL,								NULL }};

static const struct vmp pbridge[] = {
	{ "VMware Workstation 4.5.2 or 4.5.3, VMware GSX Server 3.1.0 or 3.2.0",	trybridge8848    },
	{ "VMware Workstation 4.5.2 or VMware GSX Server 3.1.0 (update72 applied)",	trybridge8848_72 },
	{ NULL,								NULL }};

static const struct vmpa {
	const char* type;
	const struct vmp* info;
} vmpinfo[] = {
	{ "vmware",	pvmware   },
	{ "vmx",	pvmx      },
	{ "vmxdebug",	pvmxdebug },
	{ "bridge",	pbridge   },
	{ NULL,		NULL      }};

static const struct vmp* gettype(const char* type) {
	const struct vmpa* p;
	
	for (p = vmpinfo; p->type; p++) {
		if (!strcmp(p->type, type)) {
			break;
		}
	}
	return p->info;
}

int main(int argc, char* argv[]) {
	struct file f;
	int err;
	const struct vmp *vp;
		
	if (argc != 3) {
		fprintf(stderr, "File name missing!\n");
		return 99;
	}
	vp = gettype(argv[1]);
	if (!vp) {
		fprintf(stderr, "Invalid update type requested!\n");
		return 97;
	}
	f.filename = argv[2];
	printf("Updating %s ... ", f.filename);
	fflush(stdout);
	f.writeable = 1;
	f.fd = open(f.filename, O_RDWR);
	if (f.fd == -1) {
		if (errno == ETXTBSY) {
			f.writeable = 0;
			f.fd = open(f.filename, O_RDONLY);
		}
		if (f.fd == -1) {
			printf("failed\n");
			fprintf(stderr, "Cannot open %s: %m\n", f.filename);
			return 98;
		}
	}
	for (; vp->name; vp++) {
		err = vp->fn(&f, vp->name);
		switch (err) {
			case 0 ... 9:	close(f.fd); return 0;	/* OK */
			case 40 ... 49: 
				close(f.fd);
				fprintf(stderr, "ERROR! It is possible that your %s is corrupted.\n", f.filename);
				fprintf(stderr, "ERROR! Please, reinstall %s. Error code is %u.\n", vp->name, err);
				return 40;
			case 30 ... 39:
				close(f.fd);
				fprintf(stderr, "ERROR! Cannot update %s. Error code is %u.\n", f.filename, err);
				return 30;
			case 10 ... 29:
				break;
			default:
				close(f.fd);
				fprintf(stderr, "ERROR! Unexpected error. Error code is %u.\n", err);
				return 99;
		}
	}
	close(f.fd);
	printf("No patch needed/available\n");
	return 10;
}

