xref: /reactos/base/setup/usetup/mui.c (revision 3a49e26f)
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
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 *
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 *
126 FindMUIErrorEntries(VOID)
127 {
128     ULONG lngIndex = max(FindLanguageIndex(), 0);
129     return ResourceList[lngIndex].MuiErrors;
130 }
131 
132 static
133 const MUI_STRING *
134 FindMUIStringEntries(VOID)
135 {
136     ULONG lngIndex = max(FindLanguageIndex(), 0);
137     return ResourceList[lngIndex].MuiStrings;
138 }
139 
140 
141 VOID
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
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
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
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
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 *
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
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
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
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
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
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