PharaohResizer/PharaohResizer.c

569 lines
16 KiB
C

#include <stdlib.h>
#include <stdio.h>
#include <lz4.h>
#define EXE_SIZE 2142208
#define MIN_WIDTH 1024
#define MAX_WIDTH 7680
#define MIN_HEIGHT 720
#define MAX_HEIGHT 4320
unsigned long int widthOffsets[] =
{
0xcfa0a,
0xcfda3
};
unsigned long int heightOffsets[] =
{
0xcfa0f,
0xcfdad
};
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
unsigned char exeFile[EXE_SIZE];
/* Patch a single byte. */
void PatchByte(unsigned long int offset, unsigned char value)
{
exeFile[offset] = value;
}
/* Patch an array of bytes in */
void PatchBytes(unsigned long int offset, int count, unsigned char *bytes)
{
int i;
for (i = 0; i < count; ++i)
{
exeFile[offset+i] = bytes[i];
}
}
/* Patch a little-endian 32bit value in. */
void PatchU32(unsigned long int offset, unsigned long int value)
{
exeFile[offset] = value & 0xFF;
exeFile[offset+1] = (value >> 8) & 0xFF;
exeFile[offset+2] = (value >> 16) & 0xFF;
exeFile[offset+3] = (value >> 24) & 0xFF;
}
/* Helper function for Nopping out a region of code. */
void NopBytes(unsigned long int offset, int count)
{
int i;
for (i = 0; i < count; ++i)
{
exeFile[offset+i] = 0x90;
}
}
/* Sometimes we pad regions with non-nop bytes. int 3 (0xCC) is popular. */
void PadBytes(unsigned long int offset, int count, unsigned char byte)
{
int i;
for (i = 0; i < count; ++i)
{
exeFile[offset+i] = byte;
}
}
/* Apply all of the patches from the PharaohResizer
* version to a raw Cleopatra exe (assuming DRM, etc,
* skipped).
*/
void DoCrudeliosPatches()
{
unsigned char jmp_loc_56E331[] = {0xE9, 0x0B, 0xBB, 0x12, 0x00};
unsigned char jmp_loc_56E37B[] = {0xE9, 0x84, 0x04, 0x09, 0x00, 0x90};
unsigned char jmp_loc_56E35E[] = {0xE9, 0x11, 0x04, 0x09, 0x00, 0x90};
unsigned char jmp_loc_56E491[] = {0xE9, 0xEE, 0x5B, 0x07, 0x00};
unsigned char new_loc_51E96D[] = {
0x7C, 0x1B, /* jl short locret_51E98F */
0x52, 0x50, /* push edx | push eax */
0xE8, 0x21, 0xFA, 0x04, 0x00, /* call sub_56E39C */
0x58, 0x29, 0xD0, /* pop eax | sub eax, edx */
0x83, 0xE8, 0x2A, /* sub eax, 42 */
0xA3, 0x60, 0x3F, 0xF5, 0x00, /* mov dword_F53F60, eax */
0x83, 0xE8, 0x78, /* sub eax, 120 */
0xA3, 0x64, 0x3F, 0xF5, 0x00, /* mov dword_F53F64, eax */
0x5A, 0xC3 /* pop edx | ret */
};
unsigned char sub_51E990_patch[] = {
0x8B, 0x0D, 0xAC, 0x8D, 0xE3, 0x00, /* mov ecx, dword_E38DAC */
0x6A, 0x09, /* push 9 */
0x50, 0x51 /* push eax | push ecx */
};
unsigned char sub_51E990_patch2[] = { 0xE8, 0xA6, 0xFA, 0x04, 0x00, 0xC3 };
unsigned char sub_51E990_patch3[] = { 0xE8, 0x6B, 0xFA, 0x04, 0x00, 0x0C3 };
unsigned char jmp_loc_56E3C7[] = {0xE9, 0xAB, 0xE5, 0x04, 0x00};
unsigned char jmp_loc_56E3DF[] = {0xE9, 0xF2, 0xEA, 0x03, 0x00, 0x90};
unsigned char sub_56E24F[] = {
0x53,
0x56, 0xE8, 0x46, 0x01, 0x00, 0x00, 0x85, 0xD2,
0x74, 0x74, 0x52, 0x51, 0x31, 0xD2, 0xA1, 0xAC,
0x8D, 0xE3, 0x00, 0xBB, 0xA0, 0x02, 0x00, 0x00,
0xF7, 0xFB, 0xF7, 0xEB, 0x05, 0x50, 0x01, 0x00,
0x00, 0x8B, 0x1D, 0xE4, 0x67, 0xF5, 0x00, 0x59,
0x01, 0xCB, 0x5A, 0x31, 0xF6, 0x8B, 0x0D, 0xB0,
0x8D, 0xE3, 0x00, 0x83, 0xFA, 0x28, 0x7E, 0x11,
0x83, 0xFA, 0x32, 0x7E, 0x07, 0xBE, 0x14, 0x00,
0x00, 0x00, 0xEB, 0x05, 0xBE, 0x0A, 0x00, 0x00,
0x00, 0x29, 0xD1, 0x01, 0xF1, 0x2D, 0x50, 0x01,
0x00, 0x00, 0x3D, 0x50, 0x01, 0x00, 0x00, 0x7D,
0x02, 0x31, 0xC0, 0x50, 0x51, 0x52, 0x50, 0x51,
0x53, 0xB9, 0xB0, 0x5B, 0xF5, 0x00, 0xE8, 0xD5,
0x02, 0xFD, 0xFF, 0x5A, 0x59, 0x58, 0x85, 0xF6,
0x74, 0x08, 0x83, 0xEE, 0x0A, 0x83, 0xE9, 0x0A,
0xEB, 0xE1, 0x85, 0xC0, 0x75, 0xAD, 0x5E, 0x5B,
0xC3
};
unsigned char loc_56E2D3[] = {
0xE8, 0xB8, 0x02, 0xFD, 0xFF,
0x53, 0xA1, 0xB0, 0x8D, 0xE3, 0x00, 0xBB, 0x48,
0x03, 0x00, 0x00, 0x29, 0xD8, 0x8B, 0x0D, 0xE4,
0x67, 0xF5, 0x00, 0x83, 0xC1, 0x08, 0x50, 0x51,
0x6A, 0x00, 0x53, 0x51, 0xB9, 0xB0, 0x5B, 0xF5,
0x00, 0xE8, 0x92, 0x02, 0xFD, 0xFF, 0x59, 0x58,
0x81, 0xC3, 0x48, 0x03, 0x00, 0x00, 0x39, 0xC3,
0x7C, 0xE4, 0x51, 0xE8, 0x8C, 0x00, 0x00, 0x00,
0x59, 0x8B, 0x1D, 0xB0, 0x8D, 0xE3, 0x00, 0x81,
0xEB, 0xE8, 0x03, 0x00, 0x00, 0x29, 0xD3, 0x6A,
0x00, 0x53, 0x51, 0xB9, 0xB0, 0x5B, 0xF5, 0x00,
0xE8, 0x63, 0x02, 0xFD, 0xFF, 0x5B, 0xC3
};
unsigned char loc_56E331[] = {
0x52, 0xA1, 0xB0, 0x8D, 0xE3, 0x00, 0x8B,
0x15, 0x10, 0x2A, 0x5D, 0x00, 0x83, 0xE8, 0x20,
0x39, 0xC2, 0x7E, 0x02, 0x89, 0xD0, 0x5A, 0xE9,
0xDA, 0x44, 0xED, 0xFF
};
unsigned char loc_56E35E[] = {
0x31, 0xD2,
0xA1, 0xAC, 0x8D, 0xE3, 0x00, 0xB9, 0x0F, 0x00,
0x00, 0x00, 0x29, 0xC8, 0xF7, 0xF1, 0x50, 0xE8,
0x28, 0x00, 0x00, 0x00, 0x50, 0xE9, 0xDC, 0xFB,
0xF6, 0xFF
};
unsigned char loc_56E37B[] = {
0x31, 0xD2, 0xA1, 0xAC, 0x8D,
0xE3, 0x00, 0xB9, 0x0F, 0x00, 0x00, 0x00, 0x29,
0xC8, 0xF7, 0xF1, 0x50, 0xE8, 0x0B, 0x00, 0x00,
0x00, 0x83, 0xC0, 0x02, 0x50, 0xE9, 0x62, 0xFB,
0xF6, 0xFF,
};
unsigned char sub_56E39C[] = {
0x31, 0xD2, 0xA1, 0xB0,
0x8D, 0xE3, 0x00, 0x2D, 0xA0, 0x00, 0x00, 0x00,
0xB9, 0x3C, 0x00, 0x00, 0x00, 0xF7, 0xF1, 0x83,
0xFA, 0x18, 0x7F, 0x06, 0xB9, 0x02, 0x00, 0x00,
0x00, 0xC3, 0xB9, 0x03, 0x00, 0x00, 0x00, 0xC3
};
unsigned char loc_56E3C7[] = {
0x50,
0xE8, 0xCF, 0xFF, 0xFF, 0xFF, 0x58, 0x89, 0xC1,
0x29, 0xD1, 0x89, 0x0D, 0x58, 0xB5, 0xD3, 0x00,
0xE9, 0x57, 0x1A, 0xFB, 0xFF
};
unsigned char loc_56E3DF[] = {
0xA1,
0xB0, 0x8D, 0xE3, 0x00, 0x8B, 0x15, 0x10, 0x2A,
0x5D, 0x00, 0x83, 0xE8, 0x20, 0x39, 0xC2, 0x7F,
0x02, 0x89, 0xC2, 0xE9, 0xF6, 0x14, 0xFC, 0xFF
};
unsigned char loc_56E491[] = {
0x8B, 0x15, 0x30, 0x8E, 0xE3, 0x00, 0x83,
0xFA, 0x26, 0x7D, 0x05, 0xBA, 0x26, 0x00, 0x00,
0x00, 0xC1, 0xE0, 0x04, 0x52, 0x83, 0xC2, 0x08,
0x01, 0xC2, 0x3B, 0x15, 0xAC, 0x8D, 0xE3, 0x00,
0x5A, 0x7F, 0x05, 0x83, 0xC2, 0x00, 0xEB, 0x05,
0x83, 0xEA, 0x00, 0x29, 0xC2, 0x89, 0x15, 0x8C,
0xDD, 0xEA, 0x00, 0xE8, 0xD4, 0xFE, 0xFF, 0xFF,
0x8B, 0x0D, 0xB0, 0x8D, 0xE3, 0x00, 0x29, 0xD1,
0x31, 0xD2, 0x3B, 0x15, 0x78, 0x3F, 0xF5, 0x00,
0x75, 0x08, 0x81, 0xE9, 0xA2, 0x00, 0x00, 0x00,
0xEB, 0x03, 0x83, 0xE9, 0x2A, 0x8B, 0x15, 0x34,
0x8E, 0xE3, 0x00, 0x52, 0x83, 0xC2, 0x08, 0xA1,
0x88, 0xDD, 0xEA, 0x00, 0xC1, 0xE0, 0x04, 0x01,
0xC2, 0x39, 0xCA, 0x5A, 0x7F, 0x05, 0x83, 0xC2,
0x00, 0xEB, 0x07, 0x89, 0xCA, 0x83, 0xEA, 0x08,
0x29, 0xC2, 0x89, 0x15, 0x90, 0xDD, 0xEA, 0x00,
0xE9, 0xC7, 0xA3, 0xF8, 0xFF
};
unsigned char sub_56E532[] = {
0x53, 0x8B, 0x5C, 0x24, 0x10, 0x53,
0x53, 0xFF, 0x74, 0x24, 0x14, 0xFF, 0x74, 0x24,
0x14, 0xB9, 0xB0, 0x5B, 0xF5, 0x00, 0xE8, 0x45,
0x00, 0xFD, 0xFF, 0x6A, 0x01, 0xE8, 0x4E, 0x0B,
0xFB, 0xFF, 0x6A, 0x01, 0xE8, 0x27, 0x11, 0xFB,
0xFF, 0x83, 0xC4, 0x08, 0x5B, 0x81, 0xC3, 0x1D,
0x01, 0x00, 0x00, 0x3B, 0x1D, 0xAC, 0x8D, 0xE3,
0x00, 0x7C, 0xCC, 0x5B, 0xC2, 0x0C, 0x00
};
unsigned char sub_56E5A6[] = {
0xA1, 0xAC,
0x8D, 0xE3, 0x00, 0x2D, 0x00, 0x03, 0x00, 0x00,
0xD1, 0xF8, 0x50, 0xA1, 0xB0, 0x8D, 0xE3, 0x00,
0x2D, 0x00, 0x04, 0x00, 0x00, 0xD1, 0xF8, 0x50,
0xFF, 0x74, 0x24, 0x0C, 0xE8, 0xC7, 0xFF, 0xFC,
0xFF, 0xC2, 0x0C, 0x00
};
/* Patch a function call? */
PatchU32(0x1A236, 0x15436C);
PatchU32(0x1A8C7, 0x153CDB);
PatchU32(0x1A8F3, 0x153CAF);
PatchU32(0x1A964, 0x153C3E);
PatchU32(0x1A9AA, 0x153BF8);
PatchU32(0x1A9D1, 0x153BD1);
PatchU32(0x1AB2F, 0x153A73);
/* Patch a comparison out */
PatchByte(0x1E657, 0xEB); /*jmp*/
/* Patch a massive jump? */
PatchBytes(0x42821, 5, jmp_loc_56E331);
/* Patch a jnz -> jl */
PatchByte(0xDDEF0, 0x7C);
/* ...and a jump in */
PatchBytes(0xDDEF2, 6, jmp_loc_56E37B);
/* Patch a jnz -> jl */
PatchByte(0xDDF42, 0x7C);
/* ...and a jump in */
PatchBytes(0xDDF48, 6, jmp_loc_56E35E);
/* Patch a jnz -> jl */
PatchByte(0xF889C, 0x7C);
/* ...and a jump in */
PatchBytes(0xF889E, 5, jmp_loc_56E491);
/* ...and nop out a bunch. */
NopBytes(0xF88A3, 57);
/* Rewrite another functon. */
PatchBytes(0x11E972, ARRAY_SIZE(new_loc_51E96D), new_loc_51E96D);
/* sub_51E990 changes: */
/* jnz -> jl */
PatchByte(0x11E99A, 0x7C);
/* call target -> sub_56E24F */
PatchU32(0x11E99D, 0x4F8AE);
/* jnz -> jl */
PatchByte(0x11E9BB, 0x7C);
/* Modify setup for call to sub_4CD9D0 */
PatchBytes(0x11E9BD, ARRAY_SIZE(sub_51E990_patch), sub_51E990_patch);
NopBytes(0x11E9C7, 6);
/* add eax, _0_ instead of 250 */
PatchByte(0x11E9D9, 0);
/* jnz -> jl */
PatchByte(0x11EA67, 0x7C);
/* call sub_56E532 and return */
PatchBytes(0x11EA87, ARRAY_SIZE(sub_51E990_patch2), sub_51E990_patch2);
NopBytes(0x11EA8D, 22);
/* and again, call sub_56E532 and return */
PatchBytes(0x11EAC2, ARRAY_SIZE(sub_51E990_patch3), sub_51E990_patch3);
NopBytes(0x11EAC8, 22);
/* Another jnz -> jl */
PatchByte(0x11EBB0, 0x7C);
/* Another one, but this time a longer encoding */
PatchByte(0x11F4AD, 0x8C);
/* Another jnz -> jl */
PatchByte(0x11FE15, 0x7C);
/* Then a jmp loc_56E3C7 */
PatchBytes(0x11FE17, 5, jmp_loc_56E3C7);
NopBytes(0x11FE1C, 7);
/* sub_51FD60 patches: */
/* A jnz -> jl */
PatchByte(0x11FF3E, 0x7C);
/* Patch call target -> sub_56E532 */
PatchU32(0x11FF5C, 0x4E5D2);
/* Another call target -> sub_56E532 */
PatchU32(0x11FFBD, 0x4E571);
/* Another call target to sub_56E5A6 */
PatchU32(0x120F95, 0x4D60D);
/* A massive jump to loc_56E3DF */
PatchBytes(0x12F8E8, 6, jmp_loc_56E3DF);
/* jnz -> jl */
PatchByte(0x136689, 0x8C);
/* A big jump to loc_56E2D3 */
PatchByte(0x1366F5, 0xE9);
PatchU32(0x1366F6, 0x37BD9);
/* Patch 1003 -> 1900 in a push statement */
PatchU32(0x13712B, 1900);
/* Now patch in a bunch of custom functions and/or
function fragments in the free space at the end
of the .exe */
PadBytes(0x16E24D, 2, 0xCC);
PatchBytes(0x16E24F, ARRAY_SIZE(sub_56E24F), sub_56E24F);
PadBytes(0x16E2D1, 2, 0xCC);
/* FUNCTION CHUNK FOR sub_536670 */
PatchBytes(0x16E2D3, ARRAY_SIZE(loc_56E2D3), loc_56E2D3);
PadBytes(0x16E32F, 2, 0xCC);
/* FUNCTION CHUNK FOR sub_442800 */
PatchBytes(0x16E331, ARRAY_SIZE(loc_56E331), loc_56E331);
/* FUNCTION CHUNK FOR sub_4DDF20 */
PatchBytes(0x16E35E, ARRAY_SIZE(loc_56E35E), loc_56E35E);
PadBytes(0x16E37A, 1, 0xCC);
/* FUNCTION CHUNK FOR sub_4DDEC0 */
PatchBytes(0x16E37B, ARRAY_SIZE(loc_56E37B), loc_56E37B);
PadBytes(0x16E39A, 2, 0xCC);
/* sub_56E39C */
PatchBytes(0x16E39C, ARRAY_SIZE(sub_56E39C), sub_56E39C);
PadBytes(0x16E3C0, 7, 0xCC);
/* FUNCTION CHUNK FOR sub_51FD60 */
PatchBytes(0x16E3C7, ARRAY_SIZE(loc_56E3C7), loc_56E3C7);
PadBytes(0x16E3DD, 2, 0xCC);
/* FUNCTION CHUNK FOR sub_52F8B0 */
PatchBytes(0x16E3DF, ARRAY_SIZE(loc_56E3DF), loc_56E3DF);
/* FUNCTION CHUNK FOR sub_4F7E50 */
PatchBytes(0x16E491, ARRAY_SIZE(loc_56E491), loc_56E491);
/* sub_56E532 */
PatchBytes(0x16E532, ARRAY_SIZE(sub_56E532), sub_56E532);
/* sub_56E5A6 */
PatchBytes(0x16E5A6, ARRAY_SIZE(sub_56E5A6), sub_56E5A6);
}
void PatchResolution(int width, int height)
{
int i;
for (i = 0; i < ARRAY_SIZE(widthOffsets); ++i)
{
PatchU32(widthOffsets[i], width);
}
for (i = 0; i < ARRAY_SIZE(heightOffsets); ++i)
{
PatchU32(heightOffsets[i], height);
}
}
/* Patch in some code to auto-detect the resolution */
void PatchAutoResolution()
{
unsigned char call_SetScreenSize[] = {
0xE8, 0x57, 0x03, 0x00, 0x00, /* call SetScreenSize */
0xEB, 0x20 /* jmp loc_4CFA2B */
};
unsigned char new_SetScreenSize[] = {
0x8B, 0x2D, 0xA0, 0xF1, 0x56, 0x00, /* mov ebp, ds:GetSystemMetrics */
0x6A, 0x00, /* push SM_CXSCREEN (0) */
0xFF, 0xD5, /* call ebp (GetSystemMetrics) */
0xA3, 0xB0, 0x8D, 0xE3, 0x00, /* mov ScreenWidth, eax */
0x6A, 0x01, /* push SM_CYSCREEN (1) */
0xFF, 0xD5, /* call ebp (GetSystemMetrics) */
0xA3, 0xAC, 0x8D, 0xE3, 0x00, /* mov ScreenHeight, eax */
0xC3 /* ret */
};
/* Don't default to 800x600: jnz -> jmp */
PatchByte(0xCF9F0, 0xEB);
PatchBytes(0xCFA04, ARRAY_SIZE(call_SetScreenSize), call_SetScreenSize);
NopBytes(0xCFA0B, 32);
PatchBytes(0xCFD60, ARRAY_SIZE(new_SetScreenSize), new_SetScreenSize);
}
int ValidateResolution(int width, int height)
{
int valid = 1;
if (width & 3)
{
fprintf(stderr, "The width %d is not a multiple of 4.\n", width);
fprintf(stderr, "Pharaoh requires the resolution's width to be divisible by 4.\n");
valid = 0;
}
if (width < MIN_WIDTH)
{
fprintf(stderr, "The width %d is less than %d.\n", width, MIN_WIDTH);
fprintf(stderr, "The selected width must be at least %d pixels.\n", MIN_WIDTH);
valid = 0;
}
if (width > MAX_WIDTH)
{
fprintf(stderr, "The width %d is greater than %d.\n", width, MAX_WIDTH);
fprintf(stderr, "The selected width must be no greater than %d pixels.\n", MAX_WIDTH);
valid = 0;
}
if (height & 3)
{
fprintf(stderr, "The height %d is not a multiple of 4.\n", height);
fprintf(stderr, "Pharaoh requres the resolution's height to be divisible by 4.\n");
valid = 0;
}
if (height < MIN_HEIGHT)
{
fprintf(stderr, "The height %d is less than %d.\n", height, MIN_HEIGHT);
fprintf(stderr, "The selected height must be at least %d pixels.\n", MIN_HEIGHT);
valid = 0;
}
if (height > MAX_HEIGHT)
{
fprintf(stderr, "The height %d is greater than %d.\n", height, MAX_HEIGHT);
fprintf(stderr, "The selected height must be no greater than %d pixels.\n", MAX_HEIGHT);
valid = 0;
}
return valid;
}
int main(int argc, char **argv)
{
const char *inName;
const char *outName;
int width;
int height;
FILE *inFile;
FILE *outFile;
size_t compSize;
int retVal;
if (argc < 2)
{
printf("%s: Run Pharaoh+Cleopatra at different resolutions\n", argv[0]);
printf("\n");
printf("Usage:\n");
printf("\t%s input [output] [width] [height]\n", argv[0]);
printf("\tinput: the Cleopatra 2.1 .exe file, or extracted EXE_RESOURCE from PharaohResizer\n");
printf("\t[output]: The .exe file to write, defaults to PharaohNew.exe\n");
printf("\t[width]: The width of the resolution to use, otherwise autodetected\n");
printf("\t[height]: The height of the resolution to use, otherwise autodetected\n");
return 1;
}
inName = argv[1];
outName = (argc >= 3)?argv[2]:"PharaohNew.exe";
width = (argc >= 4)?atoi(argv[3]):0;
height = (argc >= 5)?atoi(argv[4]):0;
/* Validate the resolution before we do anything further. */
if ((width || height) && !ValidateResolution(width, height))
{
/* ValidateResolution prints its own errors. */
return 7;
}
inFile = fopen(inName, "rb");
if (!inFile)
{
fprintf(stderr, "Couldn't open input file \"%s\"\n", inName);
return 2;
}
outFile = fopen(outName, "wb");
if (!outFile)
{
fprintf(stderr, "Couldn't open output file \"%s\"\n", outName);
fprintf(stderr, "Check that the path is correct and is writable.\n");
fclose(inFile);
return 3;
}
fseek(inFile, 0, SEEK_END);
compSize = ftell(inFile);
fseek(inFile, 0, SEEK_SET);
if (compSize == EXE_SIZE)
{
/* We are patching an original Cleopatra 2.1 .exe */
if (fread(exeFile, EXE_SIZE, 1, inFile) != 1)
{
fprintf(stderr, "Couldn't read input file \"%s\"\n", inName);
fclose(inFile);
fclose(outFile);
return 5;
}
fclose(inFile);
/* As we're using an original .exe, we need to patch it. */
DoCrudeliosPatches();
}
else
{
unsigned char *compData = malloc(compSize);
if (!compData)
{
fprintf(stderr, "Not enough memory to load compressed file \"%s\"\n", inName);
fprintf(stderr, "Is it mysteriously enormous? It appears to be %lu MiB.\n", compSize / (1024 * 1024));
fclose(inFile);
fclose(outFile);
return 4;
}
if (fread(compData, compSize, 1, inFile) != 1)
{
fprintf(stderr, "Couldn't read input file \"%s\"\n", inName);
fclose(inFile);
fclose(outFile);
return 5;
}
fclose(inFile);
retVal = LZ4_decompress_safe((char *) compData, (char *) exeFile, compSize, EXE_SIZE);
if (retVal < 1)
{
fprintf(stderr, "Couldn't decompress input file \"%s\"\n", inName);
fprintf(stderr, "Check that it's the correct resource extracted from PharaohResizer.exe\n");
fprintf(stderr, "You can extract it from PharaohResizer.exe with:\n");
fprintf(stderr, "\twrestool PharaohResizer.exe -x --type='EXECUTABLE' --name=101\n");
fprintf(stderr, "Alternatively, make sure you're providing a Cleopatra 2.1 English .exe file\n");
return 6;
}
}
if (width && height)
{
/* Patch the user's width and height in. */
PatchResolution(width, height);
}
else
{
/* Write some code to autodetect the resolution. */
PatchAutoResolution();
}
if (fwrite(exeFile, EXE_SIZE, 1, outFile) != 1)
{
fprintf(stderr, "Couldn't write output executable \"%s\"\n", outName);
fprintf(stderr, "Have you run out of disk space or something?\n");
fclose(outFile);
return 8;
}
fclose(outFile);
return 0;
}