diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/helpers.c | 547 | ||||
-rw-r--r-- | Alc/hrtf.c | 49 |
2 files changed, 115 insertions, 481 deletions
diff --git a/Alc/helpers.c b/Alc/helpers.c index c98f121f..20cd8900 100644 --- a/Alc/helpers.c +++ b/Alc/helpers.c @@ -476,301 +476,69 @@ void al_print(const char *type, const char *func, const char *fmt, ...) static inline int is_slash(int c) { return (c == '\\' || c == '/'); } -static size_t strlenW(const WCHAR *str) -{ - const WCHAR *end = str; - while(*end) ++end; - return end-str; -} - -static const WCHAR *strchrW(const WCHAR *str, WCHAR ch) -{ - for(;*str != 0;++str) - { - if(*str == ch) - return str; - } - return NULL; -} - -static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch) -{ - const WCHAR *ret = NULL; - for(;*str != 0;++str) - { - if(*str == ch) - ret = str; - } - return ret; -} - -static const WCHAR *strstrW(const WCHAR *haystack, const WCHAR *needle) -{ - size_t len = strlenW(needle); - while(*haystack != 0) - { - if(CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - haystack, len, needle, len) == CSTR_EQUAL) - return haystack; - - do { - ++haystack; - } while(((*haystack)&0xC000) == 0x8000); - } - return NULL; -} - - -/* Compares the filename in the find data with the match string. The match - * string may contain the "%r" marker to signifiy a sample rate (really any - * positive integer), "%%" to signify a single '%', or "%s" for a (non-greedy) - * string. - */ -static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata) -{ - const WCHAR *name = fdata->cFileName; - int ret = 1; - - do { - const WCHAR *p = strchrW(match, '%'); - if(!p) - ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - match, -1, name, -1) == CSTR_EQUAL; - else - { - int len = p-match; - ret = lstrlenW(name) >= len; - if(ret) - ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, - match, len, name, len) == CSTR_EQUAL; - if(ret) - { - match += len; - name += len; - - ++p; - if(*p == 'r') - { - unsigned long l = 0; - while(*name >= '0' && *name <= '9') - { - l = l*10 + (*name-'0'); - ++name; - } - ret = l > 0; - ++p; - } - else if(*p == 's') - { - const WCHAR *next = p+1; - if(*next != '\0' && *next != '%') - { - const WCHAR *next_p = strchrW(next, '%'); - const WCHAR *m; - - if(!next_p) - m = strstrW(name, next); - else - { - WCHAR *tmp = malloc((next_p - next + 1) * 2); - memcpy(tmp, next, (next_p - next) * 2); - tmp[next_p - next] = 0; - - m = strstrW(name, tmp); - - free(tmp); - } - - ret = !!m; - if(ret) - { - size_t l; - if(next_p) l = next_p - next; - else l = strlenW(next); - - name = m + l; - next += l; - } - } - p = next; - } - } - } - - match = p; - } while(ret && match && *match); - - return ret; -} - -static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results) +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) { + al_string pathstr = AL_STRING_INIT_STATIC(); WIN32_FIND_DATAW fdata; - const WCHAR *sep, *p; + WCHAR *wpath; HANDLE hdl; - if(!match[0]) - return; - - /* Find the last directory separator and the next '%' marker in the match - * string. */ - sep = strrchrW(match, '\\'); - p = strchrW(match, '%'); - - /* If there's no separator, test the files in the specified path against - * the match string, and add the results. */ - if(!sep) - { - al_string pathstr = AL_STRING_INIT_STATIC(); - WCHAR *wpath; - - TRACE("Searching %s for %ls\n", path, match); - - al_string_append_cstr(&pathstr, path); - al_string_append_cstr(&pathstr, "\\*.*"); - wpath = FromUTF8(al_string_get_cstr(pathstr)); - - hdl = FindFirstFileW(wpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - size_t base = VECTOR_SIZE(*results); - do { - if(MatchFilter(match, &fdata)) - { - al_string str = AL_STRING_INIT_STATIC(); - al_string_copy_cstr(&str, path); - al_string_append_char(&str, '\\'); - al_string_append_wcstr(&str, fdata.cFileName); - TRACE("Got result %s\n", al_string_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); - } + al_string_copy_cstr(&pathstr, path); + al_string_append_cstr(&pathstr, "\\*"); + al_string_append_cstr(&pathstr, ext); - free(wpath); - al_string_deinit(&pathstr); + TRACE("Searching %s\n", al_string_get_cstr(pathstr)); - return; - } + wpath = FromUTF8(al_string_get_cstr(pathstr)); - /* If there's no '%' marker, or it's after the final separator, append the - * remaining directories to the path and recurse into it with the remaining - * filename portion. */ - if(!p || p-sep >= 0) + hdl = FindFirstFileW(wpath, &fdata); + if(hdl != INVALID_HANDLE_VALUE) { - al_string npath = AL_STRING_INIT_STATIC(); - al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '\\'); - al_string_append_wrange(&npath, match, sep); - - TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1); - RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); + size_t base = VECTOR_SIZE(*results); + do { + al_string str = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&str, path); + al_string_append_char(&str, '\\'); + al_string_append_wcstr(&str, fdata.cFileName); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); - al_string_deinit(&npath); - return; + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } - /* Look for the last separator before the '%' marker, and the first - * separator after it. */ - sep = strchrW(match, '\\'); - if(sep-p >= 0) sep = NULL; - for(;;) - { - const WCHAR *next = strchrW(sep?sep+1:match, '\\'); - if(next-p < 0) - { - al_string npath = AL_STRING_INIT_STATIC(); - WCHAR *nwpath, *nwmatch; - - /* Append up to the last directory before the one with a '%'. */ - al_string_copy_cstr(&npath, path); - if(sep) - { - al_string_append_char(&npath, '\\'); - al_string_append_wrange(&npath, match, sep); - } - al_string_append_cstr(&npath, "\\*.*"); - nwpath = FromUTF8(al_string_get_cstr(npath)); - - /* Take the directory name containing a '%' as a new string to - * match against. */ - if(!sep) - { - nwmatch = calloc(2, next-match+1); - memcpy(nwmatch, match, (next-match)*2); - } - else - { - nwmatch = calloc(2, next-(sep+1)+1); - memcpy(nwmatch, sep+1, (next-(sep+1))*2); - } - - /* For each matching directory name, recurse into it with the - * remaining string. */ - TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch); - hdl = FindFirstFileW(nwpath, &fdata); - if(hdl != INVALID_HANDLE_VALUE) - { - do { - if(MatchFilter(nwmatch, &fdata)) - { - al_string ndir = AL_STRING_INIT_STATIC(); - al_string_copy(&ndir, npath); - al_string_append_char(&ndir, '\\'); - al_string_append_wcstr(&ndir, fdata.cFileName); - TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1); - RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); - al_string_deinit(&ndir); - } - } while(FindNextFileW(hdl, &fdata)); - FindClose(hdl); - } - - free(nwmatch); - free(nwpath); - al_string_deinit(&npath); - break; - } - sep = next; - } + free(wpath); + al_string_deinit(&pathstr); } -vector_al_string SearchDataFiles(const char *match, const char *subdir) +vector_al_string SearchDataFiles(const char *ext, const char *subdir) { static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; static RefCount search_lock; vector_al_string results = VECTOR_INIT_STATIC(); - WCHAR *wmatch; size_t i; while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) althrd_yield(); - wmatch = FromUTF8(match); - if(!wmatch) - { - ERR("Failed to convert UTF-8 filename: \"%s\"\n", match); - return results; - } - for(i = 0;wmatch[i];++i) - { - if(wmatch[i] == '/') - wmatch[i] = '\\'; - } - /* If the path is absolute, use it directly. */ - if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2])) + if(isalpha(subdir[0]) && subdir[1] == ':' && is_slash(subdir[2])) { - char drv[3] = { (char)wmatch[0], ':', 0 }; - RecurseDirectorySearch(drv, wmatch+3, &results); + al_string path = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + + DirectorySearch(al_string_get_cstr(path), ext, &results); + + al_string_deinit(&path); } - else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\') - RecurseDirectorySearch("\\\\?", wmatch+4, &results); + else if(subdir[0] == '\\' && subdir[1] == '\\' && subdir[2] == '?' && subdir[3] == '\\') + DirectorySearch(subdir, ext, &results); else { al_string path = AL_STRING_INIT_STATIC(); @@ -801,7 +569,7 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) #define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + DirectorySearch(al_string_get_cstr(path), ext, &results); /* Search the local and global data dirs. */ for(i = 0;i < COUNTOF(ids);i++) @@ -817,14 +585,13 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) VECTOR_FOR_EACH(char, path, FIX_SLASH); #undef FIX_SLASH - RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + DirectorySearch(al_string_get_cstr(path), ext, &results); } } al_string_deinit(&path); } - free(wmatch); ATOMIC_STORE(&search_lock, 0); return results; @@ -877,192 +644,46 @@ void al_print(const char *type, const char *func, const char *fmt, ...) } -static int MatchFilter(const char *name, const char *match) -{ - int ret = 1; - - do { - const char *p = strchr(match, '%'); - if(!p) - ret = strcmp(match, name) == 0; - else - { - size_t len = p-match; - ret = strncmp(match, name, len) == 0; - if(ret) - { - match += len; - name += len; - - ++p; - if(*p == 'r') - { - char *end; - ret = strtoul(name, &end, 10) > 0; - if(ret) name = end; - ++p; - } - else if(*p == 's') - { - const char *next = p+1; - if(*next != '\0' && *next != '%') - { - const char *next_p = strchr(next, '%'); - const char *m; - - if(!next_p) - m = strstr(name, next); - else - { - char *tmp = malloc(next_p - next + 1); - memcpy(tmp, next, next_p - next); - tmp[next_p - next] = 0; - - m = strstr(name, tmp); - - free(tmp); - } - - ret = !!m; - if(ret) - { - size_t l; - if(next_p) l = next_p - next; - else l = strlen(next); - - name = m + l; - next += l; - } - } - p = next; - } - } - } - - match = p; - } while(ret && match && *match); - - return ret; -} - -static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results) +static void DirectorySearch(const char *path, const char *ext, vector_al_string *results) { - char *sep, *p; - - if(!match[0]) - return; - - sep = strrchr(match, '/'); - p = strchr(match, '%'); - - if(!sep) - { - DIR *dir; - - TRACE("Searching %s for %s\n", path?path:"/", match); - dir = opendir(path?path:"/"); - if(dir != NULL) - { - size_t base = VECTOR_SIZE(*results); - struct dirent *dirent; - while((dirent=readdir(dir)) != NULL) - { - al_string str; - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0 || - !MatchFilter(dirent->d_name, match)) - continue; - - AL_STRING_INIT(str); - if(path) al_string_copy_cstr(&str, path); - al_string_append_char(&str, '/'); - al_string_append_cstr(&str, dirent->d_name); - TRACE("Got result %s\n", al_string_get_cstr(str)); - VECTOR_PUSH_BACK(*results, str); - } - closedir(dir); - - if(VECTOR_SIZE(*results) > base) - qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, - sizeof(VECTOR_FRONT(*results)), StringSortCompare); - } - - return; - } - - if(!p || p-sep >= 0) - { - al_string npath = AL_STRING_INIT_STATIC(); - if(path) al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '/'); - al_string_append_range(&npath, match, sep); - - TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1); - RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); - - al_string_deinit(&npath); - return; - } + size_t extlen = strlen(ext); + DIR *dir; - sep = strchr(match, '/'); - if(sep-p >= 0) sep = NULL; - for(;;) + TRACE("Searching %s for *%s\n", path, ext); + dir = opendir(path); + if(dir != NULL) { - char *next = strchr(sep?sep+1:match, '/'); - if(next-p < 0) + size_t base = VECTOR_SIZE(*results); + struct dirent *dirent; + while((dirent=readdir(dir)) != NULL) { - al_string npath = AL_STRING_INIT_STATIC(); - al_string nmatch = AL_STRING_INIT_STATIC(); - const char *tomatch; - DIR *dir; - - if(!sep) - { - al_string_append_cstr(&npath, path?path:"/."); - tomatch = match; - } - else - { - if(path) al_string_append_cstr(&npath, path); - al_string_append_char(&npath, '/'); - al_string_append_range(&npath, match, sep); - - al_string_append_range(&nmatch, sep+1, next); - tomatch = al_string_get_cstr(nmatch); - } - - TRACE("Searching %s for %s\n", al_string_get_cstr(npath), tomatch); - dir = opendir(path?path:"/"); - if(dir != NULL) - { - al_string ndir = AL_STRING_INIT_STATIC(); - struct dirent *dirent; - - while((dirent=readdir(dir)) != NULL) - { - if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0 || - !MatchFilter(dirent->d_name, tomatch)) - continue; - al_string_copy(&ndir, npath); - al_string_append_char(&ndir, '/'); - al_string_append_cstr(&ndir, dirent->d_name); - TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1); - RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); - } - closedir(dir); - - al_string_deinit(&ndir); - } - - al_string_deinit(&nmatch); - al_string_deinit(&npath); - break; + al_string str; + size_t len; + if(strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) + continue; + + len = strlen(dirent->d_name); + if(!(len > extlen)) + continue; + if(strcasecmp(dirent->d_name+len-extlen, ext) != 0) + continue; + + AL_STRING_INIT(str); + al_string_copy_cstr(&str, path); + al_string_append_char(&str, '/'); + al_string_append_cstr(&str, dirent->d_name); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); } + closedir(dir); - sep = next; + if(VECTOR_SIZE(*results) > base) + qsort(VECTOR_ITER_BEGIN(*results)+base, VECTOR_SIZE(*results)-base, + sizeof(VECTOR_FRONT(*results)), StringSortCompare); } } -vector_al_string SearchDataFiles(const char *match, const char *subdir) +vector_al_string SearchDataFiles(const char *ext, const char *subdir) { static RefCount search_lock; vector_al_string results = VECTOR_INIT_STATIC(); @@ -1070,8 +691,8 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) althrd_yield(); - if(match[0] == '/') - RecurseDirectorySearch(NULL, match+1, &results); + if(subdir[0] == '/') + DirectorySearch(subdir, ext, &results); else { al_string path = AL_STRING_INIT_STATIC(); @@ -1080,29 +701,27 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) /* Search the app-local directory. */ if((str=getenv("ALSOFT_LOCAL_PATH")) && *str != '\0') - { - strncpy(cwdbuf, str, sizeof(cwdbuf)-1); - cwdbuf[sizeof(cwdbuf)-1] = '\0'; - } - else if(!getcwd(cwdbuf, sizeof(cwdbuf))) - strcpy(cwdbuf, "."); - RecurseDirectorySearch(cwdbuf, match, &results); + DirectorySearch(str, ext, &results); + else if(getcwd(cwdbuf, sizeof(cwdbuf))) + DirectorySearch(cwdbuf, ext, &results); + else + DirectorySearch(".", ext, &results); // Search local data dir if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') { - al_string_append_cstr(&path, str); + al_string_copy_cstr(&path, str); al_string_append_char(&path, '/'); al_string_append_cstr(&path, subdir); + DirectorySearch(al_string_get_cstr(path), ext, &results); } else if((str=getenv("HOME")) != NULL && str[0] != '\0') { - al_string_append_cstr(&path, str); + al_string_copy_cstr(&path, str); al_string_append_cstr(&path, "/.local/share/"); al_string_append_cstr(&path, subdir); + DirectorySearch(al_string_get_cstr(path), ext, &results); } - if(!al_string_empty(path)) - RecurseDirectorySearch(al_string_get_cstr(path), match, &results); // Search global data dirs if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') @@ -1125,7 +744,7 @@ vector_al_string SearchDataFiles(const char *match, const char *subdir) al_string_append_char(&path, '/'); al_string_append_cstr(&path, subdir); - RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + DirectorySearch(al_string_get_cstr(path), ext, &results); } } @@ -603,43 +603,58 @@ done: vector_HrtfEntry EnumerateHrtf(const_al_string devname) { vector_HrtfEntry list = VECTOR_INIT_STATIC(); - const char *fnamelist = "%s.mhr"; const char *defaulthrtf = ""; + const char *pathlist = ""; + bool usedefaults = true; - ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist); - while(fnamelist && *fnamelist) + if(ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf-paths", &pathlist)) { - while(isspace(*fnamelist) || *fnamelist == ',') - fnamelist++; - if(*fnamelist != '\0') + while(pathlist && *pathlist) { const char *next, *end; - next = strchr(fnamelist, ','); - if(!next) - end = fnamelist + strlen(fnamelist); - else + while(isspace(*pathlist) || *pathlist == ',') + pathlist++; + if(*pathlist == '\0') + continue; + + next = strchr(pathlist, ','); + if(next) end = next++; + else + { + end = pathlist + strlen(pathlist); + usedefaults = false; + } - while(end != fnamelist && isspace(*(end-1))) + while(end != pathlist && isspace(*(end-1))) --end; - if(end != fnamelist) + if(end != pathlist) { - al_string fname = AL_STRING_INIT_STATIC(); + al_string pname = AL_STRING_INIT_STATIC(); vector_al_string flist; - al_string_append_range(&fname, fnamelist, end); + al_string_append_range(&pname, pathlist, end); - flist = SearchDataFiles(al_string_get_cstr(fname), "openal/hrtf"); + flist = SearchDataFiles(".mhr", al_string_get_cstr(pname)); VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); VECTOR_DEINIT(flist); - al_string_deinit(&fname); + al_string_deinit(&pname); } - fnamelist = next; + pathlist = next; } } + else if(ConfigValueExists(al_string_get_cstr(devname), NULL, "hrtf_tables")) + ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n"); + + if(usedefaults) + { + vector_al_string flist = SearchDataFiles(".mhr", "openal/hrtf"); + VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); + VECTOR_DEINIT(flist); + } if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf)) { |