diff options
-rw-r--r-- | demux/mf.c | 10 | ||||
-rw-r--r-- | osdep/glob-win.c | 195 | ||||
-rw-r--r-- | osdep/glob.h | 34 | ||||
-rw-r--r-- | osdep/io.h | 25 |
4 files changed, 152 insertions, 112 deletions
diff --git a/demux/mf.c b/demux/mf.c index b538943aff..04c99a3bcc 100644 --- a/demux/mf.c +++ b/demux/mf.c @@ -26,16 +26,8 @@ #include <limits.h> #include <sys/types.h> -#include "osdep/io.h" - #include "config.h" - -#if HAVE_GLOB -#include <glob.h> -#else -#include "osdep/glob.h" -#endif - +#include "osdep/io.h" #include "talloc.h" #include "common/msg.h" #include "stream/stream.h" 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); +} diff --git a/osdep/glob.h b/osdep/glob.h deleted file mode 100644 index f117725d63..0000000000 --- a/osdep/glob.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of MPlayer. - * - * MPlayer 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, - * 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. - */ - -#ifndef MPLAYER_GLOB_H -#define MPLAYER_GLOB_H - -#include <sys/types.h> - -typedef struct { - size_t gl_pathc; - char **gl_pathv; - size_t gl_offs; -} glob_t; - -void globfree(glob_t *pglob); - -int glob(const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), glob_t *pglob); - -#endif /* MPLAYER_GLOB_H */ diff --git a/osdep/io.h b/osdep/io.h index 4cb16677f2..53097a1b78 100644 --- a/osdep/io.h +++ b/osdep/io.h @@ -20,12 +20,17 @@ #ifndef MPLAYER_OSDEP_IO #define MPLAYER_OSDEP_IO +#include "config.h" #include <stdbool.h> #include <limits.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#if HAVE_GLOB +#include <glob.h> +#endif + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -71,6 +76,18 @@ int mp_closedir(DIR *dir); int mp_mkdir(const char *path, int mode); char *mp_getenv(const char *name); +typedef struct { + size_t gl_pathc; + char **gl_pathv; + size_t gl_offs; + void *ctx; +} mp_glob_t; + +// glob-win.c +int mp_glob(const char *restrict pattern, int flags, + int (*errfunc)(const char*, int), mp_glob_t *restrict pglob); +void mp_globfree(mp_glob_t *pglob); + // NOTE: stat is not overridden with mp_stat, because MinGW-w64 defines it as // macro. @@ -85,6 +102,14 @@ char *mp_getenv(const char *name); #define mkdir(...) mp_mkdir(__VA_ARGS__) #define getenv(...) mp_getenv(__VA_ARGS__) +#ifndef GLOB_NOMATCH +#define GLOB_NOMATCH 3 +#endif + +#define glob_t mp_glob_t +#define glob(...) mp_glob(__VA_ARGS__) +#define globfree(...) mp_globfree(__VA_ARGS__) + #else /* __MINGW32__ */ #define mp_stat(...) stat(__VA_ARGS__) |