Files
cell/source/prosperon.c

104 lines
3.7 KiB
C

#include "script.h"
#include "physfs.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
static unsigned char *zip_buffer_global;
void free_zip(void)
{
free(zip_buffer_global);
}
int main(int argc, char **argv) {
printf("%s\n", argv[0]);
FILE *f = fopen(argv[0], "rb");
if (!f) { perror("fopen"); return 1; }
if (fseek(f, 0, SEEK_END) != 0) { perror("fseek"); fclose(f); return 1; }
long size = ftell(f);
if (size < 0) { perror("ftell"); fclose(f); return 1; }
zip_buffer_global = malloc(size);
if (!zip_buffer_global) { perror("malloc"); fclose(f); return 1; }
rewind(f);
if (fread(zip_buffer_global, 1, size, f) != (size_t)size) {
perror("fread");
free(zip_buffer_global);
fclose(f);
return 1;
}
fclose(f);
// Search backwards for the EOCD signature "PK\x05\x06".
// The EOCD record is at most 0xFFFF (65535) bytes plus 22 bytes long.
long max_comment_len = 0xFFFF;
long eocd_search_start = (size > (max_comment_len + 22)) ? (size - (max_comment_len + 22)) : 0;
long eocd_pos = -1;
for (long i = size - 22; i >= eocd_search_start; i--) {
if (zip_buffer_global[i] == 'P' &&
zip_buffer_global[i + 1] == 'K' &&
zip_buffer_global[i + 2] == 0x05 &&
zip_buffer_global[i + 3] == 0x06) {
eocd_pos = i;
break;
}
}
if (eocd_pos < 0) {
fprintf(stderr, "EOCD not found\n");
free(zip_buffer_global);
return 1;
}
// Parse the EOCD record.
// EOCD record layout (without the comment):
// Offset 0: 4 bytes signature ("PK\x05\x06")
// Offset 4: 2 bytes disk number
// Offset 6: 2 bytes disk with central directory
// Offset 8: 2 bytes number of central dir records on this disk
// Offset 10:2 bytes total number of central dir records
// Offset 12:4 bytes size of central directory (cd_size)
// Offset 16:4 bytes offset of start of central directory (cd_offset_rel, relative to zip start)
// Offset 20:2 bytes comment length
uint16_t comment_length = zip_buffer_global[eocd_pos + 20] |
(zip_buffer_global[eocd_pos + 21] << 8);
int eocd_size = 22 + comment_length;
uint32_t cd_size = zip_buffer_global[eocd_pos + 12] |
(zip_buffer_global[eocd_pos + 13] << 8) |
(zip_buffer_global[eocd_pos + 14] << 16) |
(zip_buffer_global[eocd_pos + 15] << 24);
uint32_t cd_offset_rel = zip_buffer_global[eocd_pos + 16] |
(zip_buffer_global[eocd_pos + 17] << 8) |
(zip_buffer_global[eocd_pos + 18] << 16) |
(zip_buffer_global[eocd_pos + 19] << 24);
// The size of the appended zip archive is given by:
// appended_zip_size = (offset of central directory + size of central directory + EOCD record size)
// Since the EOCD record is the last part of the zip archive,
// we can compute the start of the zip archive (zip_offset) as:
uint32_t appended_zip_size = cd_offset_rel + cd_size + eocd_size;
long zip_offset = size - appended_zip_size;
if (zip_offset < 0 || zip_offset >= size) {
fprintf(stderr, "Invalid zip offset computed: %ld\n", zip_offset);
free(zip_buffer_global);
return 1;
}
printf("Zip data found at offset %ld, appended zip size %u bytes\n",
zip_offset, appended_zip_size);
PHYSFS_init(argv[0]);
char *base = PHYSFS_getBaseDir();
PHYSFS_setWriteDir(base);
PHYSFS_mount(base, "/", 0);
int ret = PHYSFS_mountMemory(zip_buffer_global + zip_offset, appended_zip_size, free_zip, "core.zip", NULL, 0);
if (!ret) {
printf("COULD NOT MOUNT! Reason: %s\n", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
return 1;
}
script_startup(argc, argv); // runs engine.js
return 0;
}