Reactos
1//
2// GetLocaleInfoA.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the CRT-internal GetLocaleInfoA implementation.
7//
8#include <corecrt_internal.h>
9
10
11
12// Wraps a call to GetLocaleInfoEx and translates the result into a narrow string.
13_Success_(return > 0)
14static int __cdecl InternalGetLocaleInfoA(
15 _locale_t const locale,
16 PCWSTR const locale_name,
17 LCTYPE const locale_type,
18 _Out_writes_z_(result_size) char* const result,
19 int const result_size
20 )
21{
22 _LocaleUpdate locale_update(locale);
23
24 int const code_page = locale_update.GetLocaleT()->locinfo->_public._locale_lc_codepage;
25
26 int const buffer_size = __acrt_GetLocaleInfoEx(locale_name, locale_type, nullptr, 0);
27 if (buffer_size == 0)
28 return 0;
29
30 __crt_scoped_stack_ptr<wchar_t> const buffer(_malloca_crt_t(wchar_t, buffer_size));
31 if (buffer.get() == nullptr)
32 return 0;
33
34 if (__acrt_GetLocaleInfoEx(locale_name, locale_type, buffer.get(), buffer_size) == 0)
35 return 0;
36
37 // Convert from wide to narrow strings:
38 return __acrt_WideCharToMultiByte(
39 code_page,
40 0,
41 buffer.get(),
42 -1,
43 result_size != 0 ? result : nullptr,
44 result_size,
45 nullptr,
46 nullptr);
47}
48
49
50
51// Gets locale information appropriate for use in the setlocale initialization
52// functions. In particular, wide locale strings can be converted to narrow
53// strings or numeric values depending on the value of the lc_type parameter.
54//
55// The void_result must be reinterpretable as a pointer to one of the following
56// types, depending on the value of LC_TYPE:
57//
58// * LC_STR_TYPE: char*
59// * LC_WSTR_TYPE: wchar_t*
60// * LC_INT_TYPE: unsigned char
61//
62// For the first two cases, where a pointer to a pointer is passed, if the
63// function succeeds, the caller is responsible for freeing the pointed-to
64// buffer.
65//
66// Returns 0 on success; -1 on failure.
67//
68// Future optimization: When converting a large number of wide strings to
69// multibyte, we do not need to query the size of the result. We can convert
70// them one after another into a large character buffer.
71int __cdecl __acrt_GetLocaleInfoA(
72 _locale_t const locale,
73 int const lc_type,
74 wchar_t const* const locale_name,
75 LCTYPE const locale_type,
76 void* const void_result
77 )
78{
79 *static_cast<void**>(void_result) = nullptr;
80
81 if (lc_type == LC_STR_TYPE)
82 {
83 char** const char_result = static_cast<char**>(void_result);
84
85 int const local_buffer_size = 128;
86 char local_buffer[local_buffer_size];
87
88 int const local_length = InternalGetLocaleInfoA(
89 locale, locale_name, locale_type, local_buffer, local_buffer_size);
90
91 if (local_length != 0)
92 {
93 *char_result = _calloc_crt_t(char, local_length).detach();
94 if (*char_result == nullptr)
95 return -1;
96
97 _ERRCHECK(strncpy_s(*char_result, local_length, local_buffer, local_length - 1));
98 return 0;
99 }
100
101 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
102 return -1;
103
104 // If the buffer size was too small, compute the required size and use a
105 // dynamically allocated buffer:
106 int const required_length = InternalGetLocaleInfoA(
107 locale, locale_name, locale_type, nullptr, 0);
108
109 if (required_length == 0)
110 return -1;
111
112 __crt_unique_heap_ptr<char> dynamic_buffer(_calloc_crt_t(char, required_length));
113 if (dynamic_buffer.get() == nullptr)
114 return -1;
115
116 int const actual_length = InternalGetLocaleInfoA(
117 locale, locale_name, locale_type, dynamic_buffer.get(), required_length);
118
119 if (actual_length == 0)
120 return -1;
121
122 *char_result = dynamic_buffer.detach();
123 return 0;
124 }
125 else if (lc_type == LC_WSTR_TYPE)
126 {
127 wchar_t** const wchar_result = static_cast<wchar_t**>(void_result);
128
129 int const required_length = __acrt_GetLocaleInfoEx(locale_name, locale_type, nullptr, 0);
130 if (required_length == 0)
131 return -1;
132
133 __crt_unique_heap_ptr<wchar_t> dynamic_buffer(_calloc_crt_t(wchar_t, required_length));
134 if (dynamic_buffer.get() == nullptr)
135 return -1;
136
137 int const actual_length = __acrt_GetLocaleInfoEx(
138 locale_name, locale_type, dynamic_buffer.get(), required_length);
139
140 if (actual_length == 0)
141 return -1;
142
143 *wchar_result = dynamic_buffer.detach();
144 return 0;
145 }
146 else if (lc_type == LC_INT_TYPE)
147 {
148 unsigned char* const uchar_result = static_cast<unsigned char*>(void_result);
149
150 DWORD value = 0;
151 int const actual_length = __acrt_GetLocaleInfoEx(
152 locale_name,
153 locale_type | LOCALE_RETURN_NUMBER,
154 reinterpret_cast<wchar_t*>(&value),
155 sizeof(value) / sizeof(wchar_t));
156
157 if (actual_length == 0)
158 return -1;
159
160 *uchar_result = static_cast<unsigned char>(value);
161 return 0;
162 }
163
164 return -1;
165}