Something went wrong. Try again.
🎥 Command line media player
Something went wrong. Try again.
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163/* * This file is part of mpv. * * mpv is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */
#include <windows.h>#include <stdbool.h>#include <string.h>#include "osdep/io.h"#include "mpv_talloc.h"
#if HAVE_UWP// Missing from MinGW headers.WINBASEAPI HANDLE WINAPI FindFirstFileExW(LPCWSTR lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, LPVOID lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, LPVOID lpSearchFilter, DWORD dwAdditionalFlags);#endif
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);}
static int compare_wcscoll(const void *v1, const void *v2){ wchar_t * const* p1 = v1; wchar_t * const* p2 = v2; return wcscoll(*p1, *p2);}
static bool exists(const char *filename){ 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; } }
// 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; }
wchar_t *wpattern = mp_from_utf8(NULL, pattern); WIN32_FIND_DATAW data; HANDLE find = FindFirstFileExW(wpattern, FindExInfoBasic, &data, FindExSearchNameMatch, NULL, 0); talloc_free(wpattern);
// 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; }
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;}
void mp_globfree(mp_glob_t *pglob){ talloc_free(pglob->ctx);}