ys2-intro/loader/tools/subsizer-0.7pre1/src/subsizer.c
2025-11-13 19:07:39 +03:00

461 lines
9.8 KiB
C

/**************************************************************************
*
* FILE subsizer.c
* Copyright (c) 2012, 2015, 2016, 2017 Daniel Kahlin <daniel@kahlin.net>
* Written by Daniel Kahlin <daniel@kahlin.net>
*
* DESCRIPTION
* CBM packer/cruncher
*
******/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include "bitfunc.h"
#include "buffer.h"
#include "crunch_normal.h"
#include "pathfinder.h"
#include "global.h"
#include "match.h"
#include "memory.h"
#include "message.h"
#include "params.h"
#include "sfx/detect_start.h"
#include "utils.h"
#define MAX_DECRUNCH_SIZE 0x100000
#define HAVE_CRUNCH_LEVEL 0
#define PROGRAM "subsizer"
const char program_g[] = PROGRAM;
typedef struct {
char *name;
int (*pack_func)(Buffer *, Buffer *);
int (*depack_func)(Buffer *, Buffer *);
int (*mem_func)(Memory *, Memory *, int num_opts, char **opts);
int (*sfx_func)(Memory *, Memory *, int num_opts, char **opts, int jmp);
} Type;
Type types[] = {
{ /* crunch_normal */
"normal",
crunch_normal, decrunch_normal,
crunch_normal_mem,
crunch_normal_sfx
},
{ 0, 0, 0, 0, 0 }
};
static int crunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode);
static int decrunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode);
static int crunch_mem(Type *p, int num_files, char **srcnames, char *destname, int forwards_mode);
#if HAVE_CRUNCH_LEVEL
static int crunch_level(Type *p, int num_files, char **srcnames, char *destname);
#endif
static int crunch_sfx(Type *p, int num_files, char **srcnames, char *destname, int num_sfx_opts, char **sfx_opts);
int main(int argc, char *argv[])
{
int c;
char **srcnames = 0;
char *destname = "a.out";
enum { MODE_RAW, MODE_SFX, MODE_MEM, MODE_LEVEL } mode;
int num_sfx_opts = 0;
char *sfx_opts[256];
int backwards_mode;
int forwards_mode;
int depack_mode;
char *pack_type;
/* defaults */
verbose_g = 1;
debug_g = 0;
mode = MODE_RAW; /* always raw mode for now */
backwards_mode = 0;
forwards_mode = 0;
depack_mode = 0;
pack_type = "normal";
/*
* scan for valid options
*/
while (EOF != (c = getopt(argc, argv, "o:t:rmlxX:bfdqvDVh"))) {
switch (c) {
/* a missing parameter */
case ':':
/* an illegal option */
case '?':
exit(1);
/* set quiet mode */
case 'q':
verbose_g = 0;
break;
/* set verbose mode */
case 'v':
verbose_g++;
break;
/* set debug mode */
case 'D':
debug_g = 1;
break;
/* print version */
case 'V':
fprintf (stdout, PROGRAM " " VERSION "\n");
exit(0);
/* print help */
case 'h':
fprintf(stderr,
PROGRAM " " VERSION ": CBM packer/cruncher\n"
"Copyright (c) 2012, 2015, 2016, 2017 Daniel Kahlin <daniel@kahlin.net>\n"
"Written by Daniel Kahlin <daniel@kahlin.net>\n"
"\n"
"usage: " PROGRAM " [OPTION] FILE...\n"
"\n"
"Valid options:\n"
" -t<type> select algorithm type (default: normal)\n"
" -r raw file\n"
" -m memory file\n"
#if HAVE_CRUNCH_LEVEL
" -l level file\n"
#endif
" -x executable file\n"
" -X<opts> executable options (implies '-x')\n"
" -b backwards mode\n"
" -f forwards mode\n"
" -d decompress\n"
" -o<name> output file\n"
" -q be quiet\n"
" -v be verbose (can be multiple)\n"
" -D display debug information\n"
" -h displays this help text\n"
" -V output program version\n"
);
exit(0);
/* set destination name */
case 'o':
destname = optarg;
break;
/* set algorithm type */
case 't':
pack_type = optarg;
break;
/* run in raw mode */
case 'r':
mode = MODE_RAW;
break;
/* run in memory mode */
case 'm':
mode = MODE_MEM;
break;
/* run in level mode */
case 'l':
mode = MODE_LEVEL;
break;
/* set executable mode */
case 'x':
mode = MODE_SFX;
break;
/* set executable options (implying -x) */
case 'X':
mode = MODE_SFX;
sfx_opts[num_sfx_opts] = optarg;
num_sfx_opts++;
break;
/* run in backwards mode */
case 'b':
backwards_mode = 1;
break;
/* run in forwards mode */
case 'f':
forwards_mode = 1;
break;
/* run in depack mode */
case 'd':
depack_mode = 1;
break;
/* default behavior */
default:
break;
}
}
/*
* optind now points at the first non option argument
* expect one or more arguments
*/
int num_files = argc - optind;
if (num_files < 1) {
panic("too few arguments");
}
srcnames = &argv[optind];
Type *p = types;
while (p->name) {
if (strcmp(p->name, pack_type) == 0) {
break;
}
p++;
}
if (!p->name) {
panic("unknown type '%s'", pack_type);
}
if (!depack_mode) {
/* handle crunching */
switch (mode) {
case MODE_RAW:
crunch_raw(p, num_files, srcnames, destname, backwards_mode);
break;
case MODE_MEM:
crunch_mem(p, num_files, srcnames, destname, forwards_mode);
break;
#if HAVE_CRUNCH_LEVEL
case MODE_LEVEL:
crunch_level(p, num_files, srcnames, destname);
break;
#endif
case MODE_SFX:
if (!p->sfx_func) {
panic("sfx not available for '%s'", p->name);
}
crunch_sfx(p, num_files, srcnames, destname, num_sfx_opts, sfx_opts);
break;
default:
panic("internal: invalid mode (%d)", mode);
break;
}
} else {
/* handle decrunching */
switch (mode) {
case MODE_RAW:
decrunch_raw(p, num_files, srcnames, destname, backwards_mode);
break;
case MODE_SFX:
panic("cannot depack sfx");
break;
default:
panic("internal: invalid mode (%d)", mode);
break;
}
}
exit(0);
}
static int crunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode)
{
int ret;
Buffer *sbf;
Buffer *dbf;
/* this should handle more than one file */
sbf = create_buffer_from_file(srcnames[0]);
dbf = create_buffer(MAX_DECRUNCH_SIZE);
if (backwards_mode) {
reverse_buffer(sbf);
}
ret = p->pack_func(sbf, dbf);
if (ret) {
printf("warning: packing failed. packer returned non-zero!\n");
}
msg(MSG_VERBOSE, "packed %zu bytes into %zu bytes\n", sbf->len, dbf->len);
#if 1
/* verify */
Buffer *vbf;
vbf = create_buffer(MAX_DECRUNCH_SIZE);
ret = p->depack_func(dbf, vbf);
if (ret) {
printf("warning: verify failed. depacker returned non-zero!\n");
} else if (compare_buffer(sbf, vbf) != 0) {
printf("warning: verify failed. depacked data does not match source data!\n");
} else {
msg(MSG_VERBOSE, "verifed %zu bytes...ok\n", sbf->len);
}
destroy_buffer(vbf);
#endif
if (backwards_mode) {
reverse_buffer(dbf);
}
write_buffer_to_file(dbf, destname);
destroy_buffer(dbf);
destroy_buffer(sbf);
return 0;
}
static int decrunch_raw(Type *p, int num_files, char **srcnames, char *destname, int backwards_mode)
{
int ret;
Buffer *sbf;
Buffer *dbf;
/* this should handle more than one file */
sbf = create_buffer_from_file(srcnames[0]);
dbf = create_buffer(MAX_DECRUNCH_SIZE);
if (backwards_mode) {
reverse_buffer(sbf);
}
ret = p->depack_func(sbf, dbf);
if (ret) {
printf("warning: depacking failed. depacker returned non-zero!\n");
}
msg(MSG_VERBOSE, "depacked %zu bytes into %zu bytes\n", sbf->len, dbf->len);
if (backwards_mode) {
reverse_buffer(dbf);
}
write_buffer_to_file(dbf, destname);
destroy_buffer(dbf);
destroy_buffer(sbf);
return 0;
}
static int crunch_mem(Type *p, int num_files, char **srcnames, char *destname, int forwards_mode)
{
int i;
int ret;
Memory *smem;
Memory *dmem;
int srclen, destlen;
smem = create_memory(0x10000);
dmem = create_memory(0x10000);
for (i = 0; i < num_files; i++) {
char *name = srcnames[i];
file_t f;
f = parse_filename(name);
load_mem(smem, &f, 0, 0);
}
srclen = smem->high - smem->low;
// ret = p->mem_func(smem, dmem, 0, 0);
ret = p->mem_func(smem, dmem, forwards_mode, 0); // FIXME: kludge!!!!
if (ret) {
printf("warning: packing failed. packer returned non-zero!\n");
}
destlen = dmem->high - dmem->low;
msg(MSG_VERBOSE, "packed %d bytes (%d blocks) into %d bytes (%d blocks)\n", srclen, (srclen+2+253)/254, destlen, (destlen+2+253)/254 );
save_file_from_memory(dmem, destname);
destroy_memory(dmem);
destroy_memory(smem);
return 0;
}
static int crunch_sfx(Type *p, int num_files, char **srcnames, char *destname, int num_sfx_opts, char **sfx_opts)
{
int i;
int ret;
Memory *smem;
Memory *dmem;
int srclen, destlen;
int jmp = -1;
smem = create_memory(0x10000);
dmem = create_memory(0x10000);
for (i = 0; i < num_files; i++) {
char *name = srcnames[i];
file_t f;
f = parse_filename(name);
load_mem(smem, &f, 0, 0);
}
srclen = smem->high - smem->low;
if (jmp < 0) {
int r;
r = detect_start(smem);
#if 0
if (r < 0) {
panic("couldn't detect start address!");
}
#endif
jmp = r;
msg(MSG_VERBOSE, "detected sys: $%04X\n", jmp);
}
/* if presumable basic start, make sure $0800 ends up $00 */
if (smem->low == 0x0801) {
set_byte(smem, 0x0800, 0x00);
smem->low = 0x0800;
}
ret = p->sfx_func(smem, dmem, num_sfx_opts, sfx_opts, jmp);
if (ret) {
printf("warning: packing failed. packer returned non-zero!\n");
}
destlen = dmem->high - dmem->low;
msg(MSG_VERBOSE, "packed %d bytes (%d blocks) into %d bytes (%d blocks)\n", srclen, (srclen+2+253)/254, destlen, (destlen+2+253)/254 );
save_file_from_memory(dmem, destname);
destroy_memory(dmem);
destroy_memory(smem);
return 0;
}
/* eof */