mirror of
https://github.com/love2d/megasource.git
synced 2026-08-18 03:34:25 +02:00
Added missing changes to the OpenAL-Soft update.
This commit is contained in:
+669
-107
@@ -13,8 +13,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#ifdef HAVE_DIRENT_H
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#ifndef AL_NO_UID_DEFS
|
||||
#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H)
|
||||
@@ -55,10 +58,13 @@ DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6);
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
|
||||
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
|
||||
DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17);
|
||||
|
||||
#ifdef HAVE_MMDEVAPI
|
||||
#include <devpropdef.h>
|
||||
#include <propkeydef.h>
|
||||
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
|
||||
DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0);
|
||||
#endif
|
||||
#endif
|
||||
#endif /* AL_NO_UID_DEFS */
|
||||
@@ -82,7 +88,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
|
||||
#include <ieeefp.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_IE
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32_IE)
|
||||
#include <shlobj.h>
|
||||
#endif
|
||||
|
||||
@@ -144,8 +152,12 @@ void FillCPUCaps(ALuint capfilter)
|
||||
if((cpuinf[0].regs[3]&(1<<26)))
|
||||
{
|
||||
caps |= CPU_CAP_SSE2;
|
||||
if((cpuinf[0].regs[2]&(1<<19)))
|
||||
caps |= CPU_CAP_SSE4_1;
|
||||
if((cpuinf[0].regs[2]&(1<<0)))
|
||||
{
|
||||
caps |= CPU_CAP_SSE3;
|
||||
if((cpuinf[0].regs[2]&(1<<19)))
|
||||
caps |= CPU_CAP_SSE4_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,8 +200,12 @@ void FillCPUCaps(ALuint capfilter)
|
||||
if((cpuinf[0].regs[3]&(1<<26)))
|
||||
{
|
||||
caps |= CPU_CAP_SSE2;
|
||||
if((cpuinf[0].regs[2]&(1<<19)))
|
||||
caps |= CPU_CAP_SSE4_1;
|
||||
if((cpuinf[0].regs[2]&(1<<0)))
|
||||
{
|
||||
caps |= CPU_CAP_SSE3;
|
||||
if((cpuinf[0].regs[2]&(1<<19)))
|
||||
caps |= CPU_CAP_SSE4_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,13 +214,16 @@ void FillCPUCaps(ALuint capfilter)
|
||||
/* Assume support for whatever's supported if we can't check for it */
|
||||
#if defined(HAVE_SSE4_1)
|
||||
#warning "Assuming SSE 4.1 run-time support!"
|
||||
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1;
|
||||
caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
|
||||
#elif defined(HAVE_SSE3)
|
||||
#warning "Assuming SSE 3 run-time support!"
|
||||
caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
|
||||
#elif defined(HAVE_SSE2)
|
||||
#warning "Assuming SSE 2 run-time support!"
|
||||
capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2;
|
||||
caps |= CPU_CAP_SSE | CPU_CAP_SSE2;
|
||||
#elif defined(HAVE_SSE)
|
||||
#warning "Assuming SSE run-time support!"
|
||||
capfilter |= CPU_CAP_SSE;
|
||||
caps |= CPU_CAP_SSE;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_NEON
|
||||
@@ -212,9 +231,10 @@ void FillCPUCaps(ALuint capfilter)
|
||||
caps |= CPU_CAP_NEON;
|
||||
#endif
|
||||
|
||||
TRACE("Extensions:%s%s%s%s%s\n",
|
||||
TRACE("Extensions:%s%s%s%s%s%s\n",
|
||||
((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""),
|
||||
((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""),
|
||||
((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""),
|
||||
((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""),
|
||||
((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""),
|
||||
((!capfilter) ? " -none-" : "")
|
||||
@@ -240,7 +260,7 @@ void *al_malloc(size_t alignment, size_t size)
|
||||
if(ret != NULL)
|
||||
{
|
||||
*(ret++) = 0x00;
|
||||
while(((ALintptrEXT)ret&(alignment-1)) != 0)
|
||||
while(((ptrdiff_t)ret&(alignment-1)) != 0)
|
||||
*(ret++) = 0x55;
|
||||
}
|
||||
return ret;
|
||||
@@ -278,6 +298,8 @@ void SetMixerFPUMode(FPUCtl *ctl)
|
||||
#ifdef HAVE_FENV_H
|
||||
fegetenv(STATIC_CAST(fenv_t, ctl));
|
||||
#if defined(__GNUC__) && defined(HAVE_SSE)
|
||||
/* FIXME: Some fegetenv implementations can get the SSE environment too?
|
||||
* How to tell when it does? */
|
||||
if((CPUCapFlags&CPU_CAP_SSE))
|
||||
__asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state));
|
||||
#endif
|
||||
@@ -421,6 +443,390 @@ FILE *al_fopen(const char *fname, const char *mode)
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
void al_print(const char *type, const char *func, const char *fmt, ...)
|
||||
{
|
||||
char str[1024];
|
||||
WCHAR *wstr;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(str, sizeof(str), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
str[sizeof(str)-1] = 0;
|
||||
wstr = FromUTF8(str);
|
||||
if(!wstr)
|
||||
fprintf(LogFile, "AL lib: %s %s: <UTF-8 error> %s", type, func, str);
|
||||
else
|
||||
{
|
||||
fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr);
|
||||
free(wstr);
|
||||
wstr = NULL;
|
||||
}
|
||||
fflush(LogFile);
|
||||
}
|
||||
|
||||
|
||||
static inline int is_slash(int c)
|
||||
{ return (c == '\\' || c == '/'); }
|
||||
|
||||
FILE *OpenDataFile(const char *fname, const char *subdir)
|
||||
{
|
||||
static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
|
||||
WCHAR *wname=NULL, *wsubdir=NULL;
|
||||
FILE *f;
|
||||
size_t i;
|
||||
|
||||
wname = FromUTF8(fname);
|
||||
if(!wname)
|
||||
{
|
||||
ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If the path is absolute, open it directly. */
|
||||
if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2]))
|
||||
{
|
||||
f = _wfopen(wname, L"rb");
|
||||
if(f) TRACE("Opened %s\n", fname);
|
||||
else WARN("Could not open %s\n", fname);
|
||||
free(wname);
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Try the current directory first before the data directories. */
|
||||
if((f=_wfopen(wname, L"rb")) != NULL)
|
||||
{
|
||||
TRACE("Opened %s\n", fname);
|
||||
free(wname);
|
||||
return f;
|
||||
}
|
||||
|
||||
wsubdir = FromUTF8(subdir);
|
||||
if(!wsubdir)
|
||||
{
|
||||
ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
|
||||
free(wname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(i = 0;i < COUNTOF(ids);i++)
|
||||
{
|
||||
WCHAR buffer[PATH_MAX];
|
||||
size_t len;
|
||||
|
||||
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE)
|
||||
continue;
|
||||
|
||||
len = lstrlenW(buffer);
|
||||
if(len > 0 && is_slash(buffer[len-1]))
|
||||
buffer[--len] = '\0';
|
||||
_snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname);
|
||||
len = lstrlenW(buffer);
|
||||
while(len > 0)
|
||||
{
|
||||
--len;
|
||||
if(buffer[len] == '/')
|
||||
buffer[len] = '\\';
|
||||
}
|
||||
|
||||
if((f=_wfopen(buffer, L"rb")) != NULL)
|
||||
{
|
||||
al_string filepath = AL_STRING_INIT_STATIC();
|
||||
al_string_copy_wcstr(&filepath, buffer);
|
||||
TRACE("Opened %s\n", al_string_get_cstr(filepath));
|
||||
al_string_deinit(&filepath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(wname);
|
||||
free(wsubdir);
|
||||
|
||||
if(f == NULL)
|
||||
WARN("Could not open %s\\%s\n", subdir, fname);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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), or "%%" to signify a single '%'.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match = p;
|
||||
} while(ret && match && *match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results)
|
||||
{
|
||||
WIN32_FIND_DATAW fdata;
|
||||
const WCHAR *sep, *p;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
free(wpath);
|
||||
al_string_deinit(&pathstr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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);
|
||||
|
||||
al_string_deinit(&npath);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
vector_al_string SearchDataFiles(const char *match, 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]))
|
||||
{
|
||||
char drv[3] = { (char)wmatch[0], ':', 0 };
|
||||
RecurseDirectorySearch(drv, wmatch+3, &results);
|
||||
}
|
||||
else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\')
|
||||
RecurseDirectorySearch("\\\\?", wmatch+4, &results);
|
||||
else
|
||||
{
|
||||
al_string path = AL_STRING_INIT_STATIC();
|
||||
WCHAR *cwdbuf;
|
||||
|
||||
/* Search the CWD. */
|
||||
if(!(cwdbuf=_wgetcwd(NULL, 0)))
|
||||
al_string_copy_cstr(&path, ".");
|
||||
else
|
||||
{
|
||||
al_string_copy_wcstr(&path, cwdbuf);
|
||||
if(is_slash(VECTOR_BACK(path)))
|
||||
{
|
||||
VECTOR_POP_BACK(path);
|
||||
*VECTOR_ITER_END(path) = 0;
|
||||
}
|
||||
free(cwdbuf);
|
||||
}
|
||||
RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results);
|
||||
|
||||
/* Search the local and global data dirs. */
|
||||
for(i = 0;i < COUNTOF(ids);i++)
|
||||
{
|
||||
WCHAR buffer[PATH_MAX];
|
||||
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE)
|
||||
{
|
||||
al_string_copy_wcstr(&path, buffer);
|
||||
if(!is_slash(VECTOR_BACK(path)))
|
||||
al_string_append_char(&path, '\\');
|
||||
al_string_append_cstr(&path, 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);
|
||||
}
|
||||
}
|
||||
|
||||
al_string_deinit(&path);
|
||||
}
|
||||
|
||||
free(wmatch);
|
||||
ATOMIC_STORE(&search_lock, 0);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef HAVE_DLFCN_H
|
||||
@@ -453,9 +859,7 @@ void *GetSymbol(void *handle, const char *name)
|
||||
return sym;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_DLFCN_H */
|
||||
|
||||
void al_print(const char *type, const char *func, const char *fmt, ...)
|
||||
{
|
||||
@@ -469,76 +873,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...)
|
||||
fflush(LogFile);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static inline int is_slash(int c)
|
||||
{ return (c == '\\' || c == '/'); }
|
||||
|
||||
FILE *OpenDataFile(const char *fname, const char *subdir)
|
||||
{
|
||||
static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA };
|
||||
WCHAR *wname=NULL, *wsubdir=NULL;
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
/* If the path is absolute, open it directly. */
|
||||
if(fname[0] != '\0' && fname[1] == ':' && is_slash(fname[2]))
|
||||
{
|
||||
if((f=al_fopen(fname, "rb")) != NULL)
|
||||
{
|
||||
TRACE("Opened %s\n", fname);
|
||||
return f;
|
||||
}
|
||||
WARN("Could not open %s\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If it's relative, try the current directory first before the data directories. */
|
||||
if((f=al_fopen(fname, "rb")) != NULL)
|
||||
{
|
||||
TRACE("Opened %s\n", fname);
|
||||
return f;
|
||||
}
|
||||
WARN("Could not open %s\n", fname);
|
||||
|
||||
wname = FromUTF8(fname);
|
||||
wsubdir = FromUTF8(subdir);
|
||||
if(!wname)
|
||||
ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname);
|
||||
else if(!wsubdir)
|
||||
ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir);
|
||||
else for(i = 0;i < 2;i++)
|
||||
{
|
||||
WCHAR buffer[PATH_MAX];
|
||||
size_t len;
|
||||
|
||||
if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE)
|
||||
continue;
|
||||
|
||||
len = lstrlenW(buffer);
|
||||
if(len > 0 && is_slash(buffer[len-1]))
|
||||
buffer[--len] = '\0';
|
||||
_snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname);
|
||||
len = lstrlenW(buffer);
|
||||
while(len > 0)
|
||||
{
|
||||
--len;
|
||||
if(buffer[len] == '/')
|
||||
buffer[len] = '\\';
|
||||
}
|
||||
|
||||
if((f=_wfopen(buffer, L"rb")) != NULL)
|
||||
{
|
||||
TRACE("Opened %ls\n", buffer);
|
||||
return f;
|
||||
}
|
||||
WARN("Could not open %ls\n", buffer);
|
||||
}
|
||||
free(wname);
|
||||
free(wsubdir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
FILE *OpenDataFile(const char *fname, const char *subdir)
|
||||
{
|
||||
char buffer[PATH_MAX] = "";
|
||||
@@ -561,7 +896,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
|
||||
TRACE("Opened %s\n", fname);
|
||||
return f;
|
||||
}
|
||||
WARN("Could not open %s\n", fname);
|
||||
|
||||
if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
|
||||
snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname);
|
||||
@@ -574,7 +908,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
|
||||
TRACE("Opened %s\n", buffer);
|
||||
return f;
|
||||
}
|
||||
WARN("Could not open %s\n", buffer);
|
||||
}
|
||||
|
||||
if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0')
|
||||
@@ -605,11 +938,221 @@ FILE *OpenDataFile(const char *fname, const char *subdir)
|
||||
TRACE("Opened %s\n", buffer);
|
||||
return f;
|
||||
}
|
||||
WARN("Could not open %s\n", buffer);
|
||||
}
|
||||
WARN("Could not open %s/%s\n", subdir, fname);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static const char *MatchString;
|
||||
static int MatchFilter(const struct dirent *dir)
|
||||
{
|
||||
const char *match = MatchString;
|
||||
const char *name = dir->d_name;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match = p;
|
||||
} while(ret && match && *match);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
char *sep, *p;
|
||||
int n, i;
|
||||
|
||||
if(!match[0])
|
||||
return;
|
||||
|
||||
sep = strrchr(match, '/');
|
||||
p = strchr(match, '%');
|
||||
|
||||
if(!sep)
|
||||
{
|
||||
MatchString = match;
|
||||
TRACE("Searching %s for %s\n", path?path:"/", match);
|
||||
n = scandir(path?path:"/", &namelist, MatchFilter, alphasort);
|
||||
if(n >= 0)
|
||||
{
|
||||
for(i = 0;i < n;++i)
|
||||
{
|
||||
al_string str = AL_STRING_INIT_STATIC();
|
||||
if(path) al_string_copy_cstr(&str, path);
|
||||
al_string_append_char(&str, '/');
|
||||
al_string_append_cstr(&str, namelist[i]->d_name);
|
||||
TRACE("Got result %s\n", al_string_get_cstr(str));
|
||||
VECTOR_PUSH_BACK(*results, str);
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
sep = strchr(match, '/');
|
||||
if(sep-p >= 0) sep = NULL;
|
||||
for(;;)
|
||||
{
|
||||
char *next = strchr(sep?sep+1:match, '/');
|
||||
if(next-p < 0)
|
||||
{
|
||||
al_string npath = AL_STRING_INIT_STATIC();
|
||||
al_string nmatch = AL_STRING_INIT_STATIC();
|
||||
|
||||
if(!sep)
|
||||
{
|
||||
al_string_append_cstr(&npath, path?path:"/.");
|
||||
MatchString = 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);
|
||||
MatchString = al_string_get_cstr(nmatch);
|
||||
}
|
||||
|
||||
TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString);
|
||||
n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort);
|
||||
if(n >= 0)
|
||||
{
|
||||
al_string ndir = AL_STRING_INIT_STATIC();
|
||||
for(i = 0;i < n;++i)
|
||||
{
|
||||
al_string_copy(&ndir, npath);
|
||||
al_string_append_char(&ndir, '/');
|
||||
al_string_append_cstr(&ndir, namelist[i]->d_name);
|
||||
free(namelist[i]);
|
||||
TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1);
|
||||
RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results);
|
||||
}
|
||||
al_string_deinit(&ndir);
|
||||
free(namelist);
|
||||
}
|
||||
|
||||
al_string_deinit(&nmatch);
|
||||
al_string_deinit(&npath);
|
||||
break;
|
||||
}
|
||||
|
||||
sep = next;
|
||||
}
|
||||
}
|
||||
|
||||
vector_al_string SearchDataFiles(const char *match, const char *subdir)
|
||||
{
|
||||
static RefCount search_lock;
|
||||
vector_al_string results = VECTOR_INIT_STATIC();
|
||||
|
||||
while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1)
|
||||
althrd_yield();
|
||||
|
||||
if(match[0] == '/')
|
||||
RecurseDirectorySearch(NULL, match+1, &results);
|
||||
else
|
||||
{
|
||||
al_string path = AL_STRING_INIT_STATIC();
|
||||
const char *str, *next;
|
||||
char cwdbuf[PATH_MAX];
|
||||
|
||||
// Search CWD
|
||||
if(!getcwd(cwdbuf, sizeof(cwdbuf)))
|
||||
strcpy(cwdbuf, ".");
|
||||
RecurseDirectorySearch(cwdbuf, match, &results);
|
||||
|
||||
// Search local data dir
|
||||
if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0')
|
||||
{
|
||||
al_string_append_cstr(&path, str);
|
||||
al_string_append_char(&path, '/');
|
||||
al_string_append_cstr(&path, subdir);
|
||||
}
|
||||
else if((str=getenv("HOME")) != NULL && str[0] != '\0')
|
||||
{
|
||||
al_string_append_cstr(&path, str);
|
||||
al_string_append_cstr(&path, "/.local/share/");
|
||||
al_string_append_cstr(&path, subdir);
|
||||
}
|
||||
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')
|
||||
str = "/usr/local/share/:/usr/share/";
|
||||
|
||||
next = str;
|
||||
while((str=next) != NULL && str[0] != '\0')
|
||||
{
|
||||
next = strchr(str, ':');
|
||||
if(!next)
|
||||
al_string_copy_cstr(&path, str);
|
||||
else
|
||||
{
|
||||
al_string_clear(&path);
|
||||
al_string_append_range(&path, str, next);
|
||||
++next;
|
||||
}
|
||||
if(!al_string_empty(path))
|
||||
{
|
||||
al_string_append_char(&path, '/');
|
||||
al_string_append_cstr(&path, subdir);
|
||||
|
||||
RecurseDirectorySearch(al_string_get_cstr(path), match, &results);
|
||||
}
|
||||
}
|
||||
|
||||
al_string_deinit(&path);
|
||||
}
|
||||
|
||||
ATOMIC_STORE(&search_lock, 0);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -638,25 +1181,20 @@ void SetRTPriority(void)
|
||||
}
|
||||
|
||||
|
||||
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact)
|
||||
ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact)
|
||||
{
|
||||
vector_ *vecptr = (vector_*)ptr;
|
||||
if(obj_count < 0)
|
||||
return AL_FALSE;
|
||||
if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count)
|
||||
{
|
||||
ALsizei old_size = (*vecptr ? (*vecptr)->Size : 0);
|
||||
size_t old_size = (*vecptr ? (*vecptr)->Size : 0);
|
||||
void *temp;
|
||||
|
||||
/* Use the next power-of-2 size if we don't need to allocate the exact
|
||||
* amount. This is preferred when regularly increasing the vector since
|
||||
* it means fewer reallocations. Though it means it also wastes some
|
||||
* memory. */
|
||||
if(exact == AL_FALSE)
|
||||
{
|
||||
if(exact == AL_FALSE && obj_count < INT_MAX)
|
||||
obj_count = NextPowerOf2((ALuint)obj_count);
|
||||
if(obj_count < 0) return AL_FALSE;
|
||||
}
|
||||
|
||||
/* Need to be explicit with the caller type's base size, because it
|
||||
* could have extra padding before the start of the array (that is,
|
||||
@@ -671,11 +1209,9 @@ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei o
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count)
|
||||
ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count)
|
||||
{
|
||||
vector_ *vecptr = (vector_*)ptr;
|
||||
if(obj_count < 0)
|
||||
return AL_FALSE;
|
||||
if(*vecptr || obj_count > 0)
|
||||
{
|
||||
if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE))
|
||||
@@ -696,12 +1232,12 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
|
||||
ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size;
|
||||
|
||||
assert(numins > 0);
|
||||
if(INT_MAX-VECTOR_SIZE(*vecptr) <= numins ||
|
||||
if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins ||
|
||||
!vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE))
|
||||
return AL_FALSE;
|
||||
|
||||
/* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */
|
||||
if(ins_elem < (*vecptr)->Size)
|
||||
if((size_t)ins_elem < (*vecptr)->Size)
|
||||
{
|
||||
memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size),
|
||||
(char*)(*vecptr) + base_size + ((ins_elem )*obj_size),
|
||||
@@ -709,14 +1245,14 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_
|
||||
}
|
||||
memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size),
|
||||
datstart, numins*obj_size);
|
||||
(*vecptr)->Size += (ALsizei)numins;
|
||||
(*vecptr)->Size += numins;
|
||||
}
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
|
||||
extern inline void al_string_deinit(al_string *str);
|
||||
extern inline ALsizei al_string_length(const_al_string str);
|
||||
extern inline size_t al_string_length(const_al_string str);
|
||||
extern inline ALboolean al_string_empty(const_al_string str);
|
||||
extern inline const al_string_char_type *al_string_get_cstr(const_al_string str);
|
||||
|
||||
@@ -730,10 +1266,10 @@ void al_string_clear(al_string *str)
|
||||
*VECTOR_ITER_END(*str) = 0;
|
||||
}
|
||||
|
||||
static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len,
|
||||
const al_string_char_type *str2, ALsizei str2len)
|
||||
static inline int al_string_compare(const al_string_char_type *str1, size_t str1len,
|
||||
const al_string_char_type *str2, size_t str2len)
|
||||
{
|
||||
ALsizei complen = mini(str1len, str2len);
|
||||
size_t complen = (str1len < str2len) ? str1len : str2len;
|
||||
int ret = memcmp(str1, str2, complen);
|
||||
if(ret == 0)
|
||||
{
|
||||
@@ -750,12 +1286,12 @@ int al_string_cmp(const_al_string str1, const_al_string str2)
|
||||
int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2)
|
||||
{
|
||||
return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1),
|
||||
str2, (ALsizei)strlen(str2));
|
||||
str2, strlen(str2));
|
||||
}
|
||||
|
||||
void al_string_copy(al_string *str, const_al_string from)
|
||||
{
|
||||
ALsizei len = VECTOR_SIZE(from);
|
||||
size_t len = al_string_length(from);
|
||||
VECTOR_RESERVE(*str, len+1);
|
||||
VECTOR_RESIZE(*str, 0);
|
||||
VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len);
|
||||
@@ -811,4 +1347,30 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from)
|
||||
*VECTOR_ITER_END(*str) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void al_string_append_wcstr(al_string *str, const wchar_t *from)
|
||||
{
|
||||
int len;
|
||||
if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0)
|
||||
{
|
||||
size_t strlen = al_string_length(*str);
|
||||
VECTOR_RESERVE(*str, strlen+len);
|
||||
VECTOR_RESIZE(*str, strlen+len-1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL);
|
||||
*VECTOR_ITER_END(*str) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to)
|
||||
{
|
||||
int len;
|
||||
if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0)
|
||||
{
|
||||
size_t strlen = al_string_length(*str);
|
||||
VECTOR_RESERVE(*str, strlen+len+1);
|
||||
VECTOR_RESIZE(*str, strlen+len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL);
|
||||
*VECTOR_ITER_END(*str) = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user