diff options
Diffstat (limited to 'osdep/glob-win.c')
-rw-r--r-- | osdep/glob-win.c | 195 |
1 files changed, 126 insertions, 69 deletions
diff --git a/osdep/glob-win.c b/osdep/glob-win.c index d67d6ddf63..30dad4dfc5 100644 --- a/osdep/glob-win.c +++ b/osdep/glob-win.c @@ -1,98 +1,155 @@ /* - * This file is part of MPlayer. + * This file is part of mpv. * - * MPlayer is free software; you can redistribute it and/or modify + * mpv is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * MPlayer is distributed in the hope that it will be useful, + * mpv is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * with mpv. If not, see <http://www.gnu.org/licenses/>. */ -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> +#include <windows.h> +#include <stdbool.h> #include <string.h> +#include "osdep/io.h" +#include "talloc.h" -#include "config.h" +static wchar_t *talloc_wcsdup(void *ctx, const wchar_t *wcs) +{ + size_t len = (wcslen(wcs) + 1) * sizeof(wchar_t); + return talloc_memdup(ctx, (void*)wcs, len); +} -#include <windows.h> -#include "glob.h" +static int compare_wcscoll(const void *v1, const void *v2) +{ + wchar_t * const* p1 = v1; + wchar_t * const* p2 = v2; + return wcscoll(*p1, *p2); +} -int glob(const char *pattern, int flags, - int (*errfunc)(const char *epath, int eerrno), glob_t *pglob) +static bool exists(const char *filename) { - HANDLE searchhndl; - WIN32_FIND_DATA found_file; - if (errfunc) - printf("glob():ERROR:Sorry errfunc not supported by this implementation\n"); - if (flags) - printf("glob():ERROR:Sorry no flags supported by this globimplementation\n"); - //printf("PATTERN \"%s\"\n",pattern); - pglob->gl_pathc = 0; - searchhndl = FindFirstFile(pattern, &found_file); - if (searchhndl == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) { - pglob->gl_pathc = 0; - //printf("could not find a file matching your search criteria\n"); - return 1; - } else { - //printf("glob():ERROR:FindFirstFile: %i\n",GetLastError()); - return 1; + wchar_t *wfilename = mp_from_utf8(NULL, filename); + bool result = GetFileAttributesW(wfilename) != INVALID_FILE_ATTRIBUTES; + talloc_free(wfilename); + return result; +} + +int mp_glob(const char *restrict pattern, int flags, + int (*errfunc)(const char*, int), mp_glob_t *restrict pglob) +{ + // This glob implementation never calls errfunc and doesn't understand any + // flags. These features are currently unused in mpv, however if new code + // were to use these them, it would probably break on Windows. + + unsigned dirlen = 0; + bool wildcards = false; + + // Check for drive relative paths eg. "C:*.flac" + if (pattern[0] != '\0' && pattern[1] == ':') + dirlen = 2; + + // Split the directory and filename. All files returned by FindFirstFile + // will be in this directory. Also check the filename for wildcards. + for (unsigned i = 0; pattern[i]; i ++) { + if (pattern[i] == '?' || pattern[i] == '*') + wildcards = true; + + if (pattern[i] == '\\' || pattern[i] == '/') { + dirlen = i + 1; + wildcards = false; } } - pglob->gl_pathv = malloc(sizeof(char *)); - pglob->gl_pathv[0] = strdup(found_file.cFileName); - pglob->gl_pathc++; - while (1) { - if (!FindNextFile(searchhndl, &found_file)) { - if (GetLastError() == ERROR_NO_MORE_FILES) { - //printf("glob(): no more files found\n"); - break; - } else { - //printf("glob():ERROR:FindNextFile:%i\n",GetLastError()); - return 1; - } - } else { - //printf("glob: found file %s\n",found_file.cFileName); - pglob->gl_pathc++; - pglob->gl_pathv = realloc(pglob->gl_pathv, pglob->gl_pathc * sizeof(char *)); - pglob->gl_pathv[pglob->gl_pathc - 1] = strdup(found_file.cFileName); + + // FindFirstFile is unreliable with certain input (it returns weird results + // with paths like "." and "..", and presumably others.) If there are no + // wildcards in the filename, don't call it, just check if the file exists. + // The CRT globbing code does this too. + if (!wildcards) { + if (!exists(pattern)) { + pglob->gl_pathc = 0; + return GLOB_NOMATCH; } + + pglob->ctx = talloc_new(NULL); + pglob->gl_pathc = 1; + pglob->gl_pathv = talloc_array_ptrtype(pglob->ctx, pglob->gl_pathv, 2); + pglob->gl_pathv[0] = talloc_strdup(pglob->ctx, pattern); + pglob->gl_pathv[1] = NULL; + return 0; } - FindClose(searchhndl); - return 0; -} -void globfree(glob_t *pglob) -{ - int i; - for (i = 0; i < pglob->gl_pathc; i++) - free(pglob->gl_pathv[i]); - free(pglob->gl_pathv); -} + wchar_t *wpattern = mp_from_utf8(NULL, pattern); + WIN32_FIND_DATAW data; + HANDLE find = FindFirstFileW(wpattern, &data); + talloc_free(wpattern); -#if 0 -int main(void) -{ - glob_t gg; - printf("globtest\n"); - glob("*.jpeg", 0, NULL, &gg); - { - int i; - for (i = 0; i < gg.gl_pathc; i++) - printf("GLOBED:%i %s\n", i, gg.gl_pathv[i]); + // Assume an error means there were no matches. mpv doesn't check for + // glob() errors, so this should be fine for now. + if (find == INVALID_HANDLE_VALUE) { + pglob->gl_pathc = 0; + return GLOB_NOMATCH; } - globfree(&gg); + size_t pathc = 0; + void *tmp = talloc_new(NULL); + wchar_t **wnamev = NULL; + + // Read a list of filenames. Unlike glob(), FindFirstFile doesn't return + // the full path, since all files are relative to the directory specified + // in the pattern. + do { + if (!wcscmp(data.cFileName, L".") || !wcscmp(data.cFileName, L"..")) + continue; + + wchar_t *wname = talloc_wcsdup(tmp, data.cFileName); + MP_TARRAY_APPEND(tmp, wnamev, pathc, wname); + } while (FindNextFileW(find, &data)); + FindClose(find); + + if (!wnamev) { + talloc_free(tmp); + pglob->gl_pathc = 0; + return GLOB_NOMATCH; + } + + // POSIX glob() is supposed to sort paths according to LC_COLLATE. + // FindFirstFile just returns paths in the order they are read from the + // directory, so sort them manually with wcscoll. + qsort(wnamev, pathc, sizeof(wchar_t*), compare_wcscoll); + + pglob->ctx = talloc_new(NULL); + pglob->gl_pathc = pathc; + pglob->gl_pathv = talloc_array_ptrtype(pglob->ctx, pglob->gl_pathv, + pathc + 1); + + // Now convert all filenames to UTF-8 (they had to be in UTF-16 for + // sorting) and prepend the directory + for (unsigned i = 0; i < pathc; i ++) { + int namelen = WideCharToMultiByte(CP_UTF8, 0, wnamev[i], -1, NULL, 0, + NULL, NULL); + char *path = talloc_array(pglob->ctx, char, namelen + dirlen); + + memcpy(path, pattern, dirlen); + WideCharToMultiByte(CP_UTF8, 0, wnamev[i], -1, path + dirlen, + namelen, NULL, NULL); + pglob->gl_pathv[i] = path; + } + + // gl_pathv must be null terminated + pglob->gl_pathv[pathc] = NULL; + talloc_free(tmp); return 0; } -#endif +void mp_globfree(mp_glob_t *pglob) +{ + talloc_free(pglob->ctx); +} |