#include #include #include #include #include "data.h" #include "window.h" bool OpenOnline(const CfgA& cfg, int iEp) { wchar_t url[sizeof(cfg.url)+4]; Swprintf(url, L"%s%d", cfg.url, iEp); INT_PTR r = reinterpret_cast( ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL)); if (r <= 32) throw Err(WINDOWS, L"Address "s + url + L" could not be opened"); return true; } bool OpenWiki(const DlvDataA& d) { wchar_t url[sizeof(d.wiki)+35]; Swprintf(url, L"https://www.detectiveconanworld.com%s", d.wiki); INT_PTR r = reinterpret_cast( ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL)); if (r <= 32) throw Err(WINDOWS, L"Address "s + url + L" could not be opened"); return true; } static inline bool MatchFileName(wchar_t (&file)[MAX_PATH], const wchar_t* const siEp) noexcept { /* This is a hand-written parser that matches file names of * the type "Detective Conan - 010.mkv". */ wchar_t* f = file; /* Match Detective Conan prefix. */ if (*f != L'D' && *f != L'd') return false; f++; if (wcsncmp(f, L"etective", 8) != 0) return false; f += 8; if (*f != L' ' && *f != L'_' && *f != L'-') return false; f++; if (*f != L'C' && *f != L'c') return false; f++; if (wcsncmp(f, L"onan", 4) != 0) return false; f += 4; /* Match garbage before episode number. */ while (*f == L' ' || *f == L'_' || *f == L'-' || *f == L'0') f++; /* Match episode number. */ size_t lenEp = wcslen(siEp); if (wcsncmp(f, siEp, lenEp) != 0) return false; f += lenEp; if (isdigit(*f)) return false; return true; } static bool FindMatchingFile(wchar_t (&file)[MAX_PATH], const wchar_t* const root, const wchar_t* const siEp, const int level = 0) { /* Don't recurse too much. */ if (level > 3) return false; wchar_t pat[MAX_PATH]; Swprintf(pat, L"%s\\*", root); WIN32_FIND_DATA fdata; Unique h = FindFirstFileW(pat, &fdata); if (h.Bad(INVALID_HANDLE_VALUE)) throw Err(WINDOWS, L"Directory "s + root + L" could not be traversed"); do if (fdata.cFileName[0] == L'.') ; else if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { /* Recurse into directory. */ wchar_t root2[MAX_PATH]; Swprintf(root2, L"%s\\%s", root, fdata.cFileName); if (FindMatchingFile(file, root2, siEp, level+1)) return true; } else if (MatchFileName(fdata.cFileName, siEp)) { Swprintf(file, L"%s\\%s", root, fdata.cFileName); return true; } while (FindNextFileW(h.v, &fdata)); if (GetLastError() != ERROR_NO_MORE_FILES) throw Err(WINDOWS, L"Next file in "s + root + L" could not be accessed"); return false; } bool OpenLocally(CfgA& cfg, const ElvDataA& e) { wchar_t file[MAX_PATH]; if (FindMatchingFile(file, cfg.root, e.siEp)) { INT_PTR r = reinterpret_cast( ShellExecuteW(nullptr, L"open", file, nullptr, nullptr, SW_SHOWNORMAL)); if (r <= 32) throw Err(WINDOWS, L"File "s + file + L" could not be opened"); return true; } else return false; } bool ShowInExplorer(CfgA& cfg, const ElvDataA& e) { wchar_t file[MAX_PATH]; if (FindMatchingFile(file, cfg.root, e.siEp)) { /* ILCreateFromPath does not support forward slashes. */ for (wchar_t *f = file; *f; f++) if (*f == L'/') *f = L'\\'; if (ITEMIDLIST* idl = ILCreateFromPath(file)) { HRESULT r = SHOpenFolderAndSelectItems(idl, 0, 0, 0); ILFree(idl); if (FAILED(r)) { SetLastError(r); throw Err(WINDOWS, L"File "s + file + L" could not be shown in Explorer"); } } return true; } else return false; }