aboutsummaryrefslogtreecommitdiff
path: root/c/ext.cpp
blob: 77028d19b8aa2c5cfe4e4dfc5460cf960a8df0fe (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
122
123
124
#include <ctype.h>
#include <string>
#include <string_view>

#include "data.h"
#include "main.h"

extern Window* g_window;

bool OpenOnline(int iEp)
{
	wchar_t url[sizeof(g_window->cfg.url)+4];
	Swprintf(url, L"%s%d", g_window->cfg.url, iEp);
	INT_PTR r = reinterpret_cast<INT_PTR>(
	    ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL));
	if (r <= 32)
		throw Win32Error();
	return true;
}

bool OpenWiki(int iEp)
{
	const DlvDataA& d = g_window->fvDlv.At(iEp-1);
	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 Win32Error();
	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 Win32Error();

	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 Win32Error();

	return false;
}

bool OpenLocally(int iEp)
{
	wchar_t file[MAX_PATH];
	if (FindMatchingFile(file, g_window->cfg.root, g_window->fvElv.At(iEp-1).siEp)) {
		INT_PTR r = reinterpret_cast<INT_PTR>(
		    ShellExecuteW(nullptr, L"open", file, nullptr, nullptr, SW_SHOWNORMAL));
		if (r <= 32)
			throw Win32Error();
		return true;
	} else
		return false;
}