From 47bf65ab6163fb70eb2ad309c9487229832bcaed Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 14 Dec 2010 01:40:34 +0200 Subject: [PATCH] add basic .Z support --- Makefile | 5 +- frontend/main.c | 36 ++++- frontend/menu.c | 3 +- frontend/plugin.c | 4 + frontend/plugin.h | 1 + plugins/cdrcimg/cdrcimg.c | 312 ++++++++++++++++++++++++++++++++++++++ plugins/cdrcimg/cdrcimg.h | 3 + 7 files changed, 357 insertions(+), 7 deletions(-) create mode 100644 plugins/cdrcimg/cdrcimg.c create mode 100644 plugins/cdrcimg/cdrcimg.h diff --git a/Makefile b/Makefile index 69c4f5e2..b712718b 100644 --- a/Makefile +++ b/Makefile @@ -47,9 +47,12 @@ ifdef X11 LDFLAGS += -lX11 -lXv OBJS += plugins/dfxvideo/draw.o else -CFLAGS += -D_MACGL # disables X in dfxvideo +plugins/dfxvideo/%.o: CFLAGS += -D_MACGL # disables X in dfxvideo OBJS += plugins/dfxvideo/draw_fb.o endif +# cdrcimg +plugins/cdrcimg/%.o: CFLAGS += -Wall +OBJS += plugins/cdrcimg/cdrcimg.o # gui OBJS += gui/Config.o gui/Plugin.o diff --git a/frontend/main.c b/frontend/main.c index b05893c9..372fdf1d 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -18,6 +18,7 @@ #include "menu.h" #include "../gui/Linux.h" #include "../libpcsxcore/misc.h" +#include "../plugins/cdrcimg/cdrcimg.h" #include "common/plat.h" #include "common/input.h" @@ -67,11 +68,31 @@ static void CreateMemcard(char *filename, char *conf_mcd) { } } +void set_cd_image(const char *fname) +{ + const char *ext; + int len; + + len = strlen(fname); + ext = fname; + if (len > 2) + ext = fname + len - 2; + + if (strcasecmp(ext, ".z") == 0) { + SetIsoFile(NULL); + cdrcimg_set_fname(fname); + strcpy(Config.Cdr, "builtin_cdrcimg"); + } else { + SetIsoFile(fname); + strcpy(Config.Cdr, "builtin_cdr"); + } +} + int main(int argc, char *argv[]) { char file[MAXPATHLEN] = ""; char path[MAXPATHLEN]; - int runcd = 0; + const char *cdfile = NULL; int loadst = 0; void *tmp; int i; @@ -118,8 +139,7 @@ int main(int argc, char *argv[]) isofilename[0] = 0; } - SetIsoFile(isofilename); - runcd = 1; + cdfile = isofilename; } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || @@ -189,6 +209,10 @@ int main(int argc, char *argv[]) chdir(plugin_default_dir); g_free(plugin_default_dir); */ + + if (cdfile) + set_cd_image(cdfile); + if (SysInit() == -1) return 1; @@ -215,7 +239,7 @@ int main(int argc, char *argv[]) if (Load(file) != -1) ready_to_go = 1; } else { - if (runcd) { + if (cdfile) { if (LoadCdrom() == -1) { ClosePlugins(); printf(_("Could not load CD-ROM!\n")); @@ -406,11 +430,13 @@ char *getenv(const char *name) /* we hook statically linked plugins here */ static const char *builtin_plugins[] = { - "builtin_gpu", "builtin_spu", "builtin_cdr", "builtin_pad" + "builtin_gpu", "builtin_spu", "builtin_cdr", "builtin_pad", + "builtin_cdrcimg", }; static const int builtin_plugin_ids[] = { PLUGIN_GPU, PLUGIN_SPU, PLUGIN_CDR, PLUGIN_PAD, + PLUGIN_CDRCIMG, }; void *SysLoadLibrary(const char *lib) { diff --git a/frontend/menu.c b/frontend/menu.c index cae99a3a..1b7418b5 100644 --- a/frontend/menu.c +++ b/frontend/menu.c @@ -526,6 +526,7 @@ const char *plat_get_credits(void) static char *romsel_run(void) { + extern void set_cd_image(const char *fname); char *ret; ret = menu_loop_romsel(last_selected_fname, sizeof(last_selected_fname)); @@ -535,7 +536,7 @@ static char *romsel_run(void) lprintf("selected file: %s\n", ret); ready_to_go = 0; - SetIsoFile(ret); + set_cd_image(ret); LoadPlugins(); NetOpened = 0; if (OpenPlugins() == -1) { diff --git a/frontend/plugin.c b/frontend/plugin.c index ca359d7d..e2c1ca39 100644 --- a/frontend/plugin.c +++ b/frontend/plugin.c @@ -11,6 +11,7 @@ #include "plugin_lib.h" #include "plugin.h" +#include "../plugins/cdrcimg/cdrcimg.h" static int dummy_func() { return 0; @@ -190,6 +191,9 @@ void *plugin_link(enum builtint_plugins_e id, const char *sym) { int i; + if (id == PLUGIN_CDRCIMG) + return cdrcimg_get_sym(sym); + for (i = 0; i < ARRAY_SIZE(plugin_funcs); i++) { if (id != plugin_funcs[i].id) continue; diff --git a/frontend/plugin.h b/frontend/plugin.h index 48ab7198..76cab259 100644 --- a/frontend/plugin.h +++ b/frontend/plugin.h @@ -7,6 +7,7 @@ enum builtint_plugins_e { PLUGIN_SPU, PLUGIN_CDR, PLUGIN_PAD, + PLUGIN_CDRCIMG, }; void *plugin_link(enum builtint_plugins_e id, const char *sym); diff --git a/plugins/cdrcimg/cdrcimg.c b/plugins/cdrcimg/cdrcimg.c new file mode 100644 index 00000000..608fdc42 --- /dev/null +++ b/plugins/cdrcimg/cdrcimg.c @@ -0,0 +1,312 @@ +/* + * (C) Gražvydas "notaz" Ignotas, 2010 + * + * This work is licensed under the terms of any of these licenses + * (at your option): + * - GNU GPL, version 2 or later. + * - GNU LGPL, version 2.1 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include + +#include "cdrcimg.h" + +#define CD_FRAMESIZE_RAW 2352 + +static const char *cd_fname; +static unsigned int *cd_index_table; +static unsigned int cd_index_len; +static FILE *cd_file; + +static unsigned char cdbuffer[CD_FRAMESIZE_RAW]; +static unsigned char cdbuffer_compressed[CD_FRAMESIZE_RAW + 100]; +static int current_sector; + +struct CdrStat; +extern long CDR__getStatus(struct CdrStat *stat); + +struct CdrStat +{ + unsigned long Type; + unsigned long Status; + unsigned char Time[3]; // current playing time +}; + +struct trackinfo { + enum {DATA, CDDA} type; + char start[3]; // MSF-format + char length[3]; // MSF-format +}; + +#define MAXTRACKS 100 /* How many tracks can a CD hold? */ + +static int numtracks = 0; + +#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */ +#define MSF2SECT(m, s, f) (((m) * 60 + (s) - 2) * 75 + (f)) + +// return Starting and Ending Track +// buffer: +// byte 0 - start track +// byte 1 - end track +static long CDRgetTN(unsigned char *buffer) +{ + buffer[0] = 1; + buffer[1] = numtracks > 0 ? numtracks : 1; + + return 0; +} + +// return Track Time +// buffer: +// byte 0 - frame +// byte 1 - second +// byte 2 - minute +static long CDRgetTD(unsigned char track, unsigned char *buffer) +{ + buffer[2] = 0; + buffer[1] = 2; + buffer[0] = 0; + + return 0; +} + +// read track +// time: byte 0 - minute; byte 1 - second; byte 2 - frame +// uses bcd format +static long CDRreadTrack(unsigned char *time) +{ + unsigned int start_byte, size; + unsigned long cdbuffer_size; + int ret, sector; + + if (cd_file == NULL) + return -1; + + sector = MSF2SECT(btoi(time[0]), btoi(time[1]), btoi(time[2])); + if (sector == current_sector) { + // it's already there, nothing to do + //printf("hit sect %d\n", sector); + return 0; + } + + if (sector >= cd_index_len) { + fprintf(stderr, "sector %d is past track end\n", sector); + return -1; + } + + start_byte = cd_index_table[sector]; + if (fseek(cd_file, start_byte, SEEK_SET) != 0) { + fprintf(stderr, "seek error for sector %d at %x: ", + sector, start_byte); + perror(NULL); + return -1; + } + + size = cd_index_table[sector + 1] - start_byte; + if (size > sizeof(cdbuffer_compressed)) { + fprintf(stderr, "sector %d is too large: %u\n", sector, size); + return -1; + } + + if (fread(cdbuffer_compressed, 1, size, cd_file) != size) { + fprintf(stderr, "read error for sector %d at %x: ", + sector, start_byte); + perror(NULL); + return -1; + } + + cdbuffer_size = sizeof(cdbuffer); + ret = uncompress(cdbuffer, &cdbuffer_size, cdbuffer_compressed, size); + if (ret != 0) { + fprintf(stderr, "uncompress failed with %d for sector %d\n", ret, sector); + return -1; + } + if (cdbuffer_size != sizeof(cdbuffer)) + printf("%lu != %d\n", cdbuffer_size, sizeof(cdbuffer)); + + // done at last! + current_sector = sector; + return 0; +} + +// return read track +static unsigned char *CDRgetBuffer(void) +{ + return cdbuffer + 12; +} + +// plays cdda audio +// sector: byte 0 - minute; byte 1 - second; byte 2 - frame +// does NOT uses bcd format +static long CDRplay(unsigned char *time) +{ + return 0; +} + +// stops cdda audio +static long CDRstop(void) +{ + return 0; +} + +// gets subchannel data +static unsigned char* CDRgetBufferSub(void) +{ + return NULL; +} + +static long CDRgetStatus(struct CdrStat *stat) { + CDR__getStatus(stat); + + stat->Type = 0x01; + + return 0; +} + +static long CDRclose(void) +{ + if (cd_file != NULL) { + fclose(cd_file); + cd_file = NULL; + } + if (cd_index_table != NULL) { + free(cd_index_table); + cd_index_table = NULL; + } + return 0; +} + +static long CDRshutdown(void) +{ + return CDRclose(); +} + +static long CDRinit(void) +{ + return 0; // do nothing +} + +// This function is invoked by the front-end when opening an ISO +// file for playback +static long CDRopen(void) +{ + // a Z.table file is binary where each element represents + // one compressed frame. + // 4 bytes: the offset of the frame in the .Z file + // 2 bytes: the length of the compressed frame + struct { + unsigned int offset; + unsigned short size; + } __attribute__((packed)) ztab_entry; + char table_fname[256]; + long table_size; + int i, ret; + FILE *f; + + if (cd_file != NULL) + return 0; // it's already open + + numtracks = 0; + + if (cd_fname == NULL) + return -1; + + snprintf(table_fname, sizeof(table_fname), "%s.table", cd_fname); + f = fopen(table_fname, "rb"); + if (f == NULL) { + fprintf(stderr, "missing file: %s: ", table_fname); + perror(NULL); + return -1; + } + + ret = fseek(f, 0, SEEK_END); + if (ret != 0) { + fprintf(stderr, "failed to seek\n"); + goto fail_table_io; + } + table_size = ftell(f); + fseek(f, 0, SEEK_SET); + + if (table_size > 2 * 1024 * 1024) { + fprintf(stderr, ".table too large\n"); + goto fail_table_io; + } + + cd_index_len = table_size / 6; + cd_index_table = malloc((cd_index_len + 1) * sizeof(cd_index_table[0])); + if (cd_index_table == NULL) + goto fail_table_io; + + for (i = 0; i < cd_index_len; i++) { + ret = fread(&ztab_entry, 1, sizeof(ztab_entry), f); + if (ret != sizeof(ztab_entry)) { + fprintf(stderr, ".table read failed on entry %d/%d\n", i, cd_index_len); + goto fail_table_io_read; + } + cd_index_table[i] = ztab_entry.offset; + } + // fake entry, so that we know last compressed block size + cd_index_table[i] = ztab_entry.offset + ztab_entry.size; + + cd_file = fopen(cd_fname, "rb"); + if (cd_file == NULL) { + fprintf(stderr, "faied to open: %s: ", table_fname); + perror(NULL); + goto fail_img; + } + fclose(f); + + printf("Loaded compressed CD Image: %s.\n", cd_fname); + current_sector = -1; + + return 0; + +fail_img: +fail_table_io_read: + free(cd_index_table); + cd_index_table = NULL; +fail_table_io: + fclose(f); + return -1; +} + +#define FUNC(n) { #n, n } + +static const struct { + const char *name; + void *func; +} plugin_funcs[] = { + /* CDR */ + FUNC(CDRinit), + FUNC(CDRshutdown), + FUNC(CDRopen), + FUNC(CDRclose), + FUNC(CDRgetTN), + FUNC(CDRgetTD), + FUNC(CDRreadTrack), + FUNC(CDRgetBuffer), + FUNC(CDRgetBufferSub), + FUNC(CDRplay), + FUNC(CDRstop), + FUNC(CDRgetStatus), +}; + +void cdrcimg_set_fname(const char *fname) +{ + cd_fname = fname; +} + +void *cdrcimg_get_sym(const char *sym) +{ + int i; + for (i = 0; i < sizeof(plugin_funcs) / sizeof(plugin_funcs[0]); i++) + if (strcmp(plugin_funcs[i].name, sym) == 0) + return plugin_funcs[i].func; + return NULL; +} + diff --git a/plugins/cdrcimg/cdrcimg.h b/plugins/cdrcimg/cdrcimg.h new file mode 100644 index 00000000..efeaaf9d --- /dev/null +++ b/plugins/cdrcimg/cdrcimg.h @@ -0,0 +1,3 @@ + +void cdrcimg_set_fname(const char *fname); +void *cdrcimg_get_sym(const char *sym); -- 2.39.2