1 /*
2 * ReactOS kernel
3 * Copyright (C) 2008 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/usetup/mui.c
23 * PURPOSE: Text-mode setup
24 * PROGRAMMER:
25 */
26
27 #include "usetup.h"
28 #include "muilanguages.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /* Special characters */
34 CHAR CharBullet = 0x07; /* bullet */
35 CHAR CharBlock = 0xDB; /* block */
36 CHAR CharHalfBlock = 0xDD; /* half-left block */
37 CHAR CharUpArrow = 0x18; /* up arrow */
38 CHAR CharDownArrow = 0x19; /* down arrow */
39 CHAR CharHorizontalLine = 0xC4; /* horizontal line */
40 CHAR CharVerticalLine = 0xB3; /* vertical line */
41 CHAR CharUpperLeftCorner = 0xDA; /* upper left corner */
42 CHAR CharUpperRightCorner = 0xBF; /* upper right corner */
43 CHAR CharLowerLeftCorner = 0xC0; /* lower left corner */
44 CHAR CharLowerRightCorner = 0xD9; /* lower right corner */
45 CHAR CharVertLineAndRightHorizLine = 0xC3; /* |- (vertical line and right horizontal line) */
46 CHAR CharLeftHorizLineAndVertLine = 0xB4; /* -| (left horizontal line and vertical line) */
47 CHAR CharDoubleHorizontalLine = 0xCD; /* double horizontal line (and underline) */
48 CHAR CharDoubleVerticalLine = 0xBA; /* double vertical line */
49 CHAR CharDoubleUpperLeftCorner = 0xC9; /* double upper left corner */
50 CHAR CharDoubleUpperRightCorner = 0xBB; /* double upper right corner */
51 CHAR CharDoubleLowerLeftCorner = 0xC8; /* double lower left corner */
52 CHAR CharDoubleLowerRightCorner = 0xBC; /* double lower right corner */
53
54 static
55 ULONG
FindLanguageIndex(VOID)56 FindLanguageIndex(VOID)
57 {
58 ULONG lngIndex = 0;
59
60 if (SelectedLanguageId == NULL)
61 {
62 /* Default to en-US */
63 return 0; // FIXME!!
64 // SelectedLanguageId = L"00000409";
65 }
66
67 while (ResourceList[lngIndex].MuiPages != NULL)
68 {
69 if (_wcsicmp(ResourceList[lngIndex].LanguageID, SelectedLanguageId) == 0)
70 {
71 return lngIndex;
72 }
73
74 lngIndex++;
75 }
76
77 return 0;
78 }
79
80
81 #if 0
82 BOOLEAN
83 IsLanguageAvailable(
84 PWCHAR LanguageId)
85 {
86 ULONG lngIndex = 0;
87
88 while (ResourceList[lngIndex].MuiPages != NULL)
89 {
90 if (_wcsicmp(ResourceList[lngIndex].LanguageID, LanguageId) == 0)
91 return TRUE;
92
93 lngIndex++;
94 }
95
96 return FALSE;
97 }
98 #endif
99
100
101 static
102 const MUI_ENTRY *
FindMUIEntriesOfPage(IN ULONG PageNumber)103 FindMUIEntriesOfPage(
104 IN ULONG PageNumber)
105 {
106 ULONG muiIndex = 0;
107 ULONG lngIndex;
108 const MUI_PAGE * Pages = NULL;
109
110 lngIndex = max(FindLanguageIndex(), 0);
111 Pages = ResourceList[lngIndex].MuiPages;
112
113 while (Pages[muiIndex].MuiEntry != NULL)
114 {
115 if (Pages[muiIndex].Number == PageNumber)
116 return Pages[muiIndex].MuiEntry;
117
118 muiIndex++;
119 }
120
121 return NULL;
122 }
123
124 static
125 const MUI_ERROR *
FindMUIErrorEntries(VOID)126 FindMUIErrorEntries(VOID)
127 {
128 ULONG lngIndex = max(FindLanguageIndex(), 0);
129 return ResourceList[lngIndex].MuiErrors;
130 }
131
132 static
133 const MUI_STRING *
FindMUIStringEntries(VOID)134 FindMUIStringEntries(VOID)
135 {
136 ULONG lngIndex = max(FindLanguageIndex(), 0);
137 return ResourceList[lngIndex].MuiStrings;
138 }
139
140
141 VOID
MUIClearPage(IN ULONG page)142 MUIClearPage(
143 IN ULONG page)
144 {
145 const MUI_ENTRY * entry;
146 ULONG index;
147
148 entry = FindMUIEntriesOfPage(page);
149 if (!entry)
150 {
151 PopupError("Error: Failed to find translated page",
152 NULL,
153 NULL,
154 POPUP_WAIT_NONE);
155 return;
156 }
157
158 index = 0;
159 while (entry[index].Buffer != NULL)
160 {
161 CONSOLE_ClearStyledText(entry[index].X,
162 entry[index].Y,
163 entry[index].Flags,
164 (USHORT)strlen(entry[index].Buffer));
165 index++;
166 }
167 }
168
169 VOID
MUIDisplayPage(IN ULONG page)170 MUIDisplayPage(
171 IN ULONG page)
172 {
173 const MUI_ENTRY * entry;
174 ULONG index;
175
176 entry = FindMUIEntriesOfPage(page);
177 if (!entry)
178 {
179 PopupError("Error: Failed to find translated page",
180 NULL,
181 NULL,
182 POPUP_WAIT_NONE);
183 return;
184 }
185
186 index = 0;
187 while (entry[index].Buffer != NULL)
188 {
189 CONSOLE_SetStyledText(entry[index].X,
190 entry[index].Y,
191 entry[index].Flags,
192 entry[index].Buffer);
193
194 index++;
195 }
196 }
197
198 VOID
MUIDisplayErrorV(IN ULONG ErrorNum,OUT PINPUT_RECORD Ir,IN ULONG WaitEvent,IN va_list args)199 MUIDisplayErrorV(
200 IN ULONG ErrorNum,
201 OUT PINPUT_RECORD Ir,
202 IN ULONG WaitEvent,
203 IN va_list args)
204 {
205 const MUI_ERROR* entry;
206 CHAR Buffer[2048];
207
208 if (ErrorNum >= ERROR_LAST_ERROR_CODE)
209 {
210 PopupError("Invalid error number provided",
211 "Press ENTER to continue",
212 Ir,
213 POPUP_WAIT_ENTER);
214 return;
215 }
216
217 entry = FindMUIErrorEntries();
218 if (!entry)
219 {
220 PopupError("Error: Failed to find translated error message",
221 NULL,
222 NULL,
223 POPUP_WAIT_NONE);
224 return;
225 }
226
227 vsprintf(Buffer, entry[ErrorNum].ErrorText, args);
228
229 PopupError(Buffer,
230 entry[ErrorNum].ErrorStatus,
231 Ir,
232 WaitEvent);
233 }
234
235 VOID
236 __cdecl
MUIDisplayError(IN ULONG ErrorNum,OUT PINPUT_RECORD Ir,IN ULONG WaitEvent,...)237 MUIDisplayError(
238 IN ULONG ErrorNum,
239 OUT PINPUT_RECORD Ir,
240 IN ULONG WaitEvent,
241 ...)
242 {
243 va_list arg_ptr;
244
245 va_start(arg_ptr, WaitEvent);
246 MUIDisplayErrorV(ErrorNum, Ir, WaitEvent, arg_ptr);
247 va_end(arg_ptr);
248 }
249
250 PCSTR
MUIGetString(ULONG Number)251 MUIGetString(
252 ULONG Number)
253 {
254 ULONG i;
255 const MUI_STRING * entry;
256 CHAR szErr[128];
257
258 entry = FindMUIStringEntries();
259 if (entry)
260 {
261 for (i = 0; entry[i].Number != 0; i++)
262 {
263 if (entry[i].Number == Number)
264 {
265 return entry[i].String;
266 }
267 }
268 }
269
270 sprintf(szErr, "Error: failed find string id %lu for language index %lu\n", Number, FindLanguageIndex());
271
272 PopupError(szErr,
273 NULL,
274 NULL,
275 POPUP_WAIT_NONE);
276
277 return "<nostring>";
278 }
279
280 /**
281 * @MUIGetEntry
282 *
283 * Retrieves a MUI entry of a page, given the page number and the text ID.
284 *
285 * @param[in] Page
286 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer.
287 *
288 * @param[in] TextID
289 * The text identification number (ID), as a unsigned integer. The parameter is used to identify
290 * its MUI properties like the coordinates, text style flag and its buffer content.
291 *
292 * @return
293 * Returns a constant MUI entry.
294 *
295 */
296 const MUI_ENTRY *
MUIGetEntry(IN ULONG Page,IN INT TextID)297 MUIGetEntry(
298 IN ULONG Page,
299 IN INT TextID)
300 {
301 const MUI_ENTRY * entry;
302 ULONG index;
303
304 /* Retrieve the entries of a MUI page */
305 entry = FindMUIEntriesOfPage(Page);
306 if (!entry)
307 {
308 DPRINT("MUIGetEntryData(): Failed to get the translated entry page!\n");
309 return NULL;
310 }
311
312 /* Loop over the ID entries and check if it matches with one of them */
313 for (index = 0; entry[index].Buffer != NULL; index++)
314 {
315 if (entry[index].TextID == TextID)
316 {
317 /* They match so return the MUI entry */
318 return &entry[index];
319 }
320 }
321
322 /* Page number or ID are incorrect so in this case bail out */
323 DPRINT("Couldn't get the MUI entry field from the page!\n");
324 return NULL;
325 }
326
327 /**
328 * @MUIClearText
329 *
330 * Clears a portion of text from the console output.
331 *
332 * @param[in] Page
333 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer.
334 *
335 * @param[in] TextID
336 * The text identification number (ID), as an integer. The parameter is used to identify
337 * its MUI properties like the coordinates, text style flag and its buffer content.
338 *
339 * @return
340 * Nothing.
341 *
342 */
343 VOID
MUIClearText(IN ULONG Page,IN INT TextID)344 MUIClearText(
345 IN ULONG Page,
346 IN INT TextID)
347 {
348 const MUI_ENTRY * entry;
349 ULONG Index = 0;
350
351 /* Get the MUI entry */
352 entry = MUIGetEntry(Page, TextID);
353
354 if (!entry)
355 return;
356
357 /* Ensure that the text string given by the text ID and page is not NULL */
358 while (entry[Index].Buffer != NULL)
359 {
360 /* If text ID is not correct, skip the entry */
361 if (entry[Index].TextID != TextID)
362 {
363 Index++;
364 continue;
365 }
366
367 /* Remove the text by using CONSOLE_ClearTextXY() */
368 CONSOLE_ClearTextXY(
369 entry[Index].X,
370 entry[Index].Y,
371 (USHORT)strlen(entry[Index].Buffer));
372
373 /* Increment the index and loop over next entires with the same ID */
374 Index++;
375 }
376 }
377
378 /**
379 * @MUIClearStyledText
380 *
381 * Clears a portion of text from the console output, given the actual state style flag of the text.
382 *
383 * @param[in] Page
384 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer.
385 *
386 * @param[in] TextID
387 * The text identification number (ID), as an integer. The parameter is used to identify
388 * its MUI properties like the coordinates, text style flag and its buffer content.
389 *
390 * @param[in] Flags
391 * The text style flag, as an integer. The flag determines the style of the text, such
392 * as being highlighted, underlined, high padding and so on.
393 *
394 * @return
395 * Nothing.
396 *
397 */
398 VOID
MUIClearStyledText(IN ULONG Page,IN INT TextID,IN INT Flags)399 MUIClearStyledText(
400 IN ULONG Page,
401 IN INT TextID,
402 IN INT Flags)
403 {
404 const MUI_ENTRY * entry;
405 ULONG Index = 0;
406
407 /* Get the MUI entry */
408 entry = MUIGetEntry(Page, TextID);
409
410 if (!entry)
411 return;
412
413 /* Ensure that the text string given by the text ID and page is not NULL */
414 while (entry[Index].Buffer != NULL)
415 {
416 /* If text ID is not correct, skip the entry */
417 if (entry[Index].TextID != TextID)
418 {
419 Index++;
420 continue;
421 }
422
423 /* Now, begin removing the text by calling CONSOLE_ClearStyledText() */
424 CONSOLE_ClearStyledText(
425 entry[Index].X,
426 entry[Index].Y,
427 Flags,
428 (USHORT)strlen(entry[Index].Buffer));
429
430 /* Increment the index and loop over next entires with the same ID */
431 Index++;
432 }
433 }
434
435 /**
436 * @MUISetText
437 *
438 * Prints a text to the console output.
439 *
440 * @param[in] Page
441 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer.
442 *
443 * @param[in] TextID
444 * The text identification number (ID), as an integer. The parameter is used to identify
445 * its MUI properties like the coordinates, text style flag and its buffer content.
446 *
447 * @return
448 * Nothing.
449 *
450 */
451 VOID
MUISetText(IN ULONG Page,IN INT TextID)452 MUISetText(
453 IN ULONG Page,
454 IN INT TextID)
455 {
456 const MUI_ENTRY * entry;
457 ULONG Index = 0;
458
459 /* Get the MUI entry */
460 entry = MUIGetEntry(Page, TextID);
461
462 if (!entry)
463 return;
464
465 /* Ensure that the text string given by the text ID and page is not NULL */
466 while (entry[Index].Buffer != NULL)
467 {
468 /* If text ID is not correct, skip the entry */
469 if (entry[Index].TextID != TextID)
470 {
471 Index++;
472 continue;
473 }
474
475 /* Print the text to the console output by calling CONSOLE_SetTextXY() */
476 CONSOLE_SetTextXY(entry[Index].X, entry[Index].Y, entry[Index].Buffer);
477
478 /* Increment the index and loop over next entires with the same ID */
479 Index++;
480 }
481 }
482
483 /**
484 * @MUISetStyledText
485 *
486 * Prints a text to the console output, with a style for it.
487 *
488 * @param[in] Page
489 * The MUI (Multilingual User Interface) entry page number, as a unsigned long integer.
490 *
491 * @param[in] TextID
492 * The text identification number (ID), as an integer. The parameter is used to identify
493 * its MUI properties like the coordinates, text style flag and its buffer content.
494 *
495 * @param[in] Flags
496 * The text style flag, as an integer. The flag determines the style of the text, such
497 * as being highlighted, underlined, high padding and so on.
498 *
499 * @return
500 * Nothing.
501 *
502 */
503 VOID
MUISetStyledText(IN ULONG Page,IN INT TextID,IN INT Flags)504 MUISetStyledText(
505 IN ULONG Page,
506 IN INT TextID,
507 IN INT Flags)
508 {
509 const MUI_ENTRY * entry;
510 ULONG Index = 0;
511
512 /* Get the MUI entry */
513 entry = MUIGetEntry(Page, TextID);
514
515 if (!entry)
516 return;
517
518 /* Ensure that the text string given by the text ID and page is not NULL */
519 while (entry[Index].Buffer != NULL)
520 {
521 /* If text ID is not correct, skip the entry */
522 if (entry[Index].TextID != TextID)
523 {
524 Index++;
525 continue;
526 }
527
528 /* Print the text to the console output by calling CONSOLE_SetStyledText() */
529 CONSOLE_SetStyledText(entry[Index].X, entry[Index].Y, Flags, entry[Index].Buffer);
530
531 /* Increment the index and loop over next entires with the same ID */
532 Index++;
533 }
534 }
535
536 VOID
SetConsoleCodePage(VOID)537 SetConsoleCodePage(VOID)
538 {
539 UINT wCodePage;
540
541 #if 0
542 ULONG lngIndex = 0;
543
544 while (ResourceList[lngIndex].MuiPages != NULL)
545 {
546 if (_wcsicmp(ResourceList[lngIndex].LanguageID, SelectedLanguageId) == 0)
547 {
548 wCodePage = ResourceList[lngIndex].OEMCPage;
549 SetConsoleOutputCP(wCodePage);
550 return;
551 }
552
553 lngIndex++;
554 }
555 #else
556 wCodePage = MUIGetOEMCodePage(SelectedLanguageId);
557 SetConsoleOutputCP(wCodePage);
558 #endif
559
560 switch (wCodePage)
561 {
562 case 28606: /* Romanian */
563 case 932: /* Japanese */
564 /* Set special characters */
565 CharBullet = 0x07;
566 CharBlock = 0x01;
567 CharHalfBlock = 0x02;
568 CharUpArrow = 0x03;
569 CharDownArrow = 0x04;
570 CharHorizontalLine = 0x05;
571 CharVerticalLine = 0x06;
572 CharUpperLeftCorner = 0x08;
573 CharUpperRightCorner = 0x09;
574 CharLowerLeftCorner = 0x0B;
575 CharLowerRightCorner = 0x0C;
576 CharVertLineAndRightHorizLine = 0x0E;
577 CharLeftHorizLineAndVertLine = 0x0F;
578 CharDoubleHorizontalLine = 0x10;
579 CharDoubleVerticalLine = 0x11;
580 CharDoubleUpperLeftCorner = 0x12;
581 CharDoubleUpperRightCorner = 0x13;
582 CharDoubleLowerLeftCorner = 0x14;
583 CharDoubleLowerRightCorner = 0x15;
584
585 /* FIXME: Enter 640x400 video mode */
586 break;
587
588 default: /* Other codepages */
589 /* Set special characters */
590 CharBullet = 0x07;
591 CharBlock = 0xDB;
592 CharHalfBlock = 0xDD;
593 CharUpArrow = 0x18;
594 CharDownArrow = 0x19;
595 CharHorizontalLine = 0xC4;
596 CharVerticalLine = 0xB3;
597 CharUpperLeftCorner = 0xDA;
598 CharUpperRightCorner = 0xBF;
599 CharLowerLeftCorner = 0xC0;
600 CharLowerRightCorner = 0xD9;
601 CharVertLineAndRightHorizLine = 0xC3;
602 CharLeftHorizLineAndVertLine = 0xB4;
603 CharDoubleHorizontalLine = 0xCD;
604 CharDoubleVerticalLine = 0xBA;
605 CharDoubleUpperLeftCorner = 0xC9;
606 CharDoubleUpperRightCorner = 0xBB;
607 CharDoubleLowerLeftCorner = 0xC8;
608 CharDoubleLowerRightCorner = 0xBC;
609
610 /* FIXME: Enter 720x400 video mode */
611 break;
612 }
613 }
614