summaryrefslogtreecommitdiff
path: root/Common/Language.c
diff options
context:
space:
mode:
authorJedidiah Barber <contact@jedbarber.id.au>2021-07-14 11:27:03 +1200
committerJedidiah Barber <contact@jedbarber.id.au>2021-07-14 11:27:03 +1200
commit3cb7fdea950dd2d0377f0d9ad8a88fcb7c48b842 (patch)
treecedbfc08a6bf0bd8cb6ec6c8d8dd94a4e715439b /Common/Language.c
Initial mirror commitHEADmaster
Diffstat (limited to 'Common/Language.c')
-rw-r--r--Common/Language.c515
1 files changed, 515 insertions, 0 deletions
diff --git a/Common/Language.c b/Common/Language.c
new file mode 100644
index 0000000..e7737ca
--- /dev/null
+++ b/Common/Language.c
@@ -0,0 +1,515 @@
+/*
+ Copyright (c) 2005-2009 TrueCrypt Developers Association. All rights reserved.
+
+ Governed by the TrueCrypt License 3.0 the full text of which is contained in
+ the file License.txt included in TrueCrypt binary and source code distribution
+ packages.
+*/
+
+#include "Language.h"
+#include "Dlgcode.h"
+#include "Dictionary.h"
+#include "Tcdefs.h"
+#include "Xml.h"
+
+#include "../Common/Resource.h"
+
+#ifdef TCMOUNT
+#include "../Mount/Resource.h"
+#endif
+
+#ifdef VOLFORMAT
+#include "../Format/Resource.h"
+#endif
+
+#ifdef SETUP
+#include "../Setup/Resource.h"
+#endif
+
+BOOL LocalizationActive;
+int LocalizationSerialNo;
+
+wchar_t UnknownString[1024];
+static char *LanguageFileBuffer;
+static HANDLE LanguageFileFindHandle = INVALID_HANDLE_VALUE;
+static char PreferredLangId[6];
+static char *LanguageResource;
+static char *HeaderResource[2];
+static char ActiveLangPackVersion[6];
+
+static char *MapFirstLanguageFile ()
+{
+ if (LanguageFileFindHandle != INVALID_HANDLE_VALUE)
+ {
+ FindClose (LanguageFileFindHandle);
+ LanguageFileFindHandle = INVALID_HANDLE_VALUE;
+ }
+
+ if (LanguageResource == NULL)
+ {
+ DWORD size;
+ LanguageResource = MapResource ("Xml", IDR_LANGUAGE, &size);
+ LanguageResource[size - 1] = 0;
+ }
+
+ return LanguageResource;
+}
+
+
+static char *MapNextLanguageFile ()
+{
+ wchar_t f[TC_MAX_PATH*2], *t;
+ WIN32_FIND_DATAW find;
+ HANDLE file;
+ DWORD read;
+
+ if (LanguageFileFindHandle == INVALID_HANDLE_VALUE)
+ {
+ GetModuleFileNameW (NULL, f, sizeof (f) / sizeof (f[0]));
+ t = wcsrchr (f, L'\\');
+ if (t == NULL) return NULL;
+
+ wcscpy (t, L"\\Language*.xml");
+
+ LanguageFileFindHandle = FindFirstFileW (f, &find);
+ }
+ else if (!FindNextFileW (LanguageFileFindHandle, &find))
+ {
+ FindClose (LanguageFileFindHandle);
+ LanguageFileFindHandle = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+
+ if (find.nFileSizeHigh != 0) return NULL;
+
+ if (LanguageFileBuffer != NULL) free (LanguageFileBuffer);
+ LanguageFileBuffer = malloc(find.nFileSizeLow);
+ if (LanguageFileBuffer == NULL) return NULL;
+
+ GetModuleFileNameW (NULL, f, sizeof (f) / sizeof(f[0]));
+ t = wcsrchr (f, L'\\');
+ wcscpy (t + 1, find.cFileName);
+
+ file = CreateFileW (f, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (file == INVALID_HANDLE_VALUE) return NULL;
+
+ ReadFile (file, LanguageFileBuffer, find.nFileSizeLow, &read, NULL);
+ CloseHandle (file);
+ if (read != find.nFileSizeLow) return NULL;
+
+ return LanguageFileBuffer;
+}
+
+
+BOOL LoadLanguageFile ()
+{
+ DWORD size;
+ BYTE *res;
+ char *xml, *header;
+ char langId[6] = "en", attr[32768], key[128];
+ BOOL defaultLangParsed = FALSE, langFound = FALSE;
+ WCHAR wattr[32768];
+ int i, intKey, len;
+
+ char *xmlElements[] = {"control", "string", 0};
+
+#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
+
+ LocalizationActive = FALSE;
+ ActiveLangPackVersion[0] = 0;
+ ClearDictionaryPool ();
+
+ if (PreferredLangId[0] != 0)
+ strcpy (langId, PreferredLangId);
+
+ // Parse all available language files until preferred language is found
+ for (res = MapFirstLanguageFile (); res != NULL; res = MapNextLanguageFile ())
+ {
+ xml = (char *) res;
+ xml = XmlFindElement (xml, "localization");
+ if (!xml)
+ continue;
+
+ // Required TrueCrypt version
+ XmlGetAttributeText (xml, "prog-version", attr, sizeof (attr));
+
+ // Check version of external language file
+ if (defaultLangParsed && strcmp (attr, VERSION_STRING) && strcmp (attr, "DEBUG"))
+ {
+ wchar_t m[2048];
+ swprintf (m, L"The installed language pack is incompatible with this version of TrueCrypt (the language pack is for TrueCrypt %hs). A newer version may be available at www.truecrypt.org.\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\\TrueCrypt' or '%%LOCALAPPDATA%%\\VirtualStore\\Program Files\\TrueCrypt', etc.)", attr);
+ MessageBoxW (NULL, m, L"TrueCrypt", MB_ICONERROR);
+ continue;
+ }
+
+ // Search language id in language file
+ if (defaultLangParsed)
+ {
+ while (xml = XmlFindElement (xml, "language"))
+ {
+ XmlGetAttributeText (xml, "langid", attr, sizeof (attr));
+ if (strcmp (attr, langId) == 0)
+ {
+ XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion));
+ langFound = TRUE;
+ break;
+ }
+ xml++;
+ }
+
+ if (!langFound) continue;
+ }
+
+ // Create font dictionary
+ xml = (char *) res;
+ while (xml = XmlFindElement (xml, "font"))
+ {
+ XmlGetAttributeText (xml, "lang", attr, sizeof (attr));
+ if (!defaultLangParsed
+ || 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);
+
+ strcpy (attr, "font_");
+ XmlGetAttributeText (xml, "class", attr + 5, sizeof (attr) - 5);
+ AddDictionaryEntry (
+ AddPoolData ((void *) attr, strlen (attr) + 1), 0,
+ AddPoolData ((void *) &font, sizeof(font)));
+ }
+
+ xml++;
+ }
+
+ // Create string and control dictionaries
+ for (i = 0; xmlElements[i] != 0; i++)
+ {
+ xml = (char *) res;
+ while (xml = XmlFindElement (xml, xmlElements[i]))
+ {
+ void *key;
+ void *text;
+
+ XmlGetAttributeText (xml, "lang", attr, sizeof (attr));
+ if (!defaultLangParsed
+ || 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:
+ MessageBox (0, key, "TrueCrypt: 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 || len == ERROR_NO_UNICODE_TRANSLATION)
+ {
+ MessageBox (0, key, "TrueCrypt: 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++;
+ }
+ }
+
+ if (langFound)
+ break;
+
+ if (!defaultLangParsed)
+ {
+ defaultLangParsed = TRUE;
+ if (langId[0] == 0 || strcmp (langId, "en") == 0)
+ break;
+ }
+ }
+
+ LocalizationActive = langFound && strcmp (langId, "en") != 0;
+ LocalizationSerialNo++;
+
+ // 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 ("Header", headers[i], &size);
+ *(HeaderResource[i] + size - 1) = 0;
+ }
+
+ header = HeaderResource[i];
+ if (header == NULL) return FALSE;
+
+ do
+ {
+ if (sscanf (header, "#define %s %d", key, &intKey) == 2)
+ {
+ WCHAR *str = GetString (key);
+
+ if (str != UnknownString)
+ AddDictionaryEntry (NULL, intKey, str);
+ }
+
+ } while ((header = strchr (header, '\n') + 1) != (char *) 1);
+ }
+
+ return TRUE;
+}
+
+
+// lParam = 1: auto mode
+BOOL CALLBACK LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ WORD hw = HIWORD (wParam);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char *xml;
+ char attr[2048], lastLangId[10];
+ WCHAR wattr[2048];
+ int len;
+ int langCount = 0;
+ BOOL defaultLangFound = FALSE;
+
+ LocalizeDialog (hwndDlg, "IDD_LANGUAGE");
+ ToHyperlink (hwndDlg, IDC_GET_LANG_PACKS);
+
+ for (xml = MapFirstLanguageFile (); xml != NULL; xml = MapNextLanguageFile ())
+ {
+ while (xml = XmlFindElement (xml, "language"))
+ {
+ XmlGetAttributeText (xml, "name", attr, sizeof (attr));
+ len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0]));
+
+ if (len != 0 && len != ERROR_NO_UNICODE_TRANSLATION
+ && (!defaultLangFound || wcscmp (wattr, L"English") != 0))
+ {
+ int i = SendDlgItemMessageW (hwndDlg, IDC_LANGLIST, LB_ADDSTRING, 0, (LPARAM)wattr);
+ if (i >= 0)
+ {
+ int id;
+
+ // Encode language id in LPARAM
+ XmlGetAttributeText (xml, "langid", attr, sizeof (attr));
+ switch (strlen (attr))
+ {
+ case 2: id = attr[0] | attr[1] << 8; break;
+ case 5: id = attr[0] | attr[1] << 8 | attr[3] << 16 | attr[4] << 24; break;
+ default: continue;
+ }
+
+ if (!defaultLangFound)
+ defaultLangFound = TRUE;
+
+ SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETITEMDATA, i, (LPARAM) id);
+
+ if (strcmp (attr, PreferredLangId) == 0)
+ {
+ char credits [10000];
+ WCHAR wcredits [10000];
+ WCHAR wversion [20];
+ wchar_t szVers [200];
+ int nLen;
+
+ SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETCURSEL, i, 0);
+
+ // Language pack version
+ if (!ActiveLangPackVersion[0] || memcmp (ActiveLangPackVersion, "0.0.0", 5) == 0)
+ {
+ swprintf (szVers, GetString("LANG_PACK_VERSION"), L"--");
+ }
+ else
+ {
+ nLen = MultiByteToWideChar (CP_UTF8, 0, ActiveLangPackVersion, -1, wversion, sizeof (wversion) / sizeof(wversion[0]));
+ if (nLen != 0 && nLen != ERROR_NO_UNICODE_TRANSLATION)
+ swprintf (szVers, GetString("LANG_PACK_VERSION"), wversion);
+ }
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_VERSION), szVers);
+
+ // Translator credits
+ XmlGetAttributeText (xml, "translators", credits, sizeof (credits));
+ nLen = MultiByteToWideChar (CP_UTF8, 0, credits, -1, wcredits, sizeof (wcredits) / sizeof(wcredits[0]));
+ if (nLen != 0 && nLen != ERROR_NO_UNICODE_TRANSLATION)
+ {
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_CREDITS), wcredits);
+ }
+ }
+
+ strcpy (lastLangId, attr);
+ langCount++;
+ }
+ }
+
+ xml++;
+ }
+ }
+
+ if (lParam == 1)
+ {
+ // Auto mode
+ if (langCount < 2)
+ EndDialog (hwndDlg, IDCANCEL);
+
+ if (langCount == 2)
+ strcpy (PreferredLangId, lastLangId);
+
+ EndDialog (hwndDlg, IDOK);
+ }
+
+ return 1;
+ }
+
+ case WM_COMMAND:
+
+ if (lw == IDOK || hw == LBN_DBLCLK)
+ {
+ int i = SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCURSEL, 0, 0);
+
+ if (i >= 0)
+ {
+ int id = SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETITEMDATA, i, 0);
+
+ if (id != LB_ERR)
+ {
+ char l[6];
+
+ // Decode language id from LPARAM
+ l[0] = (char) id;
+ l[1] = (char) (id >> 8);
+ l[2] = 0;
+
+ if ((id & 0xffff0000) != 0)
+ {
+ l[2] = '-';
+ l[3] = (char) (id >> 16);
+ l[4] = id >> 24;
+ l[5] = 0;
+ }
+
+ if (SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCOUNT, 0, 0) > 1)
+ strcpy (PreferredLangId, l);
+ }
+ }
+
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+
+ if (lw == IDCANCEL)
+ {
+ EndDialog (hwndDlg, lw);
+ return 1;
+ }
+
+ if (lw == IDC_GET_LANG_PACKS)
+ {
+ char tmpstr [256];
+
+ if (strlen (ActiveLangPackVersion) > 0 && strlen (GetPreferredLangId()) > 0)
+ sprintf (tmpstr, "&langpackversion=%s&lang=%s", ActiveLangPackVersion, GetPreferredLangId());
+ else
+ tmpstr[0] = 0;
+
+ Applink ("localizations", TRUE, tmpstr);
+
+ return 1;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+
+char *GetPreferredLangId ()
+{
+ return PreferredLangId;
+}
+
+
+void SetPreferredLangId (char *langId)
+{
+ strncpy (PreferredLangId, langId, 5);
+}
+
+
+char *GetActiveLangPackVersion ()
+{
+ return ActiveLangPackVersion;
+}
+
+
+wchar_t *GetString (const char *stringId)
+{
+ WCHAR *str = (WCHAR *) GetDictionaryValue (stringId);
+ if (str != NULL) return str;
+
+ wsprintfW (UnknownString, UNKNOWN_STRING_ID L"%hs" UNKNOWN_STRING_ID, stringId);
+ return UnknownString;
+}
+
+
+Font *GetFont (char *fontType)
+{
+ return (Font *) GetDictionaryValue (fontType);
+
+}