diff options
-rw-r--r-- | Alc/hrtf.c | 395 |
1 files changed, 134 insertions, 261 deletions
@@ -309,7 +309,7 @@ ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][ } -static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) +static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; @@ -320,21 +320,32 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) ALubyte *azCount = NULL; ALushort *evOffset = NULL; ALshort *coeffs = NULL; - ALubyte *delays = NULL; + const ALubyte *delays = NULL; ALuint i, j; - rate = fgetc(f); - rate |= fgetc(f)<<8; - rate |= fgetc(f)<<16; - rate |= fgetc(f)<<24; + if(datalen < 9) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", + al_string_get_cstr(filename), 9, datalen); + return NULL; + } + + rate = *(data++); + rate |= *(data++)<<8; + rate |= *(data++)<<16; + rate |= *(data++)<<24; + datalen -= 4; - irCount = fgetc(f); - irCount |= fgetc(f)<<8; + irCount = *(data++); + irCount |= *(data++)<<8; + datalen -= 2; - irSize = fgetc(f); - irSize |= fgetc(f)<<8; + irSize = *(data++); + irSize |= *(data++)<<8; + datalen -= 2; - evCount = fgetc(f); + evCount = *(data++); + datalen -= 1; if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { @@ -348,10 +359,16 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) evCount, MIN_EV_COUNT, MAX_EV_COUNT); failed = AL_TRUE; } - if(failed) return NULL; + if(datalen < evCount*2) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", + al_string_get_cstr(filename), evCount*2, datalen); + return NULL; + } + azCount = malloc(sizeof(azCount[0])*evCount); evOffset = malloc(sizeof(evOffset[0])*evCount); if(azCount == NULL || evOffset == NULL) @@ -362,12 +379,14 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) if(!failed) { - evOffset[0] = fgetc(f); - evOffset[0] |= fgetc(f)<<8; + evOffset[0] = *(data++); + evOffset[0] |= *(data++)<<8; + datalen -= 2; for(i = 1;i < evCount;i++) { - evOffset[i] = fgetc(f); - evOffset[i] |= fgetc(f)<<8; + evOffset[i] = *(data++); + evOffset[i] |= *(data++)<<8; + datalen -= 2; if(evOffset[i] <= evOffset[i-1]) { ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", @@ -402,8 +421,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) if(!failed) { coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) + if(coeffs == NULL) { ERR("Out of memory.\n"); failed = AL_TRUE; @@ -412,31 +430,38 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) if(!failed) { + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n", + al_string_get_cstr(filename), reqsize, datalen); + failed = AL_TRUE; + } + } + + if(!failed) + { for(i = 0;i < irCount*irSize;i+=irSize) { for(j = 0;j < irSize;j++) { - ALshort coeff; - coeff = fgetc(f); - coeff |= fgetc(f)<<8; - coeffs[i+j] = coeff; + coeffs[i+j] = *(data++); + coeffs[i+j] |= *(data++)<<8; + datalen -= 2; } } + + delays = data; + data += irCount; + datalen -= irCount; for(i = 0;i < irCount;i++) { - delays[i] = fgetc(f); if(delays[i] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); failed = AL_TRUE; } } - - if(feof(f)) - { - ERR("Premature end of data\n"); - failed = AL_TRUE; - } } if(!failed) @@ -478,31 +503,40 @@ static struct Hrtf *LoadHrtf00(FILE *f, const_al_string filename) free(azCount); free(evOffset); free(coeffs); - free(delays); return Hrtf; } -static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) +static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_string filename) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; ALboolean failed = AL_FALSE; ALuint rate = 0, irCount = 0; ALubyte irSize = 0, evCount = 0; - ALubyte *azCount = NULL; + const ALubyte *azCount = NULL; ALushort *evOffset = NULL; ALshort *coeffs = NULL; - ALubyte *delays = NULL; + const ALubyte *delays = NULL; ALuint i, j; - rate = fgetc(f); - rate |= fgetc(f)<<8; - rate |= fgetc(f)<<16; - rate |= fgetc(f)<<24; + if(datalen < 6) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", + al_string_get_cstr(filename), 6, datalen); + return NULL; + } + + rate = *(data++); + rate |= *(data++)<<8; + rate |= *(data++)<<16; + rate |= *(data++)<<24; + datalen -= 4; - irSize = fgetc(f); + irSize = *(data++); + datalen -= 1; - evCount = fgetc(f); + evCount = *(data++); + datalen -= 1; if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { @@ -516,11 +550,20 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) evCount, MIN_EV_COUNT, MAX_EV_COUNT); failed = AL_TRUE; } - if(failed) return NULL; - azCount = malloc(sizeof(azCount[0])*evCount); + if(datalen < evCount) + { + ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", + al_string_get_cstr(filename), evCount, datalen); + return NULL; + } + + azCount = data; + data += evCount; + datalen -= evCount; + evOffset = malloc(sizeof(evOffset[0])*evCount); if(azCount == NULL || evOffset == NULL) { @@ -532,7 +575,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) { for(i = 0;i < evCount;i++) { - azCount[i] = fgetc(f); if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) { ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", @@ -553,8 +595,7 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) } coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) + if(coeffs == NULL) { ERR("Out of memory.\n"); failed = AL_TRUE; @@ -563,31 +604,40 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) if(!failed) { + size_t reqsize = 2*irSize*irCount + irCount; + if(datalen < reqsize) + { + ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", + al_string_get_cstr(filename), reqsize, datalen); + failed = AL_TRUE; + } + } + + if(!failed) + { for(i = 0;i < irCount*irSize;i+=irSize) { for(j = 0;j < irSize;j++) { ALshort coeff; - coeff = fgetc(f); - coeff |= fgetc(f)<<8; + coeff = *(data++); + coeff |= *(data++)<<8; + datalen -= 2; coeffs[i+j] = coeff; } } + + delays = data; + data += irCount; + datalen -= irCount; for(i = 0;i < irCount;i++) { - delays[i] = fgetc(f); if(delays[i] > maxDelay) { ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); failed = AL_TRUE; } } - - if(feof(f)) - { - ERR("Premature end of data\n"); - failed = AL_TRUE; - } } if(!failed) @@ -626,10 +676,8 @@ static struct Hrtf *LoadHrtf01(FILE *f, const_al_string filename) memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); } - free(azCount); free(evOffset); free(coeffs); - free(delays); return Hrtf; } @@ -638,10 +686,9 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL }; struct Hrtf *hrtf = NULL; const HrtfEntry *iter; + struct FileMapping fmap; const char *name; const char *ext; - ALchar magic[8]; - FILE *f; int i; name = strrchr(al_string_get_cstr(*filename), '/'); @@ -670,31 +717,32 @@ static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) } TRACE("Loading %s...\n", al_string_get_cstr(*filename)); - f = al_fopen(al_string_get_cstr(*filename), "rb"); - if(f == NULL) + fmap = MapFileToMem(al_string_get_cstr(*filename)); + if(fmap.ptr == NULL) { ERR("Could not open %s\n", al_string_get_cstr(*filename)); goto done; } - if(fread(magic, 1, sizeof(magic), f) != sizeof(magic)) - ERR("Failed to read header from %s\n", al_string_get_cstr(*filename)); - else + if(fmap.len < sizeof(magicMarker01)) + ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), fmap.len); + else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0) { - if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - hrtf = LoadHrtf00(f, *filename); - } - else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - hrtf = LoadHrtf01(f, *filename); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), magic); + TRACE("Detected data set format v1\n"); + hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01), + fmap.len-sizeof(magicMarker01), *filename + ); } - fclose(f); + else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00), + fmap.len-sizeof(magicMarker00), *filename + ); + } + else + ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), (const char*)fmap.ptr); + UnmapFileMem(&fmap); if(!hrtf) { @@ -740,189 +788,8 @@ done: al_string_deinit(filename); } - -/* Unfortunate that we have to duplicate LoadHrtf01 like this, to take a memory - * buffer for input instead of a FILE*, but there's no portable way to access a - * memory buffer through the standard FILE* I/O API (POSIX 2008 has fmemopen, - * and Windows doesn't seem to have anything). - */ -static struct Hrtf *LoadBuiltInHrtf01(const ALubyte *data, size_t datalen, const_al_string filename) -{ - const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0, irCount = 0; - ALubyte irSize = 0, evCount = 0; - const ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALshort *coeffs = NULL; - const ALubyte *delays = NULL; - ALuint i, j; - - if(datalen < 6) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - al_string_get_cstr(filename), 6, datalen); - return NULL; - } - - rate = *(data++); - rate |= *(data++)<<8; - rate |= *(data++)<<16; - rate |= *(data++)<<24; - datalen -= 4; - - irSize = *(data++); - datalen -= 1; - - evCount = *(data++); - datalen -= 1; - - if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) - { - ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - if(failed) - return NULL; - - if(datalen < evCount) - { - ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", - al_string_get_cstr(filename), evCount, datalen); - return NULL; - } - - azCount = data; - data += evCount; - datalen -= evCount; - - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - for(i = 0;i < evCount;i++) - { - if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - if(coeffs == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - size_t reqsize = 2*irSize*irCount + irCount; - if(datalen < reqsize) - { - ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n", - al_string_get_cstr(filename), reqsize, datalen); - failed = AL_TRUE; - } - } - - if(!failed) - { - for(i = 0;i < irCount*irSize;i+=irSize) - { - for(j = 0;j < irSize;j++) - { - ALshort coeff; - coeff = *(data++); - coeff |= *(data++)<<8; - datalen -= 2; - coeffs[i+j] = coeff; - } - } - - delays = data; - data += irCount; - datalen -= irCount; - for(i = 0;i < irCount;i++) - { - if(delays[i] > maxDelay) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - size_t total = sizeof(struct Hrtf); - total += sizeof(azCount[0])*evCount; - total += sizeof(evOffset[0])*evCount; - total += sizeof(coeffs[0])*irSize*irCount; - total += sizeof(delays[0])*irCount; - total += al_string_length(filename)+1; - - Hrtf = al_calloc(16, total); - if(Hrtf == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->evCount = evCount; - Hrtf->azCount = ((ALubyte*)(Hrtf+1)); - Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount)); - Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount)); - Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount)); - Hrtf->filename = ((char*)(Hrtf->delays + irCount)); - Hrtf->next = NULL; - - memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount); - memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount); - memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount); - memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount); - memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1); - } - - free(evOffset); - free(coeffs); - return Hrtf; -} - -/* Another unfortunate duplication, this time of AddFileEntry to take a memory - * buffer for input instead of opening the given filename. +/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer + * for input instead of opening the given filename. */ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, al_string *filename) { @@ -961,9 +828,15 @@ static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); - hrtf = LoadBuiltInHrtf01( - data+sizeof(magicMarker01), datalen-sizeof(magicMarker01), - *filename + hrtf = LoadHrtf01(data+sizeof(magicMarker01), + datalen-sizeof(magicMarker01), *filename + ); + } + else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0) + { + TRACE("Detected data set format v0\n"); + hrtf = LoadHrtf00(data+sizeof(magicMarker00), + datalen-sizeof(magicMarker00), *filename ); } else |