First commit

This commit is contained in:
Matteo Bini 2023-08-22 12:35:11 +02:00
commit 5148b1182f
4 changed files with 634 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
EXE_RESOURCE
Pharaoh.exe
Pharaoh_*.exe
PharaohNew.exe
PharaohResizer

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
PharaohResizer: PharaohResizer.c
$(CC) -Os -ansi -pedantic $@.c -o $@ -llz4
clean:
rm -f PharaohResizer
.PHONY: clean

568
PharaohResizer.c Normal file
View File

@ -0,0 +1,568 @@
#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;
}

54
README Normal file
View File

@ -0,0 +1,54 @@
Pharaoh Resizer in ANSI C, by Matteo Bini.
Created in 2023. Public domain and free for any use.
This is a version of Pharaoh Resizer written in ANSI C, based on the
GNU/Linux version of the same program made by sulix [1], which itself
was based on the original Pharaoh Resizer source code by crudelios [2].
[1] https://github.com/sulix/PharaohResizer/tree/linux
[2] https://github.com/crudelios/PharaohResizer
The original readme.txt file by crudelios follows below.
Pharaoh Resizer, by crudelios.
Created in 2016. Public domain and free for any use.
This program was created in order to help people resize their Pharaoh + Cleopatra to widescreen.
Currently it supports an horizontal resolution from 1024 to 7680 and a vertical resolution from 720
to 4320 (allowing for perfect usage on 8k screens!).
In order to compile the source code, you'll need to include the LZ4 library. LZ4 is a very fast
compression algorithm which is used to decompress my edited Pharaoh.exe that is included with
this program. Check the LZ4 license below in order to download it:
LZ4 - Fast LZ compression algorithm
Copyright (C) 2011-2012, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
- LZ4 source repository : http://code.google.com/p/lz4/