1 //
2 //  Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See
5 //  accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 #ifndef BOOST_LOCALE_IMPL_WIN32_API_HPP
9 #define BOOST_LOCALE_IMPL_WIN32_API_HPP
10 
11 #include <string>
12 #include <vector>
13 #include <sstream>
14 #include <iomanip>
15 #include <limits>
16 #include <ctime>
17 
18 #include "lcid.hpp"
19 
20 #ifndef NOMINMAX
21 #define NOMINMAX
22 #endif
23 #ifndef UNICODE
24 #define UNICODE
25 #endif
26 #include <windows.h>
27 
28 #include <boost/locale/conversion.hpp>
29 #include <boost/locale/collator.hpp>
30 
31 #define BOOST_LOCALE_WINDOWS_2000_API
32 
33 #if defined(_WIN32_NT) && _WIN32_NT >= 0x600 && !defined(BOOST_LOCALE_WINDOWS_2000_API)
34 #define BOOST_LOCALE_WINDOWS_VISTA_API
35 #else
36 #define BOOST_LOCALE_WINDOWS_2000_API
37 #endif
38 
39 namespace boost {
40 namespace locale {
41 namespace impl_win {
42 
43     struct numeric_info {
44         std::wstring thousands_sep;
45         std::wstring decimal_point;
46         std::string grouping;
47     };
48 
collation_level_to_flag(collator_base::level_type level)49     inline DWORD collation_level_to_flag(collator_base::level_type level)
50     {
51         DWORD flags;
52         switch(level) {
53         case collator_base::primary:
54             flags = NORM_IGNORESYMBOLS | NORM_IGNORECASE | NORM_IGNORENONSPACE;
55             break;
56         case collator_base::secondary:
57             flags = NORM_IGNORESYMBOLS | NORM_IGNORECASE;
58             break;
59         case collator_base::tertiary:
60             flags = NORM_IGNORESYMBOLS;
61             break;
62         default:
63             flags = 0;
64         }
65         return flags;
66     }
67 
68 
69 
70     #ifdef BOOST_LOCALE_WINDOWS_2000_API
71 
72     class winlocale{
73     public:
winlocale()74         winlocale() :
75             lcid(0)
76         {
77         }
78 
winlocale(std::string const & name)79         winlocale(std::string const &name)
80         {
81             lcid = locale_to_lcid(name);
82         }
83 
84         unsigned lcid;
85 
is_c() const86         bool is_c() const
87         {
88             return lcid == 0;
89         }
90     };
91 
92 
93     ////////////////////////////////////////////////////////////////////////
94     ///
95     /// Number Format
96     ///
97     ////////////////////////////////////////////////////////////////////////
98 
wcsnumformat_l(winlocale const & l)99     inline numeric_info wcsnumformat_l(winlocale const &l)
100     {
101         numeric_info res;
102         res.decimal_point = L'.';
103         unsigned lcid = l.lcid;
104 
105         if(lcid == 0)
106             return res;
107 
108         // limits according to MSDN
109         static const int th_size = 4;
110         static const int de_size = 4;
111         static const int gr_size = 10;
112 
113         wchar_t th[th_size]={0};
114         wchar_t de[de_size]={0};
115         wchar_t gr[gr_size]={0};
116 
117         if( GetLocaleInfoW(lcid,LOCALE_STHOUSAND,th,th_size)==0
118             || GetLocaleInfoW(lcid,LOCALE_SDECIMAL ,de,de_size)==0
119             || GetLocaleInfoW(lcid,LOCALE_SGROUPING,gr,gr_size)==0)
120         {
121             return res;
122         }
123         res.decimal_point = de;
124         res.thousands_sep = th;
125         bool inf_group = false;
126         for(unsigned i=0;gr[i];i++) {
127             if(gr[i]==L';')
128                 continue;
129             if(L'1'<= gr[i] && gr[i]<=L'9') {
130                 res.grouping += char(gr[i]-L'0');
131             }
132             else if(gr[i]==L'0')
133                 inf_group = true;
134         }
135         if(!inf_group) {
136             if(std::numeric_limits<char>::is_signed) {
137                 res.grouping+=std::numeric_limits<char>::min();
138             }
139             else {
140                 res.grouping+=std::numeric_limits<char>::max();
141             }
142         }
143         return res;
144     }
145 
win_map_string_l(unsigned flags,wchar_t const * begin,wchar_t const * end,winlocale const & l)146     inline std::wstring win_map_string_l(unsigned flags,wchar_t const *begin,wchar_t const *end,winlocale const &l)
147     {
148         std::wstring res;
149         int len = LCMapStringW(l.lcid,flags,begin,end-begin,0,0);
150         if(len == 0)
151             return res;
152         std::vector<wchar_t> buf(len+1);
153         int l2 = LCMapStringW(l.lcid,flags,begin,end-begin,&buf.front(),buf.size());
154         res.assign(&buf.front(),l2);
155         return res;
156     }
157 
158     ////////////////////////////////////////////////////////////////////////
159     ///
160     /// Collation
161     ///
162     ////////////////////////////////////////////////////////////////////////
163 
164 
wcscoll_l(collator_base::level_type level,wchar_t const * lb,wchar_t const * le,wchar_t const * rb,wchar_t const * re,winlocale const & l)165     inline int wcscoll_l(   collator_base::level_type level,
166                             wchar_t const *lb,wchar_t const *le,
167                             wchar_t const *rb,wchar_t const *re,
168                             winlocale const &l)
169     {
170         return CompareStringW(l.lcid,collation_level_to_flag(level),lb,le-lb,rb,re-rb) - 2;
171     }
172 
173 
174     ////////////////////////////////////////////////////////////////////////
175     ///
176     /// Money Format
177     ///
178     ////////////////////////////////////////////////////////////////////////
179 
wcsfmon_l(double value,winlocale const & l)180     inline std::wstring wcsfmon_l(double value,winlocale const &l)
181     {
182         std::wostringstream ss;
183         ss.imbue(std::locale::classic());
184 
185         ss << std::setprecision(std::numeric_limits<double>::digits10+1) << value;
186         std::wstring sval = ss.str();
187         int len = GetCurrencyFormatW(l.lcid,0,sval.c_str(),0,0,0);
188         std::vector<wchar_t> buf(len+1);
189         GetCurrencyFormatW(l.lcid,0,sval.c_str(),0,&buf.front(),len);
190         return &buf.front();
191     }
192 
193     ////////////////////////////////////////////////////////////////////////
194     ///
195     /// Time Format
196     ///
197     ////////////////////////////////////////////////////////////////////////
198 
199 
wcs_format_date_l(wchar_t const * format,SYSTEMTIME const * tm,winlocale const & l)200     inline std::wstring wcs_format_date_l(wchar_t const *format,SYSTEMTIME const *tm,winlocale const &l)
201     {
202         int len = GetDateFormatW(l.lcid,0,tm,format,0,0);
203         std::vector<wchar_t> buf(len+1);
204         GetDateFormatW(l.lcid,0,tm,format,&buf.front(),len);
205         return &buf.front();
206     }
207 
wcs_format_time_l(wchar_t const * format,SYSTEMTIME const * tm,winlocale const & l)208     inline std::wstring wcs_format_time_l(wchar_t const *format,SYSTEMTIME const *tm,winlocale const &l)
209     {
210         int len = GetTimeFormatW(l.lcid,0,tm,format,0,0);
211         std::vector<wchar_t> buf(len+1);
212         GetTimeFormatW(l.lcid,0,tm,format,&buf.front(),len);
213         return &buf.front();
214     }
215 
wcsfold(wchar_t const * begin,wchar_t const * end)216     inline std::wstring wcsfold(wchar_t const *begin,wchar_t const *end)
217     {
218         winlocale l;
219         l.lcid = 0x0409; // en-US
220         return win_map_string_l(LCMAP_LOWERCASE,begin,end,l);
221     }
222 
wcsnormalize(norm_type norm,wchar_t const * begin,wchar_t const * end)223     inline std::wstring wcsnormalize(norm_type norm,wchar_t const *begin,wchar_t const *end)
224     {
225         // We use FoldString, under Vista it actually does normalization;
226         // under XP and below it does something similar, half job, better then nothing
227         unsigned flags = 0;
228         switch(norm) {
229         case norm_nfd:
230             flags = MAP_COMPOSITE;
231             break;
232         case norm_nfc:
233             flags = MAP_PRECOMPOSED;
234             break;
235         case norm_nfkd:
236             flags = MAP_FOLDCZONE;
237             break;
238         case norm_nfkc:
239             flags = MAP_FOLDCZONE | MAP_COMPOSITE;
240             break;
241         default:
242             flags = MAP_PRECOMPOSED;
243         }
244 
245         int len = FoldStringW(flags,begin,end-begin,0,0);
246         if(len == 0)
247             return std::wstring();
248         std::vector<wchar_t> v(len+1);
249         len = FoldStringW(flags,begin,end-begin,&v.front(),len+1);
250         return std::wstring(&v.front(),len);
251     }
252 
253 
254     #endif
255 
wcsxfrm_l(collator_base::level_type level,wchar_t const * begin,wchar_t const * end,winlocale const & l)256     inline std::wstring wcsxfrm_l(collator_base::level_type level,wchar_t const *begin,wchar_t const *end,winlocale const &l)
257     {
258         int flag = LCMAP_SORTKEY | collation_level_to_flag(level);
259 
260         return win_map_string_l(flag,begin,end,l);
261     }
262 
towupper_l(wchar_t const * begin,wchar_t const * end,winlocale const & l)263     inline std::wstring towupper_l(wchar_t const *begin,wchar_t const *end,winlocale const &l)
264     {
265         return win_map_string_l(LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING,begin,end,l);
266     }
267 
towlower_l(wchar_t const * begin,wchar_t const * end,winlocale const & l)268     inline std::wstring towlower_l(wchar_t const *begin,wchar_t const *end,winlocale const &l)
269     {
270         return win_map_string_l(LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING,begin,end,l);
271     }
272 
wcsftime_l(char c,std::tm const * tm,winlocale const & l)273     inline std::wstring wcsftime_l(char c,std::tm const *tm,winlocale const &l)
274     {
275         SYSTEMTIME wtm=SYSTEMTIME();
276         wtm.wYear = tm->tm_year + 1900;
277         wtm.wMonth = tm->tm_mon+1;
278         wtm.wDayOfWeek = tm->tm_wday;
279         wtm.wDay = tm->tm_mday;
280         wtm.wHour = tm->tm_hour;
281         wtm.wMinute = tm->tm_min;
282         wtm.wSecond = tm->tm_sec;
283         switch(c) {
284         case 'a': // Abbr Weekday
285             return wcs_format_date_l(L"ddd",&wtm,l);
286         case 'A': // Full Weekday
287             return wcs_format_date_l(L"dddd",&wtm,l);
288         case 'b': // Abbr Month
289             return wcs_format_date_l(L"MMM",&wtm,l);
290         case 'B': // Full Month
291             return wcs_format_date_l(L"MMMM",&wtm,l);
292         case 'c': // DateTile Full
293             return wcs_format_date_l(0,&wtm,l) + L" " + wcs_format_time_l(0,&wtm,l);
294         // not supported by WIN ;(
295         //  case 'C': // Century -> 1980 -> 19
296         //  retur
297         case 'd': // Day of Month [01,31]
298             return wcs_format_date_l(L"dd",&wtm,l);
299         case 'D': // %m/%d/%y
300             return wcs_format_date_l(L"MM/dd/yy",&wtm,l);
301         case 'e': // Day of Month [1,31]
302             return wcs_format_date_l(L"d",&wtm,l);
303         case 'h': // == b
304             return wcs_format_date_l(L"MMM",&wtm,l);
305         case 'H': // 24 clock hour 00,23
306             return wcs_format_time_l(L"HH",&wtm,l);
307         case 'I': // 12 clock hour 01,12
308             return wcs_format_time_l(L"hh",&wtm,l);
309         /*
310         case 'j': // day of year 001,366
311             return "D";*/
312         case 'm': // month as [01,12]
313             return wcs_format_date_l(L"MM",&wtm,l);
314         case 'M': // minute [00,59]
315             return wcs_format_time_l(L"mm",&wtm,l);
316         case 'n': // \n
317             return L"\n";
318         case 'p': // am-pm
319             return wcs_format_time_l(L"tt",&wtm,l);
320         case 'r': // time with AM/PM %I:%M:%S %p
321             return wcs_format_time_l(L"hh:mm:ss tt",&wtm,l);
322         case 'R': // %H:%M
323             return wcs_format_time_l(L"HH:mm",&wtm,l);
324         case 'S': // second [00,61]
325             return wcs_format_time_l(L"ss",&wtm,l);
326         case 't': // \t
327             return L"\t";
328         case 'T': // %H:%M:%S
329             return wcs_format_time_l(L"HH:mm:ss",&wtm,l);
330 /*          case 'u': // weekday 1,7 1=Monday
331         case 'U': // week number of year [00,53] Sunday first
332         case 'V': // week number of year [01,53] Moday first
333         case 'w': // weekday 0,7 0=Sunday
334         case 'W': // week number of year [00,53] Moday first, */
335         case 'x': // Date
336             return wcs_format_date_l(0,&wtm,l);
337         case 'X': // Time
338             return wcs_format_time_l(0,&wtm,l);
339         case 'y': // Year [00-99]
340             return wcs_format_date_l(L"yy",&wtm,l);
341         case 'Y': // Year 1998
342             return wcs_format_date_l(L"yyyy",&wtm,l);
343         case '%': // %
344             return L"%";
345         default:
346             return L"";
347         }
348     }
349 
350 
351 
352 } // win
353 } // locale
354 } // boost
355 #endif
356 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
357 
358