xref: /netbsd-src/sys/arch/hpc/stand/hpcboot/menu/menu.cpp (revision 115cdcb7310ff2435fe2e3b0f28cebc2e1b33018)
1 /* -*-C++-*-	$NetBSD: menu.cpp,v 1.13 2011/11/23 15:49:58 nonaka Exp $	*/
2 
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by UCHIYAMA Yasushi.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <hpcmenu.h>
33 #include <hpcboot.h>
34 #include <res/resource.h>
35 #include <menu/window.h>
36 #include <menu/tabwindow.h>
37 #include <menu/rootwindow.h>
38 #include <machine/bootinfo.h>
39 #include <framebuffer.h>
40 #include <console.h>
41 
42 #include <menu/menu.h>
43 
44 #define SCALEX(x) (((x) * dpix) / 96/*DPI*/)
45 #define SCALEY(y) (((y) * dpiy) / 96/*DPI*/)
46 #define UNSCALEX(x) (((x) * 96) / dpix)
47 #define UNSCALEY(y) (((y) * 96) / dpiy)
48 
49 TabWindow *
boot(int id)50 TabWindowBase::boot(int id)
51 {
52 	TabWindow *w = NULL;
53 	HpcMenuInterface &menu = HPC_MENU;
54 
55 	switch(id) {
56 	default:
57 		break;
58 	case IDC_BASE_MAIN:
59 		menu._main = new MainTabWindow(*this, IDC_BASE_MAIN);
60 		w = menu._main;
61 		break;
62 	case IDC_BASE_OPTION:
63 		menu._option = new OptionTabWindow(*this, IDC_BASE_OPTION);
64 		w = menu._option;
65 		break;
66 	case IDC_BASE_CONSOLE:
67 		menu._console = new ConsoleTabWindow(*this, IDC_BASE_CONSOLE);
68 		w = menu._console;
69 		break;
70 	}
71 
72 	if (w)
73 		w->create(0);
74 
75 	return w;
76 }
77 
78 //
79 // Main window
80 //
81 void
_insert_item(HWND w,TCHAR * name,int id)82 MainTabWindow::_insert_item(HWND w, TCHAR *name, int id)
83 {
84 	int idx = SendDlgItemMessage(w, id, CB_ADDSTRING, 0,
85 	    reinterpret_cast <LPARAM>(name));
86 	if (idx != CB_ERR)
87 		SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETITEMDATA,
88 		    idx, _item_idx++);
89 }
90 
91 void
init(HWND w)92 MainTabWindow::init(HWND w)
93 {
94 	HpcMenuInterface &menu = HPC_MENU;
95 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
96 
97 	_window = w;
98 	// insert myself to tab-control
99 	TabWindow::init(w);
100 
101 	// setup child.
102 	TCHAR *entry;
103 	int i;
104 	// kernel directory path
105 	for (i = 0; entry = menu.dir(i); i++)
106 		_insert_item(w, entry, IDC_MAIN_DIR);
107 	SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETCURSEL, menu.dir_default(),
108 	    0);
109 	// platform
110 	_sort_platids(w);
111 	// kernel file name.
112 	Edit_SetText(GetDlgItem(w, IDC_MAIN_KERNEL), pref.kernel_user ?
113 	    pref.kernel_user_file : TEXT("netbsd.gz"));
114 
115 	// root file system.
116 	int fs = pref.rootfs + IDC_MAIN_ROOT_;
117 	_set_check(fs, TRUE);
118 
119 	_edit_md_root = GetDlgItem(w, IDC_MAIN_ROOT_MD_OPS);
120 	Edit_SetText(_edit_md_root, pref.rootfs_file);
121 	EnableWindow(_edit_md_root, fs == IDC_MAIN_ROOT_MD ? TRUE : FALSE);
122 
123 	// layout checkbox and editbox.
124 	layout();
125 
126 	// set default kernel boot options.
127 	_set_check(IDC_MAIN_OPTION_A, pref.boot_ask_for_name);
128 	_set_check(IDC_MAIN_OPTION_D, pref.boot_debugger);
129 	_set_check(IDC_MAIN_OPTION_S, pref.boot_single_user);
130 	_set_check(IDC_MAIN_OPTION_V, pref.boot_verbose);
131 	_set_check(IDC_MAIN_OPTION_H, pref.boot_serial);
132 
133 	// serial console speed.
134 	TCHAR *speed_tab[] = { L"9600", L"19200", L"115200", 0 };
135 	int sel = 0;
136 	i = 0;
137 	for (TCHAR **speed = speed_tab; *speed; speed++, i++) {
138 		_insert_item(w, *speed, IDC_MAIN_OPTION_H_SPEED);
139 		if (_wtoi(*speed) == pref.serial_speed)
140 			sel = i;
141 	}
142 	_combobox_serial_speed = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED);
143 	SendDlgItemMessage(w, IDC_MAIN_OPTION_H_SPEED, CB_SETCURSEL, sel, 0);
144 	EnableWindow(_combobox_serial_speed, pref.boot_serial);
145 }
146 
147 int
_platcmp(const void * a,const void * b)148 MainTabWindow::_platcmp(const void *a, const void *b)
149 {
150 	const MainTabWindow::PlatMap *pa =
151 		reinterpret_cast <const MainTabWindow::PlatMap *>(a);
152 	const MainTabWindow::PlatMap *pb =
153 		reinterpret_cast <const MainTabWindow::PlatMap *>(b);
154 
155 	return wcscmp(pa->name, pb->name);
156 }
157 
158 void
_sort_platids(HWND w)159 MainTabWindow::_sort_platids(HWND w)
160 {
161 	HpcMenuInterface &menu = HPC_MENU;
162 	MainTabWindow::PlatMap *p;
163 	TCHAR *entry;
164 	int nids;
165 	int i;
166 
167 	for (nids = 0; menu.platform_get(nids); ++nids)
168 		continue;
169 
170 	_platmap = reinterpret_cast <MainTabWindow::PlatMap *>
171 		(malloc(nids * sizeof(MainTabWindow::PlatMap)));
172 
173 	if (_platmap == NULL) {
174 		// can't sort, present in the order of definition
175 		for (i = 0; entry = menu.platform_get(i); i++)
176 			_insert_item(w, entry, IDC_MAIN_PLATFORM);
177 		SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL,
178 				   menu.platform_default(), 0);
179 		return;
180 	}
181 
182 	for (i = 0, p = _platmap; i < nids; ++i, ++p) {
183 		p->id = i;
184 		p->name = menu.platform_get(i);
185 	}
186 
187 	qsort(_platmap, nids, sizeof(MainTabWindow::PlatMap),
188 	      MainTabWindow::_platcmp);
189 
190 	int defid = menu.platform_default();
191 	int defitem = 0;
192 	for (i = 0; i < nids; ++i) {
193 		if (_platmap[i].id == defid)
194 			defitem = i;
195 		_insert_item(w, _platmap[i].name, IDC_MAIN_PLATFORM);
196 	}
197 	SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, defitem, 0);
198 }
199 
200 int
_item_to_platid(int idx)201 MainTabWindow::_item_to_platid(int idx)
202 {
203 	if (_platmap == NULL)
204 		return idx;
205 	else
206 		return _platmap[idx].id;
207 }
208 
209 void
layout()210 MainTabWindow::layout()
211 {
212 	// inquire display size.
213 	HDC hdc = GetDC(0);
214 	int width = GetDeviceCaps(hdc, HORZRES);
215 	int height = GetDeviceCaps(hdc, VERTRES);
216 	int dpix = GetDeviceCaps(hdc, LOGPIXELSX);
217 	int dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
218 	ReleaseDC(0, hdc);
219 
220 	// set origin
221 	int x, y;
222 	if (width <= 320) {
223 		x = 5, y = 140;
224 	} else if (height <= 240) {
225 		x = 250, y = 5;
226 	} else {
227 		x = 5, y = 140;
228 	}
229 
230 	HWND h;
231 	h = GetDlgItem(_window, IDC_MAIN_OPTION_V);
232 	SetWindowPos(h, 0, SCALEX(x), SCALEY(y),
233 	    SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER);
234 	h = GetDlgItem(_window, IDC_MAIN_OPTION_S);
235 	SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 20),
236             SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER);
237 	h = GetDlgItem(_window, IDC_MAIN_OPTION_A);
238 	SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 40),
239 	    SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER);
240 	h = GetDlgItem(_window, IDC_MAIN_OPTION_D);
241 	SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 60),
242 	    SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER);
243 	h = GetDlgItem(_window, IDC_MAIN_OPTION_H);
244 	SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 80),
245 	    SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER);
246 	h = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED);
247 	SetWindowPos(h, 0, SCALEX(x + 100), SCALEY(y + 80),
248 	    SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER);
249 }
250 
251 void
get()252 MainTabWindow::get()
253 {
254 	HpcMenuInterface &menu = HPC_MENU;
255 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
256 
257 	HWND w = GetDlgItem(_window, IDC_MAIN_DIR);
258 	ComboBox_GetText(w, pref.dir_user_path, MAX_PATH);
259 	pref.dir_user = TRUE;
260 	w = GetDlgItem(_window, IDC_MAIN_KERNEL);
261 	Edit_GetText(w, pref.kernel_user_file, MAX_PATH);
262 	pref.kernel_user = TRUE;
263 
264 	int i = ComboBox_GetCurSel(GetDlgItem(_window, IDC_MAIN_PLATFORM));
265 	menu.platform_set(_item_to_platid(i));
266 
267 	if (_is_checked(IDC_MAIN_ROOT_WD))
268 		pref.rootfs = 0;
269 	else if (_is_checked(IDC_MAIN_ROOT_SD))
270 		pref.rootfs = 1;
271 	else if (_is_checked(IDC_MAIN_ROOT_MD))
272 		pref.rootfs = 2;
273 	else if (_is_checked(IDC_MAIN_ROOT_NFS))
274 		pref.rootfs = 3;
275 	else if (_is_checked(IDC_MAIN_ROOT_DK))
276 		pref.rootfs = 4;
277 	else if (_is_checked(IDC_MAIN_ROOT_LD))
278 		pref.rootfs = 5;
279 
280 	pref.boot_ask_for_name	= _is_checked(IDC_MAIN_OPTION_A);
281 	pref.boot_debugger	= _is_checked(IDC_MAIN_OPTION_D);
282 	pref.boot_verbose	= _is_checked(IDC_MAIN_OPTION_V);
283 	pref.boot_single_user	= _is_checked(IDC_MAIN_OPTION_S);
284 	pref.boot_serial	= _is_checked(IDC_MAIN_OPTION_H);
285 	Edit_GetText(_edit_md_root, pref.rootfs_file, MAX_PATH);
286 
287 	TCHAR tmpbuf[8];
288 	ComboBox_GetText(_combobox_serial_speed, tmpbuf, 8);
289 	pref.serial_speed = _wtoi(tmpbuf);
290 }
291 
292 void
command(int id,int msg)293 MainTabWindow::command(int id, int msg)
294 {
295 	switch (id) {
296 	case IDC_MAIN_OPTION_H:
297 		EnableWindow(_combobox_serial_speed,
298 		    _is_checked(IDC_MAIN_OPTION_H));
299 		break;
300 	case IDC_MAIN_ROOT_WD:
301 		/* FALLTHROUGH */
302 	case IDC_MAIN_ROOT_SD:
303 		/* FALLTHROUGH */
304 	case IDC_MAIN_ROOT_MD:
305 		/* FALLTHROUGH */
306 	case IDC_MAIN_ROOT_NFS:
307 		/* FALLTHROUGH */
308 	case IDC_MAIN_ROOT_DK:
309 		/* FALLTHROUGH */
310 	case IDC_MAIN_ROOT_LD:
311 		EnableWindow(_edit_md_root, _is_checked(IDC_MAIN_ROOT_MD));
312 	}
313 }
314 
315 //
316 // Option window
317 //
318 void
init(HWND w)319 OptionTabWindow::init(HWND w)
320 {
321 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
322 	HDC hdc = GetDC(0);
323 	int dpix = GetDeviceCaps(hdc, LOGPIXELSX);
324 	int dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
325 	ReleaseDC(0, hdc);
326 
327 	_window = w;
328 
329 	TabWindow::init(_window);
330 	_spin_edit = GetDlgItem(_window, IDC_OPT_AUTO_INPUT);
331 	_spin = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE |
332 	    UDS_SETBUDDYINT | UDS_ALIGNRIGHT,
333 	    SCALEX(80), SCALEY(0), SCALEX(50), SCALEY(50), _window,
334 	    IDC_OPT_AUTO_UPDOWN, _app._instance, _spin_edit, 60, 1, 30);
335 	BOOL onoff = pref.auto_boot ? TRUE : FALSE;
336 	EnableWindow(_spin_edit, onoff);
337 	EnableWindow(_spin, onoff);
338 
339 	SET_CHECK(AUTO, pref.auto_boot);
340 	if (pref.auto_boot) {
341 		TCHAR tmp[32];
342 		wsprintf(tmp, TEXT("%d"), pref.auto_boot);
343 		Edit_SetText(_spin_edit, tmp);
344 	}
345 	SET_CHECK(VIDEO,	pref.reverse_video);
346 	SET_CHECK(PAUSE,	pref.pause_before_boot);
347 	SET_CHECK(DEBUG,	pref.load_debug_info);
348 	SET_CHECK(SAFETY,	pref.safety_message);
349 	Edit_SetText(GetDlgItem(w, IDC_OPT_EXTKOPT), pref.boot_extra);
350 }
351 
352 void
command(int id,int msg)353 OptionTabWindow::command(int id, int msg)
354 {
355 	switch (id) {
356 	case IDC_OPT_AUTO:
357 		if (IS_CHECKED(AUTO)) {
358 			EnableWindow(_spin_edit, TRUE);
359 			EnableWindow(_spin, TRUE);
360 		} else {
361 			EnableWindow(_spin_edit, FALSE);
362 			EnableWindow(_spin, FALSE);
363 		}
364 		break;
365 	}
366 }
367 
368 void
get()369 OptionTabWindow::get()
370 {
371 	HWND w;
372 	struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE;
373 	if (IS_CHECKED(AUTO)) {
374 		TCHAR tmp[32];
375 		Edit_GetText(_spin_edit, tmp, 32);
376 		pref.auto_boot = _wtoi(tmp);
377 	} else
378 		pref.auto_boot = 0;
379 	pref.reverse_video	= IS_CHECKED(VIDEO);
380 	pref.pause_before_boot	= IS_CHECKED(PAUSE);
381 	pref.load_debug_info	= IS_CHECKED(DEBUG);
382 	pref.safety_message	= IS_CHECKED(SAFETY);
383 
384 	w = GetDlgItem(_window, IDC_OPT_EXTKOPT);
385 	Edit_GetText(w, pref.boot_extra, MAX_BOOT_STR);
386 }
387 #undef IS_CHECKED
388 #undef SET_CHECK
389 
390 
391 //
392 // Console window
393 //
394 void
print(TCHAR * buf,BOOL force_display)395 ConsoleTabWindow::print(TCHAR *buf, BOOL force_display)
396 {
397 	int cr;
398 	TCHAR *p;
399 
400 	if (force_display)
401 		goto display;
402 
403 	if (_filesave) {
404 		if (_logfile == INVALID_HANDLE_VALUE && !_open_log_file()) {
405 			_filesave = FALSE;
406 			_set_check(IDC_CONS_FILESAVE, _filesave);
407 			EnableWindow(_filename_edit, _filesave);
408 			goto display;
409 		}
410 		DWORD cnt;
411 		char c;
412 		for (int i = 0; *buf != TEXT('\0'); buf++) {
413 			c = *buf & 0x7f;
414 			WriteFile(_logfile, &c, 1, &cnt, 0);
415 		}
416 		FlushFileBuffers(_logfile);
417 		return;
418 	}
419 
420  display:
421 	// count number of '\n'
422 	for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++)
423 		continue;
424 
425 	// total length of new buffer ('\n' -> "\r\n" + '\0')
426 	size_t sz = (wcslen(buf) + cr + 1) * sizeof(TCHAR);
427 
428 	p = reinterpret_cast <TCHAR *>(malloc(sz));
429 	if (p == NULL)
430 		return;
431 
432 	// convert newlines
433 	TCHAR *d = p;
434 	while (*buf != TEXT('\0')) {
435 		TCHAR c = *buf++;
436 		if (c == TEXT('\n'))
437 			*d++ = TEXT('\r');
438 		*d++ = c;
439 	}
440 	*d = TEXT('\0');
441 
442 	// append the text and scroll
443 	int end = Edit_GetTextLength(_edit);
444 	Edit_SetSel(_edit, end, end);
445 	Edit_ReplaceSel(_edit, p);
446 	Edit_ScrollCaret(_edit);
447 	UpdateWindow(_edit);
448 
449 	free(p);
450 }
451 
452 void
init(HWND w)453 ConsoleTabWindow::init(HWND w)
454 {
455 	HDC hdc = GetDC(0);
456 	int dpix = GetDeviceCaps(hdc, LOGPIXELSX);
457 	int dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
458 	ReleaseDC(0, hdc);
459 
460 	// at this time _window is NULL.
461 	// use argument of window procedure.
462 	TabWindow::init(w);
463 	_edit = GetDlgItem(w, IDC_CONS_EDIT);
464 	MoveWindow(_edit, SCALEX(5), SCALEY(60),
465 	    SCALEX(UNSCALEX(_rect.right - _rect.left) - 10),
466 	    SCALEY(UNSCALEY(_rect.bottom - _rect.top) - 60), TRUE);
467 	Edit_FmtLines(_edit, TRUE);
468 
469 	// log file.
470 	_filename_edit = GetDlgItem(w, IDC_CONS_FILENAME);
471 	_filesave = FALSE;
472 	Edit_SetText(_filename_edit, L"bootlog.txt");
473 	EnableWindow(_filename_edit, _filesave);
474 }
475 
476 void
command(int id,int msg)477 ConsoleTabWindow::command(int id, int msg)
478 {
479 	HpcMenuInterface &menu = HPC_MENU;
480 	struct HpcMenuInterface::cons_hook_args *hook = 0;
481 	int bit;
482 
483 	switch(id) {
484 	case IDC_CONS_FILESAVE:
485 		_filesave = _is_checked(IDC_CONS_FILESAVE);
486 		EnableWindow(_filename_edit, _filesave);
487 		break;
488 	case IDC_CONS_CHK0:
489 		/* FALLTHROUGH */
490 	case IDC_CONS_CHK1:
491 		/* FALLTHROUGH */
492 	case IDC_CONS_CHK2:
493 		/* FALLTHROUGH */
494 	case IDC_CONS_CHK3:
495 		/* FALLTHROUGH */
496 	case IDC_CONS_CHK4:
497 		/* FALLTHROUGH */
498 	case IDC_CONS_CHK5:
499 		/* FALLTHROUGH */
500 	case IDC_CONS_CHK6:
501 		/* FALLTHROUGH */
502 	case IDC_CONS_CHK7:
503 		bit = 1 << (id - IDC_CONS_CHK_);
504 		if (SendDlgItemMessage(_window, id, BM_GETCHECK, 0, 0))
505 			menu._cons_parameter |= bit;
506 		else
507 			menu._cons_parameter &= ~bit;
508 		break;
509 	case IDC_CONS_BTN0:
510 		/* FALLTHROUGH */
511 	case IDC_CONS_BTN1:
512 		/* FALLTHROUGH */
513 	case IDC_CONS_BTN2:
514 		/* FALLTHROUGH */
515 	case IDC_CONS_BTN3:
516 		hook = &menu._cons_hook[id - IDC_CONS_BTN_];
517 		if (hook->func)
518 			hook->func(hook->arg, menu._cons_parameter);
519 
520 		break;
521 	}
522 }
523 
524 BOOL
_open_log_file()525 ConsoleTabWindow::_open_log_file()
526 {
527 	TCHAR path[MAX_PATH];
528 	TCHAR filename[MAX_PATH];
529 	TCHAR filepath[MAX_PATH];
530 
531 	if (!_find_pref_dir(path)) {
532 		print(L"couldn't find temporary directory.\n", TRUE);
533 		return FALSE;
534 	}
535 
536 	Edit_GetText(_filename_edit, filename, MAX_PATH);
537 	wsprintf(filepath, TEXT("\\%s\\%s"), path, filename);
538 	_logfile = CreateFile(filepath, GENERIC_WRITE, 0, 0,
539 	    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
540 	if (_logfile == INVALID_HANDLE_VALUE)
541 		return FALSE;
542 
543 	wsprintf(path, TEXT("log file is %s\n"), filepath);
544 	print(path, TRUE);
545 
546 	return TRUE;
547 }
548 
549 //
550 // Common utility
551 //
552 static BOOL
is_ignore_directory(TCHAR * filename)553 is_ignore_directory(TCHAR *filename)
554 {
555 	static const TCHAR *dirs[] = {
556 		// Network (in Japanese)
557 		(const TCHAR *)"\xcd\x30\xc3\x30\xc8\x30\xef\x30\xfc\x30\xaf\x30\x00\x00",
558 	};
559 
560 	for (int i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) {
561 		if (wcscmp(filename, dirs[i]) == 0) {
562 			return TRUE;
563 		}
564 	}
565 	return FALSE;
566 }
567 
568 BOOL
_find_pref_dir(TCHAR * path)569 _find_pref_dir(TCHAR *path)
570 {
571 	WIN32_FIND_DATA fd;
572 	HANDLE find;
573 
574 	lstrcpy(path, TEXT("\\*.*"));
575 	find = FindFirstFile(path, &fd);
576 
577 	if (find != INVALID_HANDLE_VALUE) {
578 		do {
579 			int attr = fd.dwFileAttributes;
580 			if ((attr & FILE_ATTRIBUTE_DIRECTORY) &&
581 			    (attr & FILE_ATTRIBUTE_TEMPORARY) &&
582 			    !is_ignore_directory(fd.cFileName)) {
583 				wcscpy(path, fd.cFileName);
584 				FindClose(find);
585 				return TRUE;
586 			}
587 		} while (FindNextFile(find, &fd));
588 	}
589 	FindClose(find);
590 
591 	return FALSE;
592 }
593