mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-29 23:52:22 +00:00
move the riff reading code into libQFutil
This commit is contained in:
parent
39886ebb18
commit
e937fecdc1
4 changed files with 511 additions and 424 deletions
118
include/QF/riff.h
Normal file
118
include/QF/riff.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
riff.h
|
||||||
|
|
||||||
|
riff wav file handling
|
||||||
|
|
||||||
|
Copyright (C) 2003 Bill Currie
|
||||||
|
|
||||||
|
Author: Bill Currie <bill@taniwha.org>
|
||||||
|
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
|
|
@ -29,7 +29,8 @@ libQFutil_la_SOURCES= \
|
||||||
bspfile.c buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c \
|
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 \
|
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 \
|
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)
|
wad.c zone.c $(fnmatch)
|
||||||
|
|
||||||
EXTRA_DIST= $(asm_src) $(fnmatch_src)
|
EXTRA_DIST= $(asm_src) $(fnmatch_src)
|
||||||
|
|
381
libs/util/riff.c
Normal file
381
libs/util/riff.c
Normal file
|
@ -0,0 +1,381 @@
|
||||||
|
/*
|
||||||
|
riff.c
|
||||||
|
|
||||||
|
riff wav handling
|
||||||
|
|
||||||
|
Copyright (C) 2003 Bill Currie
|
||||||
|
|
||||||
|
Author: Bill Currie <bill@taniwha.org>
|
||||||
|
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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
|
@ -1,438 +1,25 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
void *alloca(size_t size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "QF/dstring.h"
|
#include "QF/dstring.h"
|
||||||
|
#include "QF/riff.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
while (*++argv) {
|
while (*++argv) {
|
||||||
list_t *riff = riff_read (*argv);
|
QFile *f;
|
||||||
|
list_t *riff = 0;
|
||||||
d_chunk_t **ck;
|
d_chunk_t **ck;
|
||||||
int sample_start, sample_count;
|
int sample_start, sample_count;
|
||||||
|
puts (*argv);
|
||||||
if (!riff) {
|
f = Qopen (*argv, "rbz");
|
||||||
|
if (f) {
|
||||||
|
riff = riff_read (f);
|
||||||
|
Qclose (f);
|
||||||
|
}
|
||||||
|
if (!f || !riff) {
|
||||||
fprintf (stderr, "couldn't read %s\n", *argv);
|
fprintf (stderr, "couldn't read %s\n", *argv);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue