add basic .Z support
authornotaz <notasas@gmail.com>
Mon, 13 Dec 2010 23:40:34 +0000 (01:40 +0200)
committernotaz <notasas@gmail.com>
Thu, 16 Dec 2010 16:37:55 +0000 (18:37 +0200)
Makefile
frontend/main.c
frontend/menu.c
frontend/plugin.c
frontend/plugin.h
plugins/cdrcimg/cdrcimg.c [new file with mode: 0644]
plugins/cdrcimg/cdrcimg.h [new file with mode: 0644]

index 69c4f5e..b712718 100644 (file)
--- 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
index b05893c..372fdf1 100644 (file)
@@ -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) {
index cae99a3..1b7418b 100644 (file)
@@ -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) {
index ca359d7..e2c1ca3 100644 (file)
@@ -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;
index 48ab719..76cab25 100644 (file)
@@ -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 (file)
index 0000000..608fdc4
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+#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 (file)
index 0000000..efeaaf9
--- /dev/null
@@ -0,0 +1,3 @@
+
+void  cdrcimg_set_fname(const char *fname);
+void *cdrcimg_get_sym(const char *sym);