|
|
1.1 root 1: /*
2: Copyright (c) 2004-2005 TrueCrypt Foundation. All rights reserved.
3:
4: Covered by TrueCrypt License 2.0 the full text of which is contained in the file
5: License.txt included in TrueCrypt binary and source code distribution archives.
6: */
7:
8: #include "Language.h"
9: #include "Dlgcode.h"
10: #include "Dictionary.h"
11: #include "Tcdefs.h"
12: #include "Xml.h"
13:
14: #include "../Common/Resource.h"
15:
16: #ifdef TCMOUNT
17: #include "../Mount/Resource.h"
18: #endif
19:
20: #ifdef VOLFORMAT
21: #include "../Format/Resource.h"
22: #endif
23:
24: #ifdef SETUP
25: #include "../Setup/Resource.h"
26: #endif
27:
28: BOOL LocalizationActive;
29: int LocalizationSerialNo;
30:
31: wchar_t UnknownString[1024];
32: static char *LanguageFileBuffer;
33: static HANDLE LanguageFileFindHandle = INVALID_HANDLE_VALUE;
34: static char PreferredLangId[6];
35: static char *LanguageResource;
36: static char *HeaderResource[2];
37: static char ActiveLangPackVersion[6];
38:
39: static char *MapFirstLanguageFile ()
40: {
41: if (LanguageFileFindHandle != INVALID_HANDLE_VALUE)
42: {
43: FindClose (LanguageFileFindHandle);
44: LanguageFileFindHandle = INVALID_HANDLE_VALUE;
45: }
46:
47: if (LanguageResource == NULL)
48: LanguageResource = MapResource ("Xml", IDR_LANGUAGE, NULL);
49:
50: return LanguageResource;
51: }
52:
53:
54: static char *MapNextLanguageFile ()
55: {
56: wchar_t f[TC_MAX_PATH*2], *t;
57: WIN32_FIND_DATAW find;
58: HANDLE file;
59: DWORD read;
60:
61: if (LanguageFileFindHandle == INVALID_HANDLE_VALUE)
62: {
63: GetModuleFileNameW (NULL, f, sizeof (f));
64: t = wcsrchr (f, L'\\');
65: if (t == NULL) return NULL;
66:
67: wcscpy (t, L"\\Language*.xml");
68:
69: LanguageFileFindHandle = FindFirstFileW (f, &find);
70: }
71: else if (!FindNextFileW (LanguageFileFindHandle, &find))
72: {
73: FindClose (LanguageFileFindHandle);
74: LanguageFileFindHandle = INVALID_HANDLE_VALUE;
75: return NULL;
76: }
77:
78: if (find.nFileSizeHigh != 0) return NULL;
79:
80: if (LanguageFileBuffer != NULL) free (LanguageFileBuffer);
81: LanguageFileBuffer = malloc(find.nFileSizeLow);
82: if (LanguageFileBuffer == NULL) return NULL;
83:
84: GetModuleFileNameW (NULL, f, sizeof (f));
85: t = wcsrchr (f, L'\\');
86: wcscpy (t + 1, find.cFileName);
87:
88: file = CreateFileW (f, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
89: if (file == INVALID_HANDLE_VALUE) return NULL;
90:
91: ReadFile (file, LanguageFileBuffer, find.nFileSizeLow, &read, NULL);
92: CloseHandle (file);
93: if (read != find.nFileSizeLow) return NULL;
94:
95: return LanguageFileBuffer;
96: }
97:
98:
99: BOOL LoadLanguageFile ()
100: {
101: DWORD size;
102: BYTE *res;
103: char *xml, *header;
104: char langId[6] = "en", attr[2048], key[128];
105: BOOL defaultLangParsed = FALSE, langFound = FALSE;
106: WCHAR wattr[2048];
107: int i, intKey, len;
108:
109: char *xmlElements[] = {"control", "string", 0};
110:
111: #ifdef TCMOUNT
112: int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_MOUNT_RSRC_HEADER, 0 };
113: #endif
114:
115: #ifdef VOLFORMAT
116: int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_FORMAT_RSRC_HEADER, 0 };
117: #endif
118:
119: #ifdef SETUP
120: int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_SETUP_RSRC_HEADER, 0 };
121: #endif
122:
123: LocalizationActive = FALSE;
124: ClearDictionaryPool ();
125:
126: if (PreferredLangId[0] != 0)
127: strcpy (langId, PreferredLangId);
128:
129: // Parse all available language files until preferred language is found
130: for (res = MapFirstLanguageFile (); res != NULL; res = MapNextLanguageFile ())
131: {
132: xml = (char *) res;
133: xml = XmlFindElement (xml, "localization");
134: // Required TrueCrypt version
135: XmlAttribute (xml, "prog-version", attr, sizeof (attr));
136:
137: // Check version of external language file
138: if (defaultLangParsed && strcmp (attr, VERSION_STRING))
139: {
140: wchar_t m[1024];
141: swprintf (m, L"The installed language pack is incompatible with this version of TrueCrypt\n(this language pack is for TrueCrypt %hs).\n\nA newer version may be available at www.truecrypt.org.\n\nTo prevent this message from being displayed, do any of the following:\n- Update the language pack\n- Remove the language pack file from the TrueCrypt folder", attr);
142: MessageBoxW (NULL, m, L"TrueCrypt", MB_ICONERROR);
143: continue;
144: }
145:
146: // Search language id in language file
147: if (defaultLangParsed)
148: {
149: while (xml = XmlFindElement (xml, "language"))
150: {
151: XmlAttribute (xml++, "langid", attr, sizeof (attr));
152: if (strcmp (attr, langId) == 0)
153: {
154: langFound = TRUE;
155: break;
156: }
157: }
158:
159: if (!langFound) continue;
160: }
161:
162: // Create font dictionary
163: xml = (char *) res;
164: while (xml = XmlFindElement (xml, "font"))
165: {
166: XmlAttribute (xml, "lang", attr, sizeof (attr));
167: if (!defaultLangParsed
168: || strcmp (attr, langId) == 0)
169: {
170: Font font;
171:
172: XmlAttribute (xml, "face", attr, sizeof (attr));
173:
174: len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr));
175: font.FaceName = AddPoolData ((void *) wattr, len * 2);
176:
177: XmlAttribute (xml, "size", attr, sizeof (attr));
178: sscanf (attr, "%d", &font.Size);
179:
180: strcpy (attr, "font_");
181: XmlAttribute (xml, "class", attr + 5, sizeof (attr) - 5);
182: AddDictionaryEntry (AddPoolData ((void *) attr, sizeof (attr)), 0,
183: AddPoolData ((void *) &font, sizeof(font)));
184: }
185:
186: xml++;
187: }
188:
189: // Create string and control dictionaries
190: for (i = 0; xmlElements[i] != 0; i++)
191: {
192: xml = (char *) res;
193: while (xml = XmlFindElement (xml, xmlElements[i]))
194: {
195: void *key;
196: void *text;
197:
198: XmlAttribute (xml, "lang", attr, sizeof (attr));
199: if (!defaultLangParsed
200: || strcmp (attr, langId) == 0)
201: {
202: if (XmlAttribute (xml, "key", attr, sizeof (attr)))
203: {
204: key = AddPoolData (attr, strlen (attr) + 1);
205: if (key == NULL) return FALSE;
206:
207: XmlNodeText (xml, attr, sizeof (attr));
208:
209: // Parse \ escape sequences
210: {
211: char *in = attr, *out = attr;
212: while (*in)
213: {
214: if (*in == '\\')
215: {
216: in++;
217: switch (*in++)
218: {
219: case '\\': *out++ = '\\'; break;
220: case 't': *out++ = '\t'; break;
221: case 'n': *out++ = 13; *out++ = 10; break;
222: default:
223: MessageBox (0, key, "TrueCrypt: Unknown '\\' escape sequence in string", MB_ICONERROR);
224: return FALSE;
225: }
226: }
227: else
228: *out++ = *in++;
229: }
230: *out = 0;
231: }
232:
233: // UTF8 => wide char
234: len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr));
235: if (len == 0 || len == ERROR_NO_UNICODE_TRANSLATION)
236: {
237: MessageBox (0, key, "TrueCrypt: Error while decoding UTF-8 string", MB_ICONERROR);
238: return FALSE;
239: }
240:
241: // Add to dictionary
242: text = AddPoolData ((void *) wattr, len * 2);
243: if (text == NULL) return FALSE;
244:
245: AddDictionaryEntry ((char *) key, 0, text);
246: }
247: }
248:
249: xml++;
250: }
251: }
252:
253: if (langFound)
254: break;
255:
256: if (!defaultLangParsed)
257: {
258: defaultLangParsed = TRUE;
259: if (langId[0] == 0 || strcmp (langId, "en") == 0)
260: break;
261: }
262: }
263:
264: LocalizationActive = langFound && strcmp (langId, "en") != 0;
265: LocalizationSerialNo++;
266:
267: // Create control ID dictionary
268:
269: // Default controls
270: AddDictionaryEntry (NULL, 1, GetString ("IDOK"));
271: AddDictionaryEntry (NULL, 2, GetString ("IDCANCEL"));
272: AddDictionaryEntry (NULL, 8, GetString ("IDCLOSE"));
273: AddDictionaryEntry (NULL, 9, GetString ("IDHELP"));
274:
275: for (i = 0; headers[i] != 0; i++)
276: {
277: if (HeaderResource[i] == NULL)
278: HeaderResource[i] = MapResource ("Header", headers[i], &size);
279:
280: header = HeaderResource[i];
281: if (header == NULL) return FALSE;
282:
283: do
284: {
285: if (sscanf (header, "#define %s %d", key, &intKey) == 2)
286: {
287: WCHAR *str = GetString (key);
288:
289: if (str != UnknownString)
290: AddDictionaryEntry (NULL, intKey, str);
291: }
292:
293: } while ((header = strchr (header, '\n') + 1) != (char *) 1);
294: }
295:
296: return TRUE;
297: }
298:
299:
300: // lParam = 1: auto mode
301: BOOL WINAPI LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
302: {
303: WORD lw = LOWORD (wParam);
304: WORD hw = HIWORD (wParam);
305:
306: switch (msg)
307: {
308: case WM_INITDIALOG:
309: {
310: char *xml;
311: char attr[2048], lastLangId[10];
312: WCHAR wattr[2048];
313: int len;
314: int langCount = 0;
315: BOOL defaultLangFound = FALSE;
316:
317: LocalizeDialog (hwndDlg, "IDD_LANGUAGE");
318:
319: SendMessage (GetDlgItem (hwndDlg, IDC_GET_LANG_PACKS), WM_SETFONT, (WPARAM) hUserUnderlineFont, 0);
320:
321: for (xml = MapFirstLanguageFile (); xml != NULL; xml = MapNextLanguageFile ())
322: {
323: while (xml = XmlFindElement (xml, "language"))
324: {
325: XmlAttribute (xml, "name", attr, sizeof (attr));
326: len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr));
327:
328: if (len != 0 && len != ERROR_NO_UNICODE_TRANSLATION
329: && (!defaultLangFound || wcscmp (wattr, L"English") != 0))
330: {
331: int i = SendDlgItemMessageW (hwndDlg, IDC_LANGLIST, LB_ADDSTRING, 0, (LPARAM)wattr);
332: if (i >= 0)
333: {
334: int id;
335:
336: // Encode language id in LPARAM
337: XmlAttribute (xml, "langid", attr, sizeof (attr));
338: switch (strlen (attr))
339: {
340: case 2: id = attr[0] | attr[1] << 8; break;
341: case 5: id = attr[0] | attr[1] << 8 | attr[3] << 16 | attr[4] << 24; break;
342: default: continue;
343: }
344:
345: if (!defaultLangFound)
346: defaultLangFound = TRUE;
347:
348: SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETITEMDATA, i, (LPARAM) id);
349:
350: if (strcmp (attr, PreferredLangId) == 0)
351: {
352: char credits [10000];
353: WCHAR wcredits [10000];
354: WCHAR wversion [20];
355: wchar_t szVers [200];
356: int nLen;
357:
358: SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETCURSEL, i, 0);
359:
360: // Language pack version
361: XmlAttribute (xml, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion));
362: if (memcmp (ActiveLangPackVersion, "0.0.0", 5) == 0)
363: {
364: swprintf (szVers, GetString("LANG_PACK_VERSION"), L"--");
365: }
366: else
367: {
368: nLen = MultiByteToWideChar (CP_UTF8, 0, ActiveLangPackVersion, -1, wversion, sizeof (ActiveLangPackVersion));
369: if (nLen != 0 && nLen != ERROR_NO_UNICODE_TRANSLATION)
370: swprintf (szVers, GetString("LANG_PACK_VERSION"), wversion);
371: }
372: SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_VERSION), szVers);
373:
374: // Translator credits
375: XmlAttribute (xml, "translators", credits, sizeof (credits));
376: nLen = MultiByteToWideChar (CP_UTF8, 0, credits, -1, wcredits, sizeof (wcredits));
377: if (nLen != 0 && nLen != ERROR_NO_UNICODE_TRANSLATION)
378: {
379: SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_CREDITS), wcredits);
380: }
381: }
382:
383: strcpy (lastLangId, attr);
384: langCount++;
385: }
386: }
387:
388: xml++;
389: }
390: }
391:
392: if (lParam == 1)
393: {
394: // Auto mode
395: if (langCount < 2)
396: EndDialog (hwndDlg, IDCANCEL);
397:
398: if (langCount == 2)
399: {
400: strcpy (PreferredLangId, lastLangId);
401: EndDialog (hwndDlg, IDOK);
402: }
403: }
404:
405: return 1;
406: }
407:
408:
409: case WM_COMMAND:
410:
411: if (lw == IDOK || hw == LBN_DBLCLK)
412: {
413: int i = SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCURSEL, 0, 0);
414:
415: if (i >= 0)
416: {
417: int id = SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETITEMDATA, i, 0);
418:
419: if (id != LB_ERR)
420: {
421: char l[6];
422:
423: // Decode language id from LPARAM
424: l[0] = id;
425: l[1] = id >> 8;
426: l[2] = 0;
427:
428: if ((id & 0xffff0000) != 0)
429: {
430: l[2] = '-';
431: l[3] = id >> 16;
432: l[4] = id >> 24;
433: l[5] = 0;
434: }
435:
436: if (SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCOUNT, 0, 0) > 1)
437: strcpy (PreferredLangId, l);
438: }
439: }
440:
441: EndDialog (hwndDlg, IDOK);
442: return 1;
443: }
444:
445: if (lw == IDCANCEL)
446: {
447: EndDialog (hwndDlg, lw);
448: return 1;
449: }
450:
451: if (lw == IDC_GET_LANG_PACKS)
452: {
453: char tmpstr [256];
454:
455: ArrowWaitCursor ();
456: if (strlen(ActiveLangPackVersion) > 0 && strlen(PreferredLangId) > 0)
457: sprintf (tmpstr, "http://www.truecrypt.org/applink.php?version=%s&dest=localizations&langpackversion=%s&lang=%s", VERSION_STRING, ActiveLangPackVersion, PreferredLangId);
458: else
459: sprintf (tmpstr, "http://www.truecrypt.org/applink.php?version=%s&dest=localizations", VERSION_STRING);
460:
461: ShellExecute (NULL, "open", (LPCTSTR) tmpstr, NULL, NULL, SW_SHOWNORMAL);
462: Sleep (200);
463: NormalCursor ();
464: return 1;
465: }
466: return 0;
467: }
468:
469: return 0;
470: }
471:
472:
473: char *GetPreferredLangId ()
474: {
475: return PreferredLangId;
476: }
477:
478:
479: void SetPreferredLangId (char *langId)
480: {
481: strncpy (PreferredLangId, langId, 5);
482: }
483:
484:
485: wchar_t *GetString (char *stringId)
486: {
487: WCHAR *str = (WCHAR *) GetDictionaryValue (stringId);
488: if (str != NULL) return str;
489:
490: wsprintfW (UnknownString, UNKNOWN_STRING_ID L"%hs" UNKNOWN_STRING_ID, stringId);
491: return UnknownString;
492: }
493:
494:
495: Font *GetFont (char *fontType)
496: {
497: return (Font *) GetDictionaryValue (fontType);
498:
499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.