From 47bf65ab6163fb70eb2ad309c9487229832bcaed Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 14 Dec 2010 01:40:34 +0200 Subject: add basic .Z support --- plugins/cdrcimg/cdrcimg.c | 312 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 plugins/cdrcimg/cdrcimg.c (limited to 'plugins/cdrcimg/cdrcimg.c') diff --git a/plugins/cdrcimg/cdrcimg.c b/plugins/cdrcimg/cdrcimg.c new file mode 100644 index 0000000..608fdc4 --- /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; +} + -- cgit v1.2.3