Mercurial > audlegacy-plugins
view src/vtx/vtxfile.c @ 2989:323138ecc070
skins interface: fix crash
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Wed, 07 Jan 2009 20:25:14 -0600 |
parents | 3134a0987162 |
children |
line wrap: on
line source
#include <string.h> #include <stdlib.h> #include <errno.h> #include <assert.h> #include <ctype.h> #include <inttypes.h> #include <audlegacy/plugin.h> #include "ayemu.h" /* defined in lh5dec.c */ extern void lh5_decode(unsigned char *inp,unsigned char *outp,unsigned long original_size, unsigned long packed_size); /* Read 8-bit integer from file. * Return 1 if error occurs */ static int read_byte(VFSFile *fp, int *p) { int c; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_byte()"); return 1; } *p = c; return 0; } /* Read 16-bit integer from file. * Return 1 if error occurs */ static int read_word16(VFSFile *fp, int *p) { int c; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_word16()"); return 1; } *p = c; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_word16()"); return 1; } *p += c << 8; return 0; } /* read 32-bit integer from file. * Returns 1 if error occurs */ static int read_word32(VFSFile *fp, int32_t *p) { int c; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_word32()"); return 1; } *p = c; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_word32()"); return 1; } *p += c << 8; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_word32()"); return 1; } *p += c << 16; if ((c = aud_vfs_getc(fp)) == EOF) { perror("libayemu: read_word32()"); return 1; } *p += c << 24; return 0; } /* read_NTstring: reads null-terminated string from file. * Return 1 if error occures. */ static int read_NTstring(VFSFile *fp, char s[]) { int i, c; for (i = 0 ; i < AYEMU_VTX_NTSTRING_MAX && (c = aud_vfs_getc(fp)) != EOF && c ; i++) s[i] = c; s[i] = '\0'; if (c == EOF) { fprintf(stderr, "libayemu: read_NTstring(): uninspected end of file!\n"); return 1; } return 0; } /** Open specified .vtx file and read vtx file header * * Open specified .vtx file and read vtx file header in struct vtx * Return value: true if success, else false */ int ayemu_vtx_open (ayemu_vtx_t *vtx, const char *filename) { char buf[2]; int error = 0; int32_t int_regdata_size; vtx->regdata = NULL; if ((vtx->fp = aud_vfs_fopen (filename, "rb")) == NULL) { fprintf(stderr, "ayemu_vtx_open: Cannot open file %s: %s\n", filename, strerror(errno)); return 0; } if (aud_vfs_fread(buf, 2, 1, vtx->fp) != 1) { fprintf(stderr,"ayemu_vtx_open: Can't read from %s: %s\n", filename, strerror(errno)); error = 1; } buf[0] = tolower(buf[0]); buf[1] = tolower(buf[1]); if (strncmp(buf, "ay", 2) == 0) vtx->hdr.chiptype = AYEMU_AY; else if (strncmp (buf, "ym", 2) == 0) vtx->hdr.chiptype = AYEMU_YM; else { fprintf (stderr, "File %s is _not_ VORTEX format!\nIt not begins from AY or YM.\n", filename); error = 1; } /* read VTX header info in order format specified, see http:// ..... */ if (!error) error = read_byte(vtx->fp, &vtx->hdr.stereo); if (!error) error = read_word16(vtx->fp, &vtx->hdr.loop); if (!error) error = read_word32(vtx->fp, &vtx->hdr.chipFreq); if (!error) error = read_byte(vtx->fp, &vtx->hdr.playerFreq); if (!error) error = read_word16(vtx->fp, &vtx->hdr.year); if (!error) { error = read_word32(vtx->fp, &int_regdata_size); vtx->hdr.regdata_size = (size_t) int_regdata_size; } if (!error) error = read_NTstring(vtx->fp, vtx->hdr.title); if (!error) error = read_NTstring(vtx->fp, vtx->hdr.author); if (!error) error = read_NTstring(vtx->fp, vtx->hdr.from); if (!error) error = read_NTstring(vtx->fp, vtx->hdr.tracker); if (!error) error = read_NTstring (vtx->fp, vtx->hdr.comment); if (error) { aud_vfs_fclose(vtx->fp); vtx->fp = NULL; } return !error; } /** Read and encode lha data from .vtx file * * Return value: pointer to unpacked data or NULL * Note: you must call ayemu_vtx_open() first. */ char *ayemu_vtx_load_data (ayemu_vtx_t *vtx) { char *packed_data; size_t packed_size; size_t buf_alloc; int c; if (vtx->fp == NULL) { fprintf(stderr, "ayemu_vtx_load_data: tune file not open yet (do you call ayemu_vtx_open first?)\n"); return NULL; } packed_size = 0; buf_alloc = 4096; packed_data = (char *) malloc (buf_alloc); /* read packed AY register data to end of file. */ while ((c = aud_vfs_getc (vtx->fp)) != EOF) { if (buf_alloc < packed_size) { buf_alloc *= 2; packed_data = (char *) realloc (packed_data, buf_alloc); if (packed_data == NULL) { fprintf (stderr, "ayemu_vtx_load_data: Packed data out of memory!\n"); aud_vfs_fclose (vtx->fp); return NULL; } } packed_data[packed_size++] = c; } aud_vfs_fclose (vtx->fp); vtx->fp = NULL; if ((vtx->regdata = (char *) malloc (vtx->hdr.regdata_size)) == NULL) { fprintf (stderr, "ayemu_vtx_load_data: Can allocate %d bytes for unpack register data\n", (int)(vtx->hdr.regdata_size)); free (packed_data); return NULL; } lh5_decode ((unsigned char *)packed_data, (unsigned char *)(vtx->regdata), vtx->hdr.regdata_size, packed_size); free (packed_data); vtx->pos = 0; return vtx->regdata; } /** Get next 14-bytes frame of AY register data. * * Return value: 1 if sucess, 0 if no enought data. */ int ayemu_vtx_get_next_frame (ayemu_vtx_t *vtx, char *regs) { int numframes = vtx->hdr.regdata_size / 14; if (vtx->pos++ >= numframes) return 0; else { int n; char *p = vtx->regdata + vtx->pos; for(n = 0 ; n < 14 ; n++, p+=numframes) regs[n] = *p; return 1; } } static void append_string(char *buf, const int sz, const char *str) { if (strlen(buf) + strlen(str) < sz - 1) strcat(buf, str); } static void append_number(char *buf, const int sz, const int num) { char s[32]; snprintf(s, sizeof(s), "%d", num); return append_string(buf, sz, s); } static void append_char(char *buf, const int sz, const char c) { int pos = strlen(buf); if (pos < sz - 1) buf[pos++] = c; buf[pos] = '\0'; } /** Print formated file name. If fmt is NULL the default format %a - %t will used * * %% the % sign * %a author of song * %t song title * %y year * %f song from * %T Tracker * %C Comment * %s stereo type (ABC, BCA, ...) * %l 'looped' or 'non-looped' * %c chip type: 'AY' or 'YM' * %F chip Freq * %P player freq */ void ayemu_vtx_sprintname (const ayemu_vtx_t *vtx, char *const buf, const int sz, const char *fmt) { static char *stereo_types[] = { "MONO", "ABC", "ACB", "BAC", "BCA", "CAB", "CBA" }; if (fmt == NULL) fmt = "%a - %t"; buf[0] = '\0'; while (*fmt != '\0') { if (*fmt == '%') { switch(*++fmt) { case 'a': append_string(buf, sz, vtx->hdr.author); break; case 't': append_string(buf, sz, vtx->hdr.title); break; case 'y': append_number(buf, sz, vtx->hdr.year); break; case 'f': append_string(buf, sz, vtx->hdr.from); break; case 'T': append_string(buf, sz, vtx->hdr.tracker); break; case 'C': append_string(buf, sz, vtx->hdr.comment); break; case 's': append_string(buf, sz, stereo_types[vtx->hdr.stereo]); break; case 'l': append_string(buf, sz, (vtx->hdr.loop)? "looped" : "non-looped" ); break; case 'c': append_string(buf, sz, (vtx->hdr.chiptype == AYEMU_AY)? "AY" : "YM" ); break; case 'F': append_number(buf, sz, vtx->hdr.chipFreq); break; case 'P': append_number(buf, sz, vtx->hdr.playerFreq); break; default: append_char(buf, sz, *fmt); } fmt++; } else { append_char(buf, sz, *fmt++); } } } /** Free all of allocaded resource for this file. * * Free the unpacket register data if is and close file. */ void ayemu_vtx_free (ayemu_vtx_t *vtx) { if (vtx->fp) { aud_vfs_fclose(vtx->fp); vtx->fp = NULL; } if (vtx->regdata) { free(vtx->regdata); vtx->regdata = NULL; } }