• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2010 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/win/i18n.h"
6 
7 #include <windows.h>
8 
9 #include <ostream>
10 #include <string_view>
11 
12 #include "base/check_op.h"
13 #include "base/strings/string_piece.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 
17 namespace {
18 
19 using GetPreferredUILanguages_Fn = decltype(::GetSystemPreferredUILanguages)*;
20 
21 constexpr std::wstring_view kNullTerminator{L"\0", 1};
22 
GetPreferredUILanguageList(GetPreferredUILanguages_Fn function,ULONG flags,std::vector<std::wstring> * languages)23 bool GetPreferredUILanguageList(GetPreferredUILanguages_Fn function,
24                                 ULONG flags,
25                                 std::vector<std::wstring>* languages) {
26   DCHECK_EQ((flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME)), 0U);
27   const ULONG call_flags = flags | MUI_LANGUAGE_NAME;
28   ULONG language_count = 0;
29   ULONG buffer_length = 0;
30   if (!function(call_flags, &language_count, nullptr, &buffer_length) ||
31       !buffer_length) {
32     DPCHECK(!buffer_length) << "Failed getting size of preferred UI languages.";
33     return false;
34   }
35 
36   std::wstring buffer(buffer_length, '\0');
37   if (!function(call_flags, &language_count, std::data(buffer),
38                 &buffer_length) ||
39       !language_count) {
40     DPCHECK(!language_count) << "Failed getting preferred UI languages.";
41     return false;
42   }
43 
44   // The buffer has been populated with a series of strings separated by
45   // terminators, which ends with a single empty string (two terminators in a
46   // row). Chop off the last of those two terminators so that |buffer| is a
47   // basic_string that contains the terminator ending the last string but not
48   // the terminator denoting an empty string.
49   buffer.resize(buffer_length - 1);
50 
51   // Split string on NUL characters.
52   ULONG languages_added = 0;
53   for (auto token :
54        base::SplitStringPiece(buffer, kNullTerminator, base::KEEP_WHITESPACE,
55                               base::SPLIT_WANT_NONEMPTY)) {
56     languages->emplace_back(token);
57     ++languages_added;
58   }
59   DCHECK_EQ(languages_added, language_count);
60   return true;
61 }
62 
63 }  // namespace
64 
65 namespace base {
66 namespace win {
67 namespace i18n {
68 
GetUserPreferredUILanguageList(std::vector<std::wstring> * languages)69 bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
70   DCHECK(languages);
71   return GetPreferredUILanguageList(::GetUserPreferredUILanguages, 0,
72                                     languages);
73 }
74 
GetThreadPreferredUILanguageList(std::vector<std::wstring> * languages)75 bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) {
76   DCHECK(languages);
77   return GetPreferredUILanguageList(
78       ::GetThreadPreferredUILanguages,
79       MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK, languages);
80 }
81 
82 }  // namespace i18n
83 }  // namespace win
84 }  // namespace base
85