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