From 496f7870f8ac7ad497f3baa36bcf86b127d3f1ba Mon Sep 17 00:00:00 2001 From: Chris Moeller Date: Tue, 8 Apr 2014 18:06:00 -0700 Subject: [PATCH] ft2play is now safe for use on big endian machines --- Frameworks/modplay/modplay/ft2play.c | 92 +++++++++++++++++++++++++--- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/Frameworks/modplay/modplay/ft2play.c b/Frameworks/modplay/modplay/ft2play.c index e80e93904..35e068540 100644 --- a/Frameworks/modplay/modplay/ft2play.c +++ b/Frameworks/modplay/modplay/ft2play.c @@ -38,6 +38,9 @@ typedef signed long ssize_t; #endif +#undef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) + #define USE_VOL_RAMP enum { _soundBufferSize = 512 }; @@ -409,6 +412,7 @@ typedef struct static MEM *mopen(const uint8_t *src, size_t length); static void mclose(MEM *buf); static size_t mread(void *buffer, size_t size, size_t count, MEM *buf); +static size_t mread_swap(void *buffer, size_t size, size_t count, MEM *buf, uint8_t le_xor, uint8_t be_xor); static int32_t meof(MEM *buf); static void mseek(MEM *buf, ssize_t offset, int32_t whence); static void setSamplesPerFrame(PLAYER *, uint32_t val); @@ -2319,17 +2323,31 @@ static int8_t AllocateInstr(PLAYER *pl, uint16_t i) static int8_t LoadInstrHeader(PLAYER *p, MEM *f, uint16_t i) { uint8_t j; + uint16_t k; InstrHeaderTyp ih; - + size_t size; + memset(&ih, 0, InstrHeaderSize); - mread(&ih.InstrSize, 4, 1, f); + mread_swap(&ih.InstrSize, 4, 1, f, 0, 3); if ((ih.InstrSize <= 0) || (ih.InstrSize > InstrHeaderSize)) ih.InstrSize = InstrHeaderSize; - mread(ih.Name, ih.InstrSize - 4, 1, f); + size = ih.InstrSize - 4; + + mread(ih.Name, min(size, 22), 1, f); + if (size > 22) mread(&ih.Typ, min(size - 22, 1), 1, f); + if (size > 23) mread_swap(&ih.AntSamp, min(size - 23, 2), 1, f, 0, 1); + if (size > 25) mread_swap(&ih.SampleSize, min(size - 25, 4), 1, f, 0, 3); + if (size > 29) mread(&ih.TA, min(size - 29, 96), 1, f); + if (size > 125) mread_swap(&ih.EnvVP, min(size - 125, 96), 1, f, 0, 1); + if (size > 221) mread(&ih.EnvVPAnt, min(size - 221, 14), 1, f); + if (size > 235) mread_swap(&ih.FadeOut, min(size - 235, 2), 1, f, 0, 1); + if (size > 237) mread(&ih.MIDIOn, min(size - 237, 2), 1, f); + if (size > 239) mread_swap(&ih.MIDIProgram, min(size - 239, 4), 1, f, 0, 1); + if (size > 243) mread(&ih.Mute, min(size - 243, 16), 1, f); if (meof(f) || (ih.AntSamp > 32)) return (0); @@ -2340,7 +2358,11 @@ static int8_t LoadInstrHeader(PLAYER *p, MEM *f, uint16_t i) memcpy(p->Instr[i]->TA, ih.TA, ih.InstrSize); p->Instr[i]->AntSamp = ih.AntSamp; - mread(ih.Samp, ih.AntSamp * sizeof (SampleHeaderTyp), 1, f); + for (k = 0; k < ih.AntSamp; k++) + { + mread_swap(&ih.Samp[k].Len, 4, 3, f, 0, 3); + mread(&ih.Samp[k].vol, 28, 1, f); + } if (meof(f)) return (0); for (j = 0; j < ih.AntSamp; ++j) @@ -2488,7 +2510,7 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f) for (i = 0; i < p->Song.AntPtn; ++i) { - mread(&ph.PatternHeaderSize, 4, 1, f); + mread_swap(&ph.PatternHeaderSize, 4, 1, f, 0, 3); mread(&ph.Typ, 1, 1, f); ph.PattLen = 0; @@ -2499,10 +2521,10 @@ static int8_t LoadPatterns(PLAYER *p, MEM *f) } else { - mread(&ph.PattLen, 2, 1, f); + mread_swap(&ph.PattLen, 2, 1, f, 0, 1); } - mread(&ph.DataLen, 2, 1, f); + mread_swap(&ph.DataLen, 2, 1, f, 0, 1); if (p->Song.Ver == 0x0102) mseek(f, ph.PatternHeaderSize - 8, SEEK_CUR); @@ -2589,7 +2611,11 @@ int8_t ft2play_LoadModule(void *_p, const uint8_t *buffer, size_t size) if (f == NULL) return (0); // start loading - mread(&h, sizeof (h), 1, f); + mread(&h.Sig, 58, 1, f); + mread_swap(&h.Ver, 2, 1, f, 0, 1); + mread_swap(&h.HeaderSize, 4, 1, f, 0, 3); + mread_swap(&h.Len, 2, 8, f, 0, 1); + mread(&h.SongTab, 256, 1, f); if ((memcmp(h.Sig, "Extended Module: ", 17) != 0) || (h.Ver < 0x0102) || (h.Ver > 0x104)) { @@ -3789,14 +3815,25 @@ void ft2play_PlaySong(void *_p, int32_t startOrder) p->playedOrder[startOrder / 8] = 1 << (startOrder % 8); } +static int mopen_is_big_endian; + static MEM *mopen(const uint8_t *src, size_t length) { MEM *b; + union + { + uint32_t a; + uint8_t b[4]; + } endian_test; + if ((src == NULL) || (length <= 0)) return (NULL); b = (MEM *)(malloc(sizeof (MEM))); if (b == NULL) return (NULL); + + endian_test.a = 1; + mopen_is_big_endian = endian_test.b[3]; b->_base = (uint8_t *)(src); b->_ptr = (uint8_t *)(src); @@ -3840,6 +3877,45 @@ static size_t mread(void *buffer, size_t size, size_t count, MEM *buf) return (pcnt / size); } +static size_t mread_swap(void *buffer, size_t size, size_t count, MEM *buf, uint8_t le_xor, uint8_t be_xor) +{ + size_t wrcnt; + ssize_t pcnt; + uint8_t xor; + + if (buf == NULL) return (0); + if (buf->_ptr == NULL) return (0); + + wrcnt = size * count; + if ((size == 0) || buf->_eof) return (0); + + xor = mopen_is_big_endian ? be_xor : le_xor; + + pcnt = (buf->_cnt > wrcnt) ? wrcnt : buf->_cnt; + + if ( !xor ) + memcpy(buffer, buf->_ptr, pcnt); + else + { + size_t i; + uint8_t * bbuffer = (uint8_t *) buffer; + for (i = 0; i < pcnt; i++) + bbuffer[i ^ xor] = buf->_ptr[i]; + } + + buf->_cnt -= pcnt; + buf->_ptr += pcnt; + + if (buf->_cnt <= 0) + { + buf->_ptr = buf->_base + buf->_bufsiz; + buf->_cnt = 0; + buf->_eof = 1; + } + + return (pcnt / size); +} + static int32_t meof(MEM *buf) { if (buf == NULL) return (1); // XXX: Should return a different value?