diff --git a/include/QF/riff.h b/include/QF/riff.h new file mode 100644 index 000000000..79bfe6e7a --- /dev/null +++ b/include/QF/riff.h @@ -0,0 +1,118 @@ +/* + riff.h + + riff wav file handling + + Copyright (C) 2003 Bill Currie + + Author: Bill Currie + Date: 2003/4/10 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef __QF_riff_h +#define __QF_riff_h + +#include "QF/quakeio.h" + +typedef struct d_chunk_s { + unsigned char name[4]; + unsigned len; +} d_chunk_t; + +typedef struct d_cue_point_s { + unsigned name; + unsigned position; + char chunk[4]; + unsigned chunk_start; + unsigned block_start; + unsigned sample_offset; +} d_cue_point_t; + +typedef struct d_cue_s { + unsigned count; + d_cue_point_t cue_points[1]; +} d_cue_t; + +typedef struct d_format_s { + unsigned short format_tag; + unsigned short channels; + unsigned samples_pre_sec; + unsigned byte_per_sec; + unsigned short align; +} d_format_t; + +typedef struct d_ltxt_s { + unsigned name; + unsigned len; + char purpose[4]; + unsigned country; + unsigned language; + unsigned dialect; + unsigned codepage; + unsigned char data[0]; +} d_ltxt_t; + +typedef struct cue_s { + d_chunk_t ck; + d_cue_t *cue; +} cue_t; + +typedef struct format_s { + d_chunk_t ck; + d_format_t format; + char fdata[0]; +} format_t; + +typedef struct ltxt_s { + d_chunk_t ck; + d_ltxt_t ltxt; +} ltxt_t; + +typedef struct label_s { + d_chunk_t ck; + unsigned ofs; + char *label; +} label_t; + +typedef struct data_s { + d_chunk_t ck; + char *data; +} data_t; + +typedef struct list_s { + d_chunk_t ck; + char name[4]; + d_chunk_t *chunks[0]; +} list_t; + +#define SWITCH(name) switch (((name)[0] << 24) | ((name)[1] << 16) \ + | ((name)[2] << 8) | (name)[3]) +#define CASE(a,b,c,d) (((unsigned char)(a) << 24) \ + | ((unsigned char)(b) << 16) \ + | ((unsigned char)(c) << 8) \ + | (unsigned char)(d)) + +list_t *riff_read (QFile *file); +void riff_free (list_t *riff); + +#endif//__QF_riff_h diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am index 5d42a1c4c..3f7eebb89 100644 --- a/libs/util/Makefile.am +++ b/libs/util/Makefile.am @@ -29,7 +29,8 @@ libQFutil_la_SOURCES= \ bspfile.c buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c \ fendian.c getopt.c getopt1.c hash.c idparse.c info.c link.c mathlib.c \ mdfour.c msg.c pakfile.c pcx.c plugin.c qargs.c qendian.c qfplist.c \ - quakefs.c quakeio.c sizebuf.c string.c sys.c tga.c va.c ver_check.c \ + quakefs.c quakeio.c riff.c sizebuf.c string.c sys.c tga.c va.c \ + ver_check.c \ wad.c zone.c $(fnmatch) EXTRA_DIST= $(asm_src) $(fnmatch_src) diff --git a/libs/util/riff.c b/libs/util/riff.c new file mode 100644 index 000000000..7aae9d395 --- /dev/null +++ b/libs/util/riff.c @@ -0,0 +1,381 @@ +/* + riff.c + + riff wav handling + + Copyright (C) 2003 Bill Currie + + Author: Bill Currie + Date: 2003/4/10 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static __attribute__ ((unused)) const char rcsid[] = + "$Id$"; + +#include +#include + +#ifdef _WIN32 +void *alloca(size_t size); +#endif + +#include "QF/dstring.h" +#include "QF/riff.h" + +static char * +read_string (QFile *f, int len) +{ + char c[2] = {0, 0}; + char *s; + int l = len; + dstring_t *str = dstring_newstr (); + + while (l--) { + Qread (f, c, 1); + if (!c[0]) + break; + dstring_appendstr (str, c); + } + s = str->str; + free (str); + if (len &1) puts ("bling"); + Qseek (f, l + (len & 1), SEEK_CUR); + return s; +} + +static void * +read_data (QFile *f, int len) +{ + void *data = malloc (len); + + Qread (f, data, len); + if (len &1) puts ("bling"); + Qseek (f, len & 1, SEEK_CUR); + return data; +} + +static void +read_ltxt (QFile *f, int len, d_ltxt_t *ltxt) +{ + Qread (f, ltxt, len); +} + +static void +read_adtl (dstring_t *list_buf, QFile *f, int len) +{ + d_chunk_t ck, *chunk = 0; + ltxt_t *ltxt; + label_t *label; + data_t *data; + list_t *list; + int r; + + list = (list_t *) list_buf->str; + while (len) { + r = Qread (f, &ck, sizeof (ck)); + if (!r) { + len = 0; + break; + } + len -= r; + SWITCH (ck.name) { + case CASE ('l','t','x','t'): + ltxt = malloc (sizeof (ltxt_t)); + ltxt->ck = ck; + read_ltxt (f, ck.len, <xt->ltxt); + chunk = <xt->ck; + break; + case CASE ('l','a','b','l'): + case CASE ('n','o','t','e'): + label = malloc (sizeof (label_t)); + label->ck = ck; + Qread (f, &label->ofs, 4); + label->label = read_string (f, ck.len - 4); + chunk = &label->ck; + break; + default: + data = malloc (sizeof (data)); + data->ck = ck; + data->data = read_data (f, ck.len); + chunk = &data->ck; + break; + } + len -= ck.len + (ck.len & 1); + dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); + list = (list_t *) list_buf->str; + chunk = 0; + } + dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); + list = (list_t *) list_buf->str; +} + +static list_t * +read_list (d_chunk_t *ck, QFile *f, int len) +{ + d_chunk_t *chunk = 0; + dstring_t *list_buf; + list_t *list; + int r; + + list_buf = dstring_new (); + list_buf->size = sizeof (list_t); + dstring_adjust (list_buf); + list = (list_t *)list_buf->str; + list->ck = *ck; + + len -= Qread (f, list->name, sizeof (list->name)); + while (len) { + SWITCH (list->name) { + case CASE ('I','N','F','O'): + { + data_t *data = malloc (sizeof (data_t)); + chunk = &data->ck; + r = Qread (f, &data->ck, sizeof (data->ck)); + if (!r) { + len = 0; + break; + } + len -= r; + SWITCH (data->ck.name) { + case CASE ('I','C','R','D'): + case CASE ('I','S','F','T'): + data->data = read_string (f, data->ck.len); + break; + default: + data->data = read_data (f, data->ck.len); + break; + } + len -= data->ck.len + (data->ck.len & 1); + } + break; + case CASE ('a','d','t','l'): + read_adtl (list_buf, f, len); + len = 0; + break; + default: + { + data_t *data = malloc (sizeof (data_t)); + Qread (f, &data->ck, sizeof (data->ck)); + data->data = read_data (f, data->ck.len); + len -= data->ck.len + sizeof (data->ck); + chunk = &data->ck; + } + len = 0; + break; + } + if (chunk) { + dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); + list = (list_t *) list_buf->str; + } + chunk = 0; + } + dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); + list = (list_t *) list_buf->str; + free (list_buf); + return list; +} + +static d_cue_t * +read_cue (QFile *f, int len) +{ + d_cue_t *cue = malloc (len); + + Qread (f, cue, len); + + return cue; +} + +list_t * +riff_read (QFile *f) +{ + dstring_t *riff_buf; + list_t *riff; + d_chunk_t *chunk = 0; + d_chunk_t ck; + int file_len, len; + + riff_buf = dstring_new (); + riff_buf->size = sizeof (list_t); + dstring_adjust (riff_buf); + riff = (list_t *)riff_buf->str; + + Qseek (f, 0, SEEK_END); + file_len = Qtell (f); + Qseek (f, 0, SEEK_SET); + + Qread (f, &riff->ck, sizeof (riff->ck)); + Qread (f, riff->name, sizeof (riff->name)); + while (Qread (f, &ck, sizeof (ck))) { + if (ck.len < 0x80000000) + len = ck.len; + else + len = file_len - Qtell (f); + SWITCH (ck.name) { + case CASE ('c','u','e',' '): + { + cue_t *cue = malloc (sizeof (cue_t)); + cue->ck = ck; + cue->cue = read_cue (f, len); + chunk = &cue->ck; + } + break; + case CASE ('L','I','S','T'): + { + list_t *list; + list = read_list (&ck, f, len); + chunk = &list->ck; + } + break; + default: + { + data_t *data = malloc (sizeof (data_t)); + data->ck = ck; + data->data = read_data (f, len); + chunk = &data->ck; + } + break; + } + dstring_append (riff_buf, (char *)&chunk, sizeof (chunk)); + riff = (list_t *) riff_buf->str; + chunk = 0; + } + dstring_append (riff_buf, (char *)&chunk, sizeof (chunk)); + riff = (list_t *) riff_buf->str; + free (riff_buf); + return riff; +} + +static void +free_adtl (d_chunk_t *adtl) +{ + ltxt_t *ltxt; + label_t *label; + data_t *data; + + //printf (" %.4s\n", adtl->name); + SWITCH (adtl->name) { + case CASE ('l','t','x','t'): + ltxt = (ltxt_t *) adtl; + /*printf (" %d %d %4s %d %d %d %d\n", + ltxt->ltxt.name, + ltxt->ltxt.len, + ltxt->ltxt.purpose, + ltxt->ltxt.country, + ltxt->ltxt.language, + ltxt->ltxt.dialect, + ltxt->ltxt.codepage);*/ + free (ltxt); + break; + case CASE ('l','a','b','l'): + case CASE ('n','o','t','e'): + label = (label_t *) adtl; + //printf (" %-8d %s\n", label->ofs, label->label); + free (label->label); + free (label); + break; + default: + data = (data_t *) adtl; + free (data->data); + free (data); + break; + } +} + +static void +free_list (list_t *list) +{ + d_chunk_t **ck; + data_t *data; + + //printf (" %.4s\n", list->name); + for (ck = list->chunks; *ck; ck++) { + SWITCH (list->name) { + case CASE ('I','N','F','O'): + data = (data_t *) *ck; + //printf (" %.4s\n", data->ck.name); + SWITCH (data->ck.name) { + case CASE ('I','C','R','D'): + case CASE ('I','S','F','T'): + //printf (" %s\n", data->data); + default: + free (data->data); + free (data); + break; + } + break; + case CASE ('a','d','t','l'): + free_adtl (*ck); + break; + default: + data = (data_t *) *ck; + free (data->data); + free (data); + break; + } + } + free (list); +} + +void +riff_free (list_t *riff) +{ + d_chunk_t **ck; + cue_t *cue; + list_t *list; + data_t *data; + + for (ck = riff->chunks; *ck; ck++) { + //printf ("%.4s\n", (*ck)->name); + SWITCH ((*ck)->name) { + case CASE ('c','u','e',' '): + cue = (cue_t *) *ck; + /*{ + int i; + for (i = 0; i < cue->cue->count; i++) { + printf (" %08x %d %.4s %d %d %d\n", + cue->cue->cue_points[i].name, + cue->cue->cue_points[i].position, + cue->cue->cue_points[i].chunk, + cue->cue->cue_points[i].chunk_start, + cue->cue->cue_points[i].block_start, + cue->cue->cue_points[i].sample_offset); + } + }*/ + free (cue->cue); + free (cue); + break; + case CASE ('L','I','S','T'): + list = (list_t *) *ck; + free_list (list); + break; + default: + data = (data_t *) *ck; + free (data->data); + free (data); + break; + } + } + free (riff); +} diff --git a/tools/wav/qfwavinfo.c b/tools/wav/qfwavinfo.c index 52316a5b2..a2bc6f75c 100644 --- a/tools/wav/qfwavinfo.c +++ b/tools/wav/qfwavinfo.c @@ -1,438 +1,25 @@ #include #include -#ifdef _WIN32 -void *alloca(size_t size); -#endif - #include "QF/dstring.h" - -typedef struct d_chunk_s { - unsigned char name[4]; - unsigned len; -} d_chunk_t; - -typedef struct d_cue_point_s { - unsigned name; - unsigned position; - char chunk[4]; - unsigned chunk_start; - unsigned block_start; - unsigned sample_offset; -} d_cue_point_t; - -typedef struct d_cue_s { - unsigned count; - d_cue_point_t cue_points[1]; -} d_cue_t; - -typedef struct d_format_s { - unsigned short format_tag; - unsigned short channels; - unsigned samples_pre_sec; - unsigned byte_per_sec; - unsigned short align; -} d_format_t; - -typedef struct d_ltxt_s { - unsigned name; - unsigned len; - char purpose[4]; - unsigned country; - unsigned language; - unsigned dialect; - unsigned codepage; - unsigned char data[0]; -} d_ltxt_t; - -typedef struct cue_s { - d_chunk_t ck; - d_cue_t *cue; -} cue_t; - -typedef struct format_s { - d_chunk_t ck; - d_format_t format; - char fdata[0]; -} format_t; - -typedef struct ltxt_s { - d_chunk_t ck; - d_ltxt_t ltxt; -} ltxt_t; - -typedef struct label_s { - d_chunk_t ck; - unsigned ofs; - char *label; -} label_t; - -typedef struct data_s { - d_chunk_t ck; - char *data; -} data_t; - -typedef struct list_s { - d_chunk_t ck; - char name[4]; - d_chunk_t *chunks[0]; -} list_t; - -#define SWITCH(name) switch (((name)[0] << 24) | ((name)[1] << 16) \ - | ((name)[2] << 8) | (name)[3]) -#define CASE(a,b,c,d) (((unsigned char)(a) << 24) \ - | ((unsigned char)(b) << 16) \ - | ((unsigned char)(c) << 8) \ - | (unsigned char)(d)) - -static char * -read_string (FILE *f, int len) -{ - char c[2] = {0, 0}; - char *s; - int l = len; - dstring_t *str = dstring_newstr (); - - while (l--) { - fread (c, 1, 1, f); - if (!c[0]) - break; - dstring_appendstr (str, c); - } - s = str->str; - free (str); - fseek (f, l + (len & 1), SEEK_CUR); - return s; -} - -static void * -read_data (FILE *f, int len) -{ - void *data = malloc (len); - - fread (data, 1, len, f); - fseek (f, len & 1, SEEK_CUR); - return data; -} - -static void -read_ltxt (FILE *f, int len, d_ltxt_t *ltxt) -{ - fread (ltxt, 1, len, f); -} - -static void -read_adtl (dstring_t *list_buf, FILE *f, int len) -{ - d_chunk_t ck, *chunk = 0; - ltxt_t *ltxt; - label_t *label; - data_t *data; - list_t *list; - int r; - - list = (list_t *) list_buf->str; - while (len) { - r = fread (&ck, 1, sizeof (ck), f); - if (!r) { - len = 0; - break; - } - len -= r; - SWITCH (ck.name) { - case CASE ('l','t','x','t'): - ltxt = malloc (sizeof (ltxt_t)); - ltxt->ck = ck; - read_ltxt (f, ck.len, <xt->ltxt); - chunk = <xt->ck; - break; - case CASE ('l','a','b','l'): - case CASE ('n','o','t','e'): - label = malloc (sizeof (label_t)); - label->ck = ck; - fread (&label->ofs, 1, 4, f); - label->label = read_string (f, ck.len - 4); - chunk = &label->ck; - break; - default: - data = malloc (sizeof (data)); - data->ck = ck; - data->data = read_data (f, ck.len); - chunk = &data->ck; - break; - } - len -= ck.len + (ck.len & 1); - dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); - list = (list_t *) list_buf->str; - chunk = 0; - } - dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); - list = (list_t *) list_buf->str; -} - -static list_t * -read_list (d_chunk_t *ck, FILE *f, int len) -{ - d_chunk_t *chunk = 0; - dstring_t *list_buf; - list_t *list; - int r; - - list_buf = dstring_new (); - list_buf->size = sizeof (list_t); - dstring_adjust (list_buf); - list = (list_t *)list_buf->str; - list->ck = *ck; - - len -= fread (list->name, 1, sizeof (list->name), f); - while (len) { - SWITCH (list->name) { - case CASE ('I','N','F','O'): - { - data_t *data = malloc (sizeof (data_t)); - chunk = &data->ck; - r = fread (&data->ck, 1, sizeof (data->ck), f); - if (!r) { - len = 0; - break; - } - len -= r; - SWITCH (data->ck.name) { - case CASE ('I','C','R','D'): - case CASE ('I','S','F','T'): - data->data = read_string (f, data->ck.len); - break; - default: - data->data = read_data (f, data->ck.len); - break; - } - len -= data->ck.len + (data->ck.len & 1); - } - break; - case CASE ('a','d','t','l'): - read_adtl (list_buf, f, len); - len = 0; - break; - default: - { - data_t *data = malloc (sizeof (data_t)); - fread (&data->ck, 1, sizeof (data->ck), f); - data->data = read_data (f, data->ck.len); - len -= data->ck.len + sizeof (data->ck); - chunk = &data->ck; - } - len = 0; - break; - } - if (chunk) { - dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); - list = (list_t *) list_buf->str; - } - chunk = 0; - } - dstring_append (list_buf, (char *)&chunk, sizeof (chunk)); - list = (list_t *) list_buf->str; - free (list_buf); - return list; -} - -static d_cue_t * -read_cue (FILE *f, int len) -{ - d_cue_t *cue = malloc (len); - - fread (cue, 1, len, f); - - return cue; -} - -static list_t * -riff_read (const char *filename) -{ - dstring_t *riff_buf; - list_t *riff = 0; - d_chunk_t *chunk = 0; - FILE *f = fopen (filename, "rb"); - d_chunk_t ck; - int file_len, len; - - if (f) { - riff_buf = dstring_new (); - riff_buf->size = sizeof (list_t); - dstring_adjust (riff_buf); - riff = (list_t *)riff_buf->str; - - fseek (f, 0, SEEK_END); - file_len = ftell (f); - fseek (f, 0, SEEK_SET); - - fread (&riff->ck, 1, sizeof (riff->ck), f); - fread (riff->name, 1, sizeof (riff->name), f); - while (fread (&ck, 1, sizeof (ck), f)) { - if (ck.len < 0x80000000) - len = ck.len; - else - len = file_len - ftell (f); - SWITCH (ck.name) { - case CASE ('c','u','e',' '): - { - cue_t *cue = malloc (sizeof (cue_t)); - cue->ck = ck; - cue->cue = read_cue (f, len); - chunk = &cue->ck; - } - break; - case CASE ('L','I','S','T'): - { - list_t *list; - list = read_list (&ck, f, len); - chunk = &list->ck; - } - break; - default: - { - data_t *data = malloc (sizeof (data_t)); - data->ck = ck; - data->data = read_data (f, len); - chunk = &data->ck; - } - break; - } - dstring_append (riff_buf, (char *)&chunk, sizeof (chunk)); - riff = (list_t *) riff_buf->str; - chunk = 0; - } - dstring_append (riff_buf, (char *)&chunk, sizeof (chunk)); - riff = (list_t *) riff_buf->str; - fclose (f); - free (riff_buf); - } - return riff; -} - -static void -free_adtl (d_chunk_t *adtl) -{ - ltxt_t *ltxt; - label_t *label; - data_t *data; - - //printf (" %.4s\n", adtl->name); - SWITCH (adtl->name) { - case CASE ('l','t','x','t'): - ltxt = (ltxt_t *) adtl; - /*printf (" %d %d %4s %d %d %d %d\n", - ltxt->ltxt.name, - ltxt->ltxt.len, - ltxt->ltxt.purpose, - ltxt->ltxt.country, - ltxt->ltxt.language, - ltxt->ltxt.dialect, - ltxt->ltxt.codepage);*/ - free (ltxt); - break; - case CASE ('l','a','b','l'): - case CASE ('n','o','t','e'): - label = (label_t *) adtl; - //printf (" %-8d %s\n", label->ofs, label->label); - free (label->label); - free (label); - break; - default: - data = (data_t *) adtl; - free (data->data); - free (data); - break; - } -} - -static void -free_list (list_t *list) -{ - d_chunk_t **ck; - data_t *data; - - //printf (" %.4s\n", list->name); - for (ck = list->chunks; *ck; ck++) { - SWITCH (list->name) { - case CASE ('I','N','F','O'): - data = (data_t *) *ck; - //printf (" %.4s\n", data->ck.name); - SWITCH (data->ck.name) { - case CASE ('I','C','R','D'): - case CASE ('I','S','F','T'): - //printf (" %s\n", data->data); - default: - free (data->data); - free (data); - break; - } - break; - case CASE ('a','d','t','l'): - free_adtl (*ck); - break; - default: - data = (data_t *) *ck; - free (data->data); - free (data); - break; - } - } - free (list); -} - -static void -riff_free (list_t *riff) -{ - d_chunk_t **ck; - cue_t *cue; - list_t *list; - data_t *data; - - for (ck = riff->chunks; *ck; ck++) { - //printf ("%.4s\n", (*ck)->name); - SWITCH ((*ck)->name) { - case CASE ('c','u','e',' '): - cue = (cue_t *) *ck; - /*{ - int i; - for (i = 0; i < cue->cue->count; i++) { - printf (" %08x %d %.4s %d %d %d\n", - cue->cue->cue_points[i].name, - cue->cue->cue_points[i].position, - cue->cue->cue_points[i].chunk, - cue->cue->cue_points[i].chunk_start, - cue->cue->cue_points[i].block_start, - cue->cue->cue_points[i].sample_offset); - } - }*/ - free (cue->cue); - free (cue); - break; - case CASE ('L','I','S','T'): - list = (list_t *) *ck; - free_list (list); - break; - default: - data = (data_t *) *ck; - free (data->data); - free (data); - break; - } - } - free (riff); -} +#include "QF/riff.h" int main (int argc, char **argv) { while (*++argv) { - list_t *riff = riff_read (*argv); + QFile *f; + list_t *riff = 0; d_chunk_t **ck; int sample_start, sample_count; - - if (!riff) { +puts (*argv); + f = Qopen (*argv, "rbz"); + if (f) { + riff = riff_read (f); + Qclose (f); + } + if (!f || !riff) { fprintf (stderr, "couldn't read %s\n", *argv); continue; }