aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Alc/midi/base.h9
-rw-r--r--Alc/midi/sf2load.c136
2 files changed, 94 insertions, 51 deletions
diff --git a/Alc/midi/base.h b/Alc/midi/base.h
index 42a4c279..157f2399 100644
--- a/Alc/midi/base.h
+++ b/Alc/midi/base.h
@@ -17,8 +17,13 @@ typedef struct Reader {
void *ptr;
int error;
} Reader;
-#define READ(x_, buf_, len_) ((x_)->cb((buf_), (len_), (x_)->ptr))
-#define READERR(x_) ((x_)->error)
+inline size_t Reader_read(Reader *self, void *buf, size_t len)
+{
+ size_t got = (!self->error) ? self->cb(buf, len, self->ptr) : 0;
+ if(got < len) self->error = 1;
+ return got;
+}
+#define READERR(x_) ((x_)->error)
ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context);
diff --git a/Alc/midi/sf2load.c b/Alc/midi/sf2load.c
index b32319b3..0245e27e 100644
--- a/Alc/midi/sf2load.c
+++ b/Alc/midi/sf2load.c
@@ -12,34 +12,27 @@
#include "midi/base.h"
+extern inline size_t Reader_read(Reader *self, void *buf, size_t len);
+
static ALuint read_le32(Reader *stream)
{
ALubyte buf[4];
- if(READ(stream, buf, 4) != 4)
- {
- READERR(stream) = 1;
+ if(Reader_read(stream, buf, 4) != 4)
return 0;
- }
return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
}
static ALushort read_le16(Reader *stream)
{
ALubyte buf[2];
- if(READ(stream, buf, 2) != 2)
- {
- READERR(stream) = 1;
+ if(Reader_read(stream, buf, 2) != 2)
return 0;
- }
return (buf[1]<<8) | buf[0];
}
static ALubyte read_8(Reader *stream)
{
ALubyte buf[1];
- if(READ(stream, buf, 1) != 1)
- {
- READERR(stream) = 1;
+ if(Reader_read(stream, buf, 1) != 1)
return 0;
- }
return buf[0];
}
static void skip(Reader *stream, ALuint amt)
@@ -47,13 +40,7 @@ static void skip(Reader *stream, ALuint amt)
while(amt > 0 && !READERR(stream))
{
char buf[4096];
- size_t got;
-
- got = READ(stream, buf, minu(sizeof(buf), amt));
- if(got == 0 || got > amt)
- READERR(stream) = 1;
-
- amt -= (ALuint)got;
+ amt -= Reader_read(stream, buf, minu(sizeof(buf), amt));
}
}
@@ -167,8 +154,7 @@ typedef struct PresetHeader {
} PresetHeader;
static void PresetHeader_read(PresetHeader *self, Reader *stream)
{
- if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
- READERR(stream) = 1;
+ Reader_read(stream, self->mName, sizeof(self->mName));
self->mPreset = read_le16(stream);
self->mBank = read_le16(stream);
self->mZoneIdx = read_le16(stream);
@@ -183,13 +169,12 @@ typedef struct InstrumentHeader {
} InstrumentHeader;
static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream)
{
- if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
- READERR(stream) = 1;
+ Reader_read(stream, self->mName, sizeof(self->mName));
self->mZoneIdx = read_le16(stream);
}
typedef struct SampleHeader {
- ALchar mName[20]; // 20 bytes
+ ALchar mName[20];
ALuint mStart;
ALuint mEnd;
ALuint mStartloop;
@@ -202,8 +187,7 @@ typedef struct SampleHeader {
} SampleHeader;
static void SampleHeader_read(SampleHeader *self, Reader *stream)
{
- if(READ(stream, self->mName, sizeof(self->mName)) != sizeof(self->mName))
- READERR(stream) = 1;
+ Reader_read(stream, self->mName, sizeof(self->mName));
self->mStart = read_le32(stream);
self->mEnd = read_le32(stream);
self->mStartloop = read_le32(stream);
@@ -976,6 +960,22 @@ static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCco
GenModList_Destruct(&gzone);
}
+static size_t printStringChunk(Reader *stream, const RiffHdr *chnk, const char *title)
+{
+ size_t len = 0;
+ if(chnk->mSize == 0 || (chnk->mSize&1))
+ ERR("Invalid %c%c%c%c size: %d\n", FOURCCARGS(chnk->mCode), chnk->mSize);
+ else
+ {
+ char *str = calloc(1, chnk->mSize+1);
+ len = Reader_read(stream, str, chnk->mSize);
+
+ TRACE("%s: %s\n", title, str);
+ free(str);
+ }
+ return len;
+}
+
ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
{
ALsfpreset **presets = NULL;
@@ -1006,21 +1006,37 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
list.mSize -= 4;
while(list.mSize > 0 && !READERR(stream))
{
- RiffHdr info;
+ RiffHdr chnk;
- RiffHdr_read(&info, stream);
+ if(list.mSize < 8)
+ {
+ WARN("Unexpected end of INFO list (%u extra bytes)\n", list.mSize);
+ skip(stream, list.mSize);
+ list.mSize = 0;
+ break;
+ }
+
+ RiffHdr_read(&chnk, stream);
list.mSize -= 8;
- if(info.mCode == FOURCC('i','f','i','l'))
+ if(list.mSize < chnk.mSize)
+ {
+ WARN("INFO sub-chunk '%c%c%c%c' has %u bytes, but only %u bytes remain\n",
+ FOURCCARGS(chnk.mCode), chnk.mSize, list.mSize);
+ skip(stream, list.mSize);
+ list.mSize = 0;
+ break;
+ }
+ list.mSize -= chnk.mSize;
+
+ if(chnk.mCode == FOURCC('i','f','i','l'))
{
- if(info.mSize != 4)
- ERR("Invalid ifil chunk size: %d\n", info.mSize);
+ if(chnk.mSize != 4)
+ ERR("Invalid ifil chunk size: %d\n", chnk.mSize);
else
{
ALushort major = read_le16(stream);
ALushort minor = read_le16(stream);
-
- list.mSize -= 4;
- info.mSize -= 4;
+ chnk.mSize -= 4;
if(major != 2)
ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor);
@@ -1029,26 +1045,48 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
sfont.ifil = (major<<16) | minor;
}
}
- else if(info.mCode == FOURCC('i','r','o','m'))
+ else if(chnk.mCode == FOURCC('i','r','o','m'))
{
- if(info.mSize == 0 || (info.mSize&1))
- ERR("Invalid irom size: %d\n", info.mSize);
+ if(chnk.mSize == 0 || (chnk.mSize&1))
+ ERR("Invalid irom size: %d\n", chnk.mSize);
else
{
free(sfont.irom);
- sfont.irom = calloc(1, info.mSize+1);
- READ(stream, sfont.irom, info.mSize);
-
- list.mSize -= info.mSize;
- info.mSize -= info.mSize;
+ sfont.irom = calloc(1, chnk.mSize+1);
+ chnk.mSize -= Reader_read(stream, sfont.irom, chnk.mSize);
TRACE("SF2 ROM ID: %s\n", sfont.irom);
}
}
else
- TRACE("Skipping INFO sub-chunk '%c%c%c%c' (%u bytes)\n", FOURCCARGS(info.mCode), info.mSize);
- list.mSize -= info.mSize;
- skip(stream, info.mSize);
+ {
+ static const struct {
+ ALuint code;
+ char title[16];
+ } listinfos[] = {
+ { FOURCC('i','s','n','g'), "Engine ID" },
+ { FOURCC('I','N','A','M'), "Name" },
+ { FOURCC('I','C','R','D'), "Creation Date" },
+ { FOURCC('I','E','N','G'), "Creator" },
+ { FOURCC('I','P','R','D'), "Product ID" },
+ { FOURCC('I','C','O','P'), "Copyright" },
+ { FOURCC('I','C','M','T'), "Comment" },
+ { FOURCC('I','S','F','T'), "Created With" },
+ { 0, "" },
+ };
+
+ for(i = 0;listinfos[i].code;i++)
+ {
+ if(listinfos[i].code == chnk.mCode)
+ {
+ chnk.mSize -= printStringChunk(stream, &chnk, listinfos[i].title);
+ break;
+ }
+ }
+ if(!listinfos[i].code)
+ TRACE("Skipping INFO sub-chunk '%c%c%c%c' (%u bytes)\n", FOURCCARGS(chnk.mCode), chnk.mSize);
+ }
+ skip(stream, chnk.mSize);
}
if(READERR(stream) != 0)
@@ -1074,17 +1112,18 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
if(smpl.mSize > list.mSize)
ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n");
+ list.mSize -= smpl.mSize;
buffer = NewBuffer(context);
if(!buffer)
SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error);
- /* Sample rate it unimportant, the individual fontsounds will specify it. */
+ /* Sample rate is unimportant, the individual fontsounds will specify it. */
if((err=LoadData(buffer, 22050, AL_MONO16_SOFT, smpl.mSize/2, UserFmtMono, UserFmtShort, NULL, 1, AL_FALSE)) != AL_NO_ERROR)
SET_ERROR_AND_GOTO(context, err, error);
ptr = buffer->data;
if(IS_LITTLE_ENDIAN)
- READ(stream, ptr, smpl.mSize);
+ smpl.mSize -= Reader_read(stream, ptr, smpl.mSize);
else
{
ALuint total = 0;
@@ -1094,14 +1133,13 @@ ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context)
ALuint todo = minu(smpl.mSize-total, sizeof(buf));
ALuint i;
- READ(stream, buf, todo);
+ smpl.mSize -= Reader_read(stream, buf, todo);
for(i = 0;i < todo;i++)
ptr[total+i] = buf[i^1];
total += todo;
}
}
- list.mSize -= smpl.mSize;
skip(stream, list.mSize);
}