104 lines
3.7 KiB
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;
|
|
}
|