aboutsummaryrefslogtreecommitdiff
path: root/c/ext.cpp
blob: c1bcc48352542423ce4675ae80db8aa5a90c737b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <ctype.h>
#include <string>
#include <string_view>

#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<INT_PTR>(
	    ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL));
	if (r <= 32)
		throw Err(WINDOWS, L"Address "s + url + L" could not be opened: %s.");
	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<INT_PTR>(
	    ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL));
	if (r <= 32)
		throw Err(WINDOWS, L"Address "s + url + L" could not be opened: %s.");
	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<HANDLE, FindClose> h = FindFirstFileW(pat, &fdata);
	if (h.Bad(INVALID_HANDLE_VALUE))
		throw Err(WINDOWS, L"Directory "s + root + L" could not be traversed: %s.");

	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: %s.");

	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<INT_PTR>(
		    ShellExecuteW(nullptr, L"open", file, nullptr, nullptr, SW_SHOWNORMAL));
		if (r <= 32)
			throw Err(WINDOWS, L"File "s + file + L" could not be opened: %s.");
		return true;
	} else
		return false;
}