From 80d7bf771ab28122213a40776e43ed815b2c681a Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Thu, 15 Oct 2026 02:51:44 +0200 Subject: [PATCH] Unix: fall back to English when a language file is unusable An empty language file made VeraCrypt access the first element of an empty vector, and any language file without a language element crashed it at startup, when LanguageStrings::Init took the first element of an empty node list. A file with an unterminated tag made initialization fail instead, so VeraCrypt could not start until the preferences file was edited. Read the file only if it is not empty, and ignore a language file that cannot be parsed or has no language element, keeping the built-in English strings. Also fall back when the optional language file cannot be opened or read completely. Catch I/O failures at the resource loader, leaving preference-loading errors outside the handler. --- src/Main/LanguageStrings.cpp | 20 ++++++++++++++++++-- src/Main/Resources.cpp | 26 ++++++++++++++++++-------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Main/LanguageStrings.cpp b/src/Main/LanguageStrings.cpp index 9dbdf211..d5564a54 100644 --- a/src/Main/LanguageStrings.cpp +++ b/src/Main/LanguageStrings.cpp @@ -57,14 +57,30 @@ namespace VeraCrypt } string translatedXml = Resources::GetLanguageXml(PreferredLang); - foreach (XmlNode node, XmlParser (translatedXml).GetNodes (L"entry")) + XmlNodeList translatedEntries, languageNodes; + try + { + translatedEntries = XmlParser (translatedXml).GetNodes (L"entry"); + languageNodes = XmlParser (translatedXml).GetNodes (L"language"); + } + catch (ParameterIncorrect&) { } + + // Keep the built-in strings if the language file is empty, malformed or has no language element + if (languageNodes.empty()) + { + translatedEntries.clear(); + languageNodes = XmlParser (def).GetNodes (L"language"); + PreferredLang = "en"; + } + + foreach (XmlNode node, translatedEntries) { wxString text = node.InnerText; text.Replace (L"\\n", L"\n"); Map[StringConverter::ToSingle (wstring (node.Attributes[L"key"]))] = text; } - XmlNode node = XmlParser (translatedXml).GetNodes (L"language").front(); + XmlNode node = languageNodes.front(); Map["LANGUAGE_TRANSLATORS"] = wxString (node.Attributes[L"translators"]); Map["CURRENT_LANGUAGE_PACK"] = wxString (node.Attributes[L"name"]); } diff --git a/src/Main/Resources.cpp b/src/Main/Resources.cpp index bc7ab7e3..b5a79017 100644 --- a/src/Main/Resources.cpp +++ b/src/Main/Resources.cpp @@ -149,14 +149,24 @@ namespace VeraCrypt } FilesystemPath xml(filename); if ( xml.IsFile() ){ - File file; - file.Open (xml, File::OpenRead, File::ShareRead); - vector keyfileData (file.Length()); - BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); - file.ReadCompleteBuffer (keyfileDataBuf); - file.Close(); - string langxml(keyfileData.begin(), keyfileData.end()); - return langxml; + try + { + File file; + file.Open (xml, File::OpenRead, File::ShareRead); + vector keyfileData (file.Length()); + if (!keyfileData.empty()) + { + BufferPtr keyfileDataBuf (&keyfileData.front(), keyfileData.size()); + file.ReadCompleteBuffer (keyfileDataBuf); + } + file.Close(); + string langxml(keyfileData.begin(), keyfileData.end()); + return langxml; + } + // An optional translation must not prevent startup if it cannot be + // opened or read completely (for example, if it shrinks while reading). + catch (SystemException&) { } + catch (InsufficientData&) { } } static uint8 LanguageXml[] = {