From 17af27bc7fa82030084c3c3065f9516bfb88a899 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Mon, 13 Aug 2018 14:52:52 +0200 Subject: Windows: code enhancements for language selection mechanism in the installer. --- src/Common/Language.c | 357 +++++++++++++++----------------------------------- src/Setup/Setup.c | 15 ++- src/Setup/Setup.rc | 17 +-- 3 files changed, 126 insertions(+), 263 deletions(-) diff --git a/src/Common/Language.c b/src/Common/Language.c index bcf7b72f..ba0b6d19 100644 --- a/src/Common/Language.c +++ b/src/Common/Language.c @@ -44,6 +44,7 @@ static DWORD LanguageResourceSize = 0; static char *HeaderResource[2] = {NULL, NULL}; static DWORD HeaderResourceSize[2] = {0, 0}; static char ActiveLangPackVersion[6] = {0}; +static int LanguageResourceId = 0; static char *MapFirstLanguageFile () { @@ -59,6 +60,8 @@ static char *MapFirstLanguageFile () LanguageFileBuffer = NULL; } + LanguageResourceId = 0; + if (LanguageResource == NULL) { DWORD size; @@ -81,7 +84,7 @@ static char *MapFirstLanguageFile () } -static char *MapNextLanguageFile () +static char *MapNextLanguageFile (int resourceid) { wchar_t f[TC_MAX_PATH*2], *t; WIN32_FIND_DATAW find; @@ -96,67 +99,90 @@ static char *MapNextLanguageFile () LanguageFileBuffer = NULL; } - if (LanguageFileFindHandle == INVALID_HANDLE_VALUE) + if (resourceid == 0) { - GetModuleFileNameW (NULL, f, sizeof (f) / sizeof (f[0])); - t = wcsrchr (f, L'\\'); - if (t == NULL) return NULL; + if (LanguageFileFindHandle == INVALID_HANDLE_VALUE) + { + GetModuleFileNameW (NULL, f, sizeof (f) / sizeof (f[0])); + t = wcsrchr (f, L'\\'); + if (t == NULL) return NULL; - *t = 0; - StringCbCatW (f, sizeof(f), L"\\Languages\\Language*.xml"); + *t = 0; + StringCbCatW (f, sizeof(f), L"\\Languages\\Language*.xml"); - LanguageFileFindHandle = FindFirstFileW (f, &find); - } - else if (!FindNextFileW (LanguageFileFindHandle, &find)) - { - FindClose (LanguageFileFindHandle); - LanguageFileFindHandle = INVALID_HANDLE_VALUE; - return NULL; - } + LanguageFileFindHandle = FindFirstFileW (f, &find); + } + else if (!FindNextFileW (LanguageFileFindHandle, &find)) + { + FindClose (LanguageFileFindHandle); + LanguageFileFindHandle = INVALID_HANDLE_VALUE; + return NULL; + } - if (LanguageFileFindHandle == INVALID_HANDLE_VALUE) return NULL; - if (find.nFileSizeHigh != 0) return NULL; + if (LanguageFileFindHandle == INVALID_HANDLE_VALUE) return NULL; + if (find.nFileSizeHigh != 0) return NULL; - LanguageFileBuffer = malloc(find.nFileSizeLow + 1); - if (LanguageFileBuffer == NULL) return NULL; + LanguageFileBuffer = malloc(find.nFileSizeLow + 1); + if (LanguageFileBuffer == NULL) return NULL; - GetModuleFileNameW (NULL, f, sizeof (f) / sizeof(f[0])); - t = wcsrchr (f, L'\\'); - if (t == NULL) - { - free(LanguageFileBuffer); - LanguageFileBuffer = NULL; - return NULL; - } + GetModuleFileNameW (NULL, f, sizeof (f) / sizeof(f[0])); + t = wcsrchr (f, L'\\'); + if (t == NULL) + { + free(LanguageFileBuffer); + LanguageFileBuffer = NULL; + return NULL; + } - t[1] = 0; - StringCbCatW (f, sizeof(f), L"Languages\\"); - StringCbCatW (f, sizeof(f),find.cFileName); + t[1] = 0; + StringCbCatW (f, sizeof(f), L"Languages\\"); + StringCbCatW (f, sizeof(f),find.cFileName); - file = CreateFileW (f, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); - if (file == INVALID_HANDLE_VALUE) - { - free(LanguageFileBuffer); - LanguageFileBuffer = NULL; - return NULL; - } + file = CreateFileW (f, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (file == INVALID_HANDLE_VALUE) + { + free(LanguageFileBuffer); + LanguageFileBuffer = NULL; + return NULL; + } - bStatus = ReadFile (file, LanguageFileBuffer, find.nFileSizeLow, &read, NULL); - CloseHandle (file); - if (!bStatus || (read != find.nFileSizeLow)) - { - free(LanguageFileBuffer); - LanguageFileBuffer = NULL; - return NULL; + bStatus = ReadFile (file, LanguageFileBuffer, find.nFileSizeLow, &read, NULL); + CloseHandle (file); + if (!bStatus || (read != find.nFileSizeLow)) + { + free(LanguageFileBuffer); + LanguageFileBuffer = NULL; + return NULL; + } + + LanguageFileBuffer [find.nFileSizeLow] = 0; // we have allocated (find.nFileSizeLow + 1) bytes } + else if (LanguageResourceId != resourceid) + { + DWORD size; + + LanguageResourceId = resourceid; + + LanguageResource = MapResource (L"Languages", LanguageResourceId, &size); + if (LanguageResource) + LanguageResourceSize = size; - LanguageFileBuffer [find.nFileSizeLow] = 0; // we have allocated (find.nFileSizeLow + 1) bytes + if (LanguageResource) + { + LanguageFileBuffer = malloc(LanguageResourceSize + 1); + if (LanguageFileBuffer) + { + memcpy (LanguageFileBuffer, LanguageResource, LanguageResourceSize); + LanguageFileBuffer[LanguageResourceSize] = 0; + } + } + } return LanguageFileBuffer; } -BOOL LoadLanguageFile () +static BOOL LoadLanguageData (int resourceid, BOOL bForceSetPreferredLanguage, BOOL bForceSilent) { DWORD size; BYTE *res; @@ -184,11 +210,11 @@ BOOL LoadLanguageFile () ActiveLangPackVersion[0] = 0; ClearDictionaryPool (); - if (PreferredLangId[0] != 0) + if ((resourceid == 0) && (PreferredLangId[0] != 0)) StringCbCopyA (langId, sizeof(langId), PreferredLangId); // Parse all available language files until preferred language is found - for (res = MapFirstLanguageFile (); res != NULL; res = MapNextLanguageFile ()) + for (res = MapFirstLanguageFile (); res != NULL; res = MapNextLanguageFile (resourceid)) { xml = (char *) res; xml = XmlFindElement (xml, "localization"); @@ -203,7 +229,8 @@ BOOL LoadLanguageFile () { wchar_t m[2048]; StringCbPrintfW (m, sizeof(m), L"The installed language pack is incompatible with this version of VeraCrypt (the language pack is for VeraCrypt %hs). A newer version may be available at www.idrix.fr.\n\nTo prevent this message from being displayed, do any of the following:\n\n- Select 'Settings' > 'Language'; then select 'English' and click 'OK'.\n\n- Remove or replace the language pack with a compatible version (the language pack may reside e.g. in 'C:\\Program Files\\VeraCrypt' or '%%LOCALAPPDATA%%\\VirtualStore\\Program Files\\VeraCrypt', etc.)", attr); - MessageBoxW (NULL, m, L"VeraCrypt", MB_ICONERROR); + if (!bForceSilent) + MessageBoxW (NULL, m, L"VeraCrypt", MB_ICONERROR); continue; } @@ -213,13 +240,23 @@ BOOL LoadLanguageFile () while (xml = XmlFindElement (xml, "language")) { XmlGetAttributeText (xml, "langid", attr, sizeof (attr)); - if (strcmp (attr, langId) == 0) + if (resourceid == 0) + { + if (strcmp (attr, langId) == 0) + { + XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion)); + langFound = TRUE; + break; + } + xml++; + } + else { + StringCbCopyA (langId, sizeof (langId), attr); XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion)); langFound = TRUE; break; } - xml++; } if (!langFound) continue; @@ -288,7 +325,8 @@ BOOL LoadLanguageFile () case 't': *out++ = '\t'; break; case 'n': *out++ = 13; *out++ = 10; break; default: - MessageBoxA (0, key, "VeraCrypt: Unknown '\\' escape sequence in string", MB_ICONERROR); + if (!bForceSilent) + MessageBoxA (0, key, "VeraCrypt: Unknown '\\' escape sequence in string", MB_ICONERROR); return FALSE; } } @@ -302,7 +340,8 @@ BOOL LoadLanguageFile () len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0])); if (len == 0) { - MessageBoxA (0, key, "VeraCrypt: Error while decoding UTF-8 string", MB_ICONERROR); + if (!bForceSilent) + MessageBoxA (0, key, "VeraCrypt: Error while decoding UTF-8 string", MB_ICONERROR); return FALSE; } @@ -324,7 +363,7 @@ BOOL LoadLanguageFile () if (!defaultLangParsed) { defaultLangParsed = TRUE; - if (langId[0] == 0 || strcmp (langId, "en") == 0) + if ((resourceid == 0) && (langId[0] == 0 || strcmp (langId, "en") == 0)) break; } } @@ -332,6 +371,9 @@ BOOL LoadLanguageFile () LocalizationActive = langFound && strcmp (langId, "en") != 0; LocalizationSerialNo++; + if (bForceSetPreferredLanguage) + StringCbCopyA (PreferredLangId, sizeof (PreferredLangId), langId); + // Create control ID dictionary // Default controls @@ -383,208 +425,15 @@ BOOL LoadLanguageFile () return TRUE; } -BOOL LoadLanguageFromResource (int resourceid, BOOL bSetPreferredLanguage, BOOL bForceSilent) +BOOL LoadLanguageFile () { - DWORD size; - BYTE *res; - char *xml, *header, *headerPtr; - char langId[16] = "en", attr[32768], key[128]; - BOOL defaultLangParsed = FALSE, langFound = FALSE; - WCHAR wattr[32768]; - int i, intKey, len; - -#ifdef TCMOUNT - int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_MOUNT_RSRC_HEADER, 0 }; -#endif - -#ifdef VOLFORMAT - int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_FORMAT_RSRC_HEADER, 0 }; -#endif - -#ifdef SETUP - int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_SETUP_RSRC_HEADER, 0 }; -#endif - - res = (char*) MapResource (L"Languages", resourceid, &size); - if (!res) - return FALSE; - - LocalizationActive = FALSE; - ActiveLangPackVersion[0] = 0; - ClearDictionaryPool (); - - xml = res; - xml = XmlFindElement (xml, "localization"); - if (!xml) - return FALSE; - - // Required VeraCrypt version - XmlGetAttributeText (xml, "prog-version", attr, sizeof (attr)); - - // Search language id in language file - while (xml = XmlFindElement (xml, "language")) - { - XmlGetAttributeText (xml, "langid", attr, sizeof (attr)); - if (strlen (attr)) - { - StringCbCopyA (langId, sizeof (langId), attr); - XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion)); - langFound = TRUE; - break; - } - xml++; - } - - if (!langFound) return FALSE; - - // Create font dictionary - xml = (char *) res; - while (xml = XmlFindElement (xml, "font")) - { - XmlGetAttributeText (xml, "lang", attr, sizeof (attr)); - if (strcmp (attr, langId) == 0) - { - Font font; - memset (&font, 0, sizeof (font)); - - XmlGetAttributeText (xml, "face", attr, sizeof (attr)); - - len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0])); - font.FaceName = AddPoolData ((void *) wattr, len * 2); - - XmlGetAttributeText (xml, "size", attr, sizeof (attr)); - sscanf (attr, "%d", &font.Size); - - StringCbCopyA (attr, sizeof(attr), "font_"); - XmlGetAttributeText (xml, "class", attr + 5, sizeof (attr) - 5); - AddDictionaryEntry ( - AddPoolData ((void *) attr, strlen (attr) + 1), 0, - AddPoolData ((void *) &font, sizeof(font))); - } - - xml++; - } - - xml = (char *) res; - while (xml = XmlFindElement (xml, "entry")) - { - void *key; - void *text; - - XmlGetAttributeText (xml, "lang", attr, sizeof (attr)); - if (strcmp (attr, langId) == 0) - { - if (XmlGetAttributeText (xml, "key", attr, sizeof (attr))) - { - key = AddPoolData (attr, strlen (attr) + 1); - if (key == NULL) return FALSE; - - XmlGetNodeText (xml, attr, sizeof (attr)); - - // Parse \ escape sequences - { - char *in = attr, *out = attr; - while (*in) - { - if (*in == '\\') - { - in++; - switch (*in++) - { - case '\\': *out++ = '\\'; break; - case 't': *out++ = '\t'; break; - case 'n': *out++ = 13; *out++ = 10; break; - default: - if (!bForceSilent) - MessageBoxA (0, key, "VeraCrypt: Unknown '\\' escape sequence in string", MB_ICONERROR); - return FALSE; - } - } - else - *out++ = *in++; - } - *out = 0; - } - - // UTF8 => wide char - len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0])); - if (len == 0) - { - if (!bForceSilent) - MessageBoxA (0, key, "VeraCrypt: Error while decoding UTF-8 string", MB_ICONERROR); - return FALSE; - } - - // Add to dictionary - text = AddPoolData ((void *) wattr, len * 2); - if (text == NULL) return FALSE; - - AddDictionaryEntry ((char *) key, 0, text); - } - } - - xml++; - } - - defaultLangParsed = TRUE; - - LocalizationActive = strcmp (langId, "en") != 0; - LocalizationSerialNo++; - - if (bSetPreferredLanguage) - StringCbCopyA (PreferredLangId, sizeof (PreferredLangId), langId); - - // Create control ID dictionary - - // Default controls - AddDictionaryEntry (NULL, 1, GetString ("IDOK")); - AddDictionaryEntry (NULL, 2, GetString ("IDCANCEL")); - AddDictionaryEntry (NULL, 8, GetString ("IDCLOSE")); - AddDictionaryEntry (NULL, 9, GetString ("IDHELP")); - - for (i = 0; headers[i] != 0; i++) - { - if (HeaderResource[i] == NULL) - { - HeaderResource[i] = MapResource (L"Header", headers[i], &size); - if (HeaderResource[i]) - HeaderResourceSize[i] = size; - } - - headerPtr = NULL; - if (HeaderResource[i]) - { - headerPtr = (char*) malloc (HeaderResourceSize[i] + 1); - if (headerPtr) - { - memcpy (headerPtr, HeaderResource[i], HeaderResourceSize[i]); - headerPtr [HeaderResourceSize[i]] = 0; - } - } - - header = headerPtr; - if (header == NULL) return FALSE; - header--; - - do - { - header++; - if (sscanf (header, "#define %127s %d", key, &intKey) == 2) - { - WCHAR *str = GetString (key); - - if (str != UnknownString) - AddDictionaryEntry (NULL, intKey, str); - } - - } while ((header = strchr (header, '\n')) != NULL); - - free (headerPtr); - } - - return TRUE; + return LoadLanguageData (0, FALSE, FALSE); } +BOOL LoadLanguageFromResource (int resourceid, BOOL bSetPreferredLanguage, BOOL bForceSilent) +{ + return LoadLanguageData (resourceid, bSetPreferredLanguage, bForceSilent); +} // lParam = 1: auto mode BOOL CALLBACK LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) @@ -606,7 +455,7 @@ BOOL CALLBACK LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa LocalizeDialog (hwndDlg, "IDD_LANGUAGE"); ToHyperlink (hwndDlg, IDC_GET_LANG_PACKS); - for (xml = MapFirstLanguageFile (); xml != NULL; xml = MapNextLanguageFile ()) + for (xml = MapFirstLanguageFile (); xml != NULL; xml = MapNextLanguageFile (0)) { while (xml = XmlFindElement (xml, "language")) { diff --git a/src/Setup/Setup.c b/src/Setup/Setup.c index 986bc122..3c638364 100644 --- a/src/Setup/Setup.c +++ b/src/Setup/Setup.c @@ -2414,10 +2414,15 @@ static void UpdateSelectLanguageDialog (HWND hwndDlg) HWND hLangList = GetDlgItem (hwndDlg, IDC_LANGUAGES_LIST); LPARAM nIndex = SendMessage (hLangList, CB_GETCURSEL, 0, 0); int resourceid = (int) SendMessage (hLangList, CB_GETITEMDATA, nIndex, 0); + BOOL bVal; LoadLanguageFromResource (resourceid, TRUE, TRUE); + bVal = LocalizationActive; + LocalizationActive = TRUE; LocalizeDialog (hwndDlg, "IDD_INSTL_DLG"); + InvalidateRect (hwndDlg, NULL, FALSE); + LocalizationActive = bVal; } BOOL CALLBACK SelectLanguageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -2660,7 +2665,15 @@ int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, wchar_t *lpsz { if (!bDevm && !LocalizationActive && (nCurrentOS >= WIN_VISTA)) { - DialogBoxParamW (hInstance, MAKEINTRESOURCEW (IDD_INSTALL_LANGUAGE), NULL, (DLGPROC) SelectLanguageDialogProc, (LPARAM) 0 ); + BOOL bHasPreferredLanguage = (strlen (GetPreferredLangId ()) > 0)? TRUE : FALSE; + if ((IDCANCEL == DialogBoxParamW (hInstance, MAKEINTRESOURCEW (IDD_INSTALL_LANGUAGE), NULL, (DLGPROC) SelectLanguageDialogProc, (LPARAM) 0 )) + && !bHasPreferredLanguage + ) + { + // Language dialog cancelled by user: exit the installer + FinalizeApp (); + exit (1); + } } /* Create the main dialog for install */ diff --git a/src/Setup/Setup.rc b/src/Setup/Setup.rc index 5e8a16aa..3323f9f0 100644 --- a/src/Setup/Setup.rc +++ b/src/Setup/Setup.rc @@ -205,18 +205,19 @@ BEGIN PUSHBUTTON "Donate now...",IDC_DONATE,124,94,96,14 END -IDD_INSTALL_LANGUAGE DIALOGEX 0, 0, 213, 87 +IDD_INSTALL_LANGUAGE DIALOGEX 0, 0, 214, 75 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "VeraCrypt Setup Wizard" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - DEFPUSHBUTTON "OK",IDOK,102,66,50,14 - PUSHBUTTON "Cancel",IDCANCEL,156,66,50,14 - ICON 501,IDC_STATIC,10,10,32,32 - LTEXT "Select the language to use during the installation:",IDC_SELECT_LANGUAGE_LABEL,42,13,157,26 - COMBOBOX IDC_LANGUAGES_LIST,42,44,164,155,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK",IDOK,102,54,50,14 + PUSHBUTTON "Cancel",IDCANCEL,157,54,50,14 + ICON IDI_SETUP,IDC_STATIC,10,10,32,32 + LTEXT "Select the language to use during the installation:",IDC_SELECT_LANGUAGE_LABEL,42,13,158,17 + COMBOBOX IDC_LANGUAGES_LIST,42,36,164,155,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END + ///////////////////////////////////////////////////////////////////////////// // // Icon @@ -334,9 +335,9 @@ BEGIN IDD_INSTALL_LANGUAGE, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 206 + RIGHTMARGIN, 207 TOPMARGIN, 7 - BOTTOMMARGIN, 80 + BOTTOMMARGIN, 68 END END #endif // APSTUDIO_INVOKED -- cgit v1.2.3