1 /*
2  *
3  * Copyright (c) 2004
4  * John Maddock
5  *
6  * Use, modification and distribution are subject to the
7  * Boost Software License, Version 1.0. (See accompanying file
8  * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9  *
10  */
11 
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         w32_regex_traits.hpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Declares regular expression traits class w32_regex_traits.
17   */
18 
19 #ifndef BOOST_W32_REGEX_TRAITS_HPP_INCLUDED
20 #define BOOST_W32_REGEX_TRAITS_HPP_INCLUDED
21 
22 #ifndef BOOST_REGEX_NO_WIN32_LOCALE
23 
24 #include <boost/regex/pattern_except.hpp>
25 #include <boost/regex/v5/regex_traits_defaults.hpp>
26 #ifdef BOOST_HAS_THREADS
27 #include <mutex>
28 #endif
29 #include <boost/regex/v5/primary_transform.hpp>
30 #include <boost/regex/v5/object_cache.hpp>
31 
32 #if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(UNDER_CE)
33 #pragma comment(lib, "user32.lib")
34 #endif
35 
36 #ifdef BOOST_REGEX_MSVC
37 #pragma warning(push)
38 #pragma warning(disable:4786)
39 #if BOOST_REGEX_MSVC < 1910
40 #pragma warning(disable:4800)
41 #endif
42 #endif
43 
44 #ifndef BASETYPES
45 //
46 // windows.h not included, so lets forward declare what we need:
47 //
48 #ifndef NO_STRICT
49 #ifndef STRICT
50 #define STRICT 1
51 #endif
52 #endif
53 
54 #if defined(STRICT)
55 #define BOOST_RE_DETAIL_DECLARE_HANDLE(x) struct x##__; typedef struct x##__ *x
56 #else
57 #define BOOST_RE_DETAIL_DECLARE_HANDLE(x) typedef void* x
58 #endif
59 //
60 // This must be in the global namespace:
61 //
62 extern "C" {
63 
64    BOOST_RE_DETAIL_DECLARE_HANDLE(HINSTANCE);
65    typedef HINSTANCE HMODULE;
66 }
67 #endif
68 
69 namespace boost{
70 
71 //
72 // forward declaration is needed by some compilers:
73 //
74 template <class charT>
75 class w32_regex_traits;
76 
77 namespace BOOST_REGEX_DETAIL_NS{
78 
79 //
80 // start by typedeffing the types we'll need:
81 //
82 typedef unsigned long lcid_type;        // placeholder for LCID.
83 typedef std::shared_ptr<void> cat_type; // placeholder for dll HANDLE.
84 
85 //
86 // then add wrappers around the actual Win32 API's (ie implementation hiding):
87 //
88 lcid_type  w32_get_default_locale();
89 bool  w32_is_lower(char, lcid_type);
90 #ifndef BOOST_NO_WREGEX
91 bool  w32_is_lower(wchar_t, lcid_type);
92 #endif
93 bool  w32_is_upper(char, lcid_type);
94 #ifndef BOOST_NO_WREGEX
95 bool  w32_is_upper(wchar_t, lcid_type);
96 #endif
97 cat_type  w32_cat_open(const std::string& name);
98 std::string  w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::string& def);
99 #ifndef BOOST_NO_WREGEX
100 std::wstring  w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::wstring& def);
101 #endif
102 std::string  w32_transform(lcid_type state_id, const char* p1, const char* p2);
103 #ifndef BOOST_NO_WREGEX
104 std::wstring  w32_transform(lcid_type state_id, const wchar_t* p1, const wchar_t* p2);
105 #endif
106 char  w32_tolower(char c, lcid_type);
107 #ifndef BOOST_NO_WREGEX
108 wchar_t  w32_tolower(wchar_t c, lcid_type);
109 #endif
110 char  w32_toupper(char c, lcid_type);
111 #ifndef BOOST_NO_WREGEX
112 wchar_t  w32_toupper(wchar_t c, lcid_type);
113 #endif
114 bool  w32_is(lcid_type, std::uint32_t mask, char c);
115 #ifndef BOOST_NO_WREGEX
116 bool  w32_is(lcid_type, std::uint32_t mask, wchar_t c);
117 #endif
118 
119 #ifndef BASETYPES
120 //
121 // Forward declarations of the small number of windows types and API's we use:
122 //
123 
124 #if !defined(__LP64__)
125 using dword = unsigned long;
126 #else
127 using DWORD = unsigned int;
128 #endif
129 using word = unsigned short;
130 using lctype = dword;
131 
132 static constexpr dword ct_ctype1 = 0x00000001;
133 static constexpr dword c1_upper = 0x0001;      // upper case
134 static constexpr dword c1_lower = 0x0002;      // lower case
135 static constexpr dword c1_digit = 0x0004;      // decimal digits
136 static constexpr dword c1_space = 0x0008;      // spacing characters
137 static constexpr dword c1_punct = 0x0010;      // punctuation characters
138 static constexpr dword c1_cntrl = 0x0020;      // control characters
139 static constexpr dword c1_blank = 0x0040;      // blank characters
140 static constexpr dword c1_xdigit = 0x0080;      // other digits
141 static constexpr dword c1_alpha = 0x0100;      // any linguistic character
142 static constexpr dword c1_defined = 0x0200;      // defined character
143 static constexpr unsigned int cp_acp = 0;
144 static constexpr dword lcmap_lowercase = 0x00000100;
145 static constexpr dword lcmap_uppercase = 0x00000200;
146 static constexpr dword lcmap_sortkey = 0x00000400;  // WC sort key (normalize)
147 static constexpr lctype locale_idefaultansicodepage = 0x00001004;
148 
149 # ifdef UNDER_CE
150 #  ifndef WINAPI
151 #   ifndef _WIN32_WCE_EMULATION
152 #    define BOOST_RE_STDCALL __cdecl     // Note this doesn't match the desktop definition
153 #   else
154 #    define BOOST_RE_STDCALL __stdcall
155 #   endif
156 #  endif
157 # else
158 #  if defined(_M_IX86) || defined(__i386__)
159 #   define BOOST_RE_STDCALL __stdcall
160 #  else
161     // On architectures other than 32-bit x86 __stdcall is ignored. Clang also issues a warning.
162 #   define BOOST_RE_STDCALL
163 #  endif
164 # endif
165 
166 #if defined (WIN32_PLATFORM_PSPC)
167 #define BOOST_RE_IMPORT __declspec( dllimport )
168 #elif defined (_WIN32_WCE)
169 #define BOOST_RE_IMPORT
170 #else
171 #define BOOST_RE_IMPORT __declspec( dllimport )
172 #endif
173 
174 extern "C" {
175 
176    BOOST_RE_IMPORT int BOOST_RE_STDCALL FreeLibrary(HMODULE hLibModule);
177    BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringA(lcid_type Locale, dword dwMapFlags, const char* lpSrcStr, int cchSrc, char* lpDestStr, int cchDest);
178    BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringW(lcid_type Locale, dword dwMapFlags, const wchar_t* lpSrcStr, int cchSrc, wchar_t* lpDestStr, int cchDest);
179    BOOST_RE_IMPORT int BOOST_RE_STDCALL MultiByteToWideChar(unsigned int CodePage, dword dwFlags, const char* lpMultiByteStr, int cbMultiByte, wchar_t* lpWideCharStr, int cchWideChar);
180    BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringW(lcid_type Locale, dword dwMapFlags, const wchar_t* lpSrcStr, int cchSrc, wchar_t* lpDestStr, int cchDest);
181    BOOST_RE_IMPORT int BOOST_RE_STDCALL WideCharToMultiByte(unsigned int CodePage, dword dwFlags, const wchar_t* lpWideCharStr, int cchWideChar, char* lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, int* lpUsedDefaultChar);
182    BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExA(lcid_type Locale, dword dwInfoType, const char* lpSrcStr, int cchSrc, word* lpCharType);
183    BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExW(lcid_type Locale, dword dwInfoType, const wchar_t* lpSrcStr, int cchSrc, word* lpCharType);
184    BOOST_RE_IMPORT lcid_type BOOST_RE_STDCALL GetUserDefaultLCID();
185    BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExA(lcid_type Locale, dword dwInfoType, const char* lpSrcStr, int cchSrc, word* lpCharType);
186    BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExW(lcid_type Locale, dword dwInfoType, const wchar_t* lpSrcStr, int cchSrc, word* lpCharType);
187    BOOST_RE_IMPORT HMODULE BOOST_RE_STDCALL LoadLibraryA(const char* lpLibFileName);
188    BOOST_RE_IMPORT HMODULE BOOST_RE_STDCALL LoadLibraryW(const wchar_t* lpLibFileName);
189    BOOST_RE_IMPORT int BOOST_RE_STDCALL LoadStringW(HINSTANCE hInstance, unsigned int uID, wchar_t* lpBuffer, int cchBufferMax);
190    BOOST_RE_IMPORT int BOOST_RE_STDCALL LoadStringA(HINSTANCE hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax);
191    BOOST_RE_IMPORT int BOOST_RE_STDCALL GetLocaleInfoW(lcid_type Locale, lctype LCType, wchar_t* lpLCData, int cchData);
192 }
193 
194 #else
195 //
196 // We have windows.h already included:
197 //
198 using dword = DWORD;
199 using word = WORD;
200 using lctype = LCTYPE;
201 
202 static constexpr dword ct_ctype1 = 0x00000001;
203 static constexpr dword c1_upper = 0x0001;      // upper case
204 static constexpr dword c1_lower = 0x0002;      // lower case
205 static constexpr dword c1_digit = 0x0004;      // decimal digits
206 static constexpr dword c1_space = 0x0008;      // spacing characters
207 static constexpr dword c1_punct = 0x0010;      // punctuation characters
208 static constexpr dword c1_cntrl = 0x0020;      // control characters
209 static constexpr dword c1_blank = 0x0040;      // blank characters
210 static constexpr dword c1_xdigit = 0x0080;      // other digits
211 static constexpr dword c1_alpha = 0x0100;      // any linguistic character
212 static constexpr dword c1_defined = 0x0200;      // defined character
213 static constexpr unsigned int cp_acp = 0;
214 static constexpr dword lcmap_lowercase = 0x00000100;
215 static constexpr dword lcmap_uppercase = 0x00000200;
216 static constexpr dword lcmap_sortkey = 0x00000400;  // WC sort key (normalize)
217 static constexpr lctype locale_idefaultansicodepage = 0x00001004;
218 
219 using ::FreeLibrary;
220 using ::LCMapStringA;
221 using ::LCMapStringW;
222 using ::MultiByteToWideChar;
223 using ::LCMapStringW;
224 using ::WideCharToMultiByte;
225 using ::GetStringTypeExA;
226 using ::GetStringTypeExW;
227 using ::GetUserDefaultLCID;
228 using ::GetStringTypeExA;
229 using ::GetStringTypeExW;
230 using ::LoadLibraryA;
231 using ::LoadLibraryW;
232 using ::LoadStringW;
233 using ::LoadStringA;
234 using ::GetLocaleInfoW;
235 
236 #endif
237 //
238 // class w32_regex_traits_base:
239 // acts as a container for locale and the facets we are using.
240 //
241 template <class charT>
242 struct w32_regex_traits_base
243 {
w32_regex_traits_baseboost::BOOST_REGEX_DETAIL_NS::w32_regex_traits_base244    w32_regex_traits_base(lcid_type l)
245    { imbue(l); }
246    lcid_type imbue(lcid_type l);
247 
248    lcid_type m_locale;
249 };
250 
251 template <class charT>
imbue(lcid_type l)252 inline lcid_type w32_regex_traits_base<charT>::imbue(lcid_type l)
253 {
254    lcid_type result(m_locale);
255    m_locale = l;
256    return result;
257 }
258 
259 //
260 // class w32_regex_traits_char_layer:
261 // implements methods that require specialisation for narrow characters:
262 //
263 template <class charT>
264 class w32_regex_traits_char_layer : public w32_regex_traits_base<charT>
265 {
266    typedef std::basic_string<charT> string_type;
267    typedef std::map<charT, regex_constants::syntax_type> map_type;
268    typedef typename map_type::const_iterator map_iterator_type;
269 public:
270    w32_regex_traits_char_layer(const lcid_type l);
271 
syntax_type(charT c) const272    regex_constants::syntax_type syntax_type(charT c)const
273    {
274       map_iterator_type i = m_char_map.find(c);
275       return ((i == m_char_map.end()) ? 0 : i->second);
276    }
escape_syntax_type(charT c) const277    regex_constants::escape_syntax_type escape_syntax_type(charT c) const
278    {
279       map_iterator_type i = m_char_map.find(c);
280       if(i == m_char_map.end())
281       {
282          if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_lower(c, this->m_locale)) return regex_constants::escape_type_class;
283          if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_upper(c, this->m_locale)) return regex_constants::escape_type_not_class;
284          return 0;
285       }
286       return i->second;
287    }
tolower(charT c) const288    charT tolower(charT c)const
289    {
290       return ::boost::BOOST_REGEX_DETAIL_NS::w32_tolower(c, this->m_locale);
291    }
isctype(std::uint32_t mask,charT c) const292    bool isctype(std::uint32_t mask, charT c)const
293    {
294       return ::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, mask, c);
295    }
296 
297 private:
298    string_type get_default_message(regex_constants::syntax_type);
299    // TODO: use a hash table when available!
300    map_type m_char_map;
301 };
302 
303 template <class charT>
w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)304 w32_regex_traits_char_layer<charT>::w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
305    : w32_regex_traits_base<charT>(l)
306 {
307    // we need to start by initialising our syntax map so we know which
308    // character is used for which purpose:
309    cat_type cat;
310    std::string cat_name(w32_regex_traits<charT>::get_catalog_name());
311    if(cat_name.size())
312    {
313       cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name);
314       if(!cat)
315       {
316          std::string m("Unable to open message catalog: ");
317          std::runtime_error err(m + cat_name);
318          boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
319       }
320    }
321    //
322    // if we have a valid catalog then load our messages:
323    //
324    if(cat)
325    {
326       for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
327       {
328          string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_message(i));
329          for(typename string_type::size_type j = 0; j < mss.size(); ++j)
330          {
331             this->m_char_map[mss[j]] = i;
332          }
333       }
334    }
335    else
336    {
337       for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
338       {
339          const char* ptr = get_default_syntax(i);
340          while(ptr && *ptr)
341          {
342             this->m_char_map[static_cast<charT>(*ptr)] = i;
343             ++ptr;
344          }
345       }
346    }
347 }
348 
349 template <class charT>
350 typename w32_regex_traits_char_layer<charT>::string_type
get_default_message(regex_constants::syntax_type i)351    w32_regex_traits_char_layer<charT>::get_default_message(regex_constants::syntax_type i)
352 {
353    const char* ptr = get_default_syntax(i);
354    string_type result;
355    while(ptr && *ptr)
356    {
357       result.append(1, static_cast<charT>(*ptr));
358       ++ptr;
359    }
360    return result;
361 }
362 
363 //
364 // specialised version for narrow characters:
365 //
366 template <>
367 class w32_regex_traits_char_layer<char> : public w32_regex_traits_base<char>
368 {
369    typedef std::string string_type;
370 public:
w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)371    w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
372    : w32_regex_traits_base<char>(l)
373    {
374       init<char>();
375    }
376 
syntax_type(char c) const377    regex_constants::syntax_type syntax_type(char c)const
378    {
379       return m_char_map[static_cast<unsigned char>(c)];
380    }
escape_syntax_type(char c) const381    regex_constants::escape_syntax_type escape_syntax_type(char c) const
382    {
383       return m_char_map[static_cast<unsigned char>(c)];
384    }
tolower(char c) const385    char tolower(char c)const
386    {
387       return m_lower_map[static_cast<unsigned char>(c)];
388    }
isctype(std::uint32_t mask,char c) const389    bool isctype(std::uint32_t mask, char c)const
390    {
391       return m_type_map[static_cast<unsigned char>(c)] & mask;
392    }
393 
394 private:
395    regex_constants::syntax_type m_char_map[1u << CHAR_BIT];
396    char m_lower_map[1u << CHAR_BIT];
397    std::uint16_t m_type_map[1u << CHAR_BIT];
398    template <class U>
399    void init();
400 };
401 
402 //
403 // class w32_regex_traits_implementation:
404 // provides pimpl implementation for w32_regex_traits.
405 //
406 template <class charT>
407 class w32_regex_traits_implementation : public w32_regex_traits_char_layer<charT>
408 {
409 public:
410    typedef typename w32_regex_traits<charT>::char_class_type char_class_type;
411    static const char_class_type mask_word = 0x0400; // must be C1_DEFINED << 1
412    static const char_class_type mask_unicode = 0x0800; // must be C1_DEFINED << 2
413    static const char_class_type mask_horizontal = 0x1000; // must be C1_DEFINED << 3
414    static const char_class_type mask_vertical = 0x2000; // must be C1_DEFINED << 4
415    static const char_class_type mask_base = 0x3ff;  // all the masks used by the CT_CTYPE1 group
416 
417    typedef std::basic_string<charT> string_type;
418    typedef charT char_type;
419    w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l);
error_string(regex_constants::error_type n) const420    std::string error_string(regex_constants::error_type n) const
421    {
422       if(!m_error_strings.empty())
423       {
424          std::map<int, std::string>::const_iterator p = m_error_strings.find(n);
425          return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second;
426       }
427       return get_default_error_string(n);
428    }
lookup_classname(const charT * p1,const charT * p2) const429    char_class_type lookup_classname(const charT* p1, const charT* p2) const
430    {
431       char_class_type result = lookup_classname_imp(p1, p2);
432       if(result == 0)
433       {
434          typedef typename string_type::size_type size_type;
435          string_type temp(p1, p2);
436          for(size_type i = 0; i < temp.size(); ++i)
437             temp[i] = this->tolower(temp[i]);
438          result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size());
439       }
440       return result;
441    }
442    string_type lookup_collatename(const charT* p1, const charT* p2) const;
443    string_type transform_primary(const charT* p1, const charT* p2) const;
transform(const charT * p1,const charT * p2) const444    string_type transform(const charT* p1, const charT* p2) const
445    {
446       return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_locale, p1, p2);
447    }
448 private:
449    std::map<int, std::string>     m_error_strings;   // error messages indexed by numberic ID
450    std::map<string_type, char_class_type>  m_custom_class_names; // character class names
451    std::map<string_type, string_type>      m_custom_collate_names; // collating element names
452    unsigned                       m_collate_type;    // the form of the collation string
453    charT                          m_collate_delim;   // the collation group delimiter
454    //
455    // helpers:
456    //
457    char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const;
458 };
459 
460 template <class charT>
461 typename w32_regex_traits_implementation<charT>::string_type
transform_primary(const charT * p1,const charT * p2) const462    w32_regex_traits_implementation<charT>::transform_primary(const charT* p1, const charT* p2) const
463 {
464    string_type result;
465    //
466    // What we do here depends upon the format of the sort key returned by
467    // sort key returned by this->transform:
468    //
469    switch(m_collate_type)
470    {
471    case sort_C:
472    case sort_unknown:
473       // the best we can do is translate to lower case, then get a regular sort key:
474       {
475          result.assign(p1, p2);
476          typedef typename string_type::size_type size_type;
477          for(size_type i = 0; i < result.size(); ++i)
478             result[i] = this->tolower(result[i]);
479          result = this->transform(&*result.begin(), &*result.begin() + result.size());
480          break;
481       }
482    case sort_fixed:
483       {
484          // get a regular sort key, and then truncate it:
485          result.assign(this->transform(p1, p2));
486          result.erase(this->m_collate_delim);
487          break;
488       }
489    case sort_delim:
490          // get a regular sort key, and then truncate everything after the delim:
491          result.assign(this->transform(p1, p2));
492          std::size_t i;
493          for(i = 0; i < result.size(); ++i)
494          {
495             if(result[i] == m_collate_delim)
496                break;
497          }
498          result.erase(i);
499          break;
500    }
501    if(result.empty())
502       result = string_type(1, charT(0));
503    return result;
504 }
505 
506 template <class charT>
507 typename w32_regex_traits_implementation<charT>::string_type
lookup_collatename(const charT * p1,const charT * p2) const508    w32_regex_traits_implementation<charT>::lookup_collatename(const charT* p1, const charT* p2) const
509 {
510    typedef typename std::map<string_type, string_type>::const_iterator iter_type;
511    if(m_custom_collate_names.size())
512    {
513       iter_type pos = m_custom_collate_names.find(string_type(p1, p2));
514       if(pos != m_custom_collate_names.end())
515          return pos->second;
516    }
517    std::string name(p1, p2);
518    name = lookup_default_collate_name(name);
519    if(name.size())
520       return string_type(name.begin(), name.end());
521    if(p2 - p1 == 1)
522       return string_type(1, *p1);
523    return string_type();
524 }
525 
526 template <class charT>
w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)527 w32_regex_traits_implementation<charT>::w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
528 : w32_regex_traits_char_layer<charT>(l)
529 {
530    cat_type cat;
531    std::string cat_name(w32_regex_traits<charT>::get_catalog_name());
532    if(cat_name.size())
533    {
534       cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name);
535       if(!cat)
536       {
537          std::string m("Unable to open message catalog: ");
538          std::runtime_error err(m + cat_name);
539          boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
540       }
541    }
542    //
543    // if we have a valid catalog then load our messages:
544    //
545    if(cat)
546    {
547       //
548       // Error messages:
549       //
550       for(boost::regex_constants::error_type i = static_cast<boost::regex_constants::error_type>(0);
551          i <= boost::regex_constants::error_unknown;
552          i = static_cast<boost::regex_constants::error_type>(i + 1))
553       {
554          const char* p = get_default_error_string(i);
555          string_type default_message;
556          while(*p)
557          {
558             default_message.append(1, static_cast<charT>(*p));
559             ++p;
560          }
561          string_type s = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i+200, default_message);
562          std::string result;
563          for(std::string::size_type j = 0; j < s.size(); ++j)
564          {
565             result.append(1, static_cast<char>(s[j]));
566          }
567          m_error_strings[i] = result;
568       }
569       //
570       // Custom class names:
571       //
572       static const char_class_type masks[14] =
573       {
574          0x0104u, // C1_ALPHA | C1_DIGIT
575          0x0100u, // C1_ALPHA
576          0x0020u, // C1_CNTRL
577          0x0004u, // C1_DIGIT
578          (~(0x0020u|0x0008u) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE
579          0x0002u, // C1_LOWER
580          (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL
581          0x0010u, // C1_PUNCT
582          0x0008u, // C1_SPACE
583          0x0001u, // C1_UPPER
584          0x0080u, // C1_XDIGIT
585          0x0040u, // C1_BLANK
586          w32_regex_traits_implementation<charT>::mask_word,
587          w32_regex_traits_implementation<charT>::mask_unicode,
588       };
589       static const string_type null_string;
590       for(unsigned int j = 0; j <= 13; ++j)
591       {
592          string_type s(::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, j+300, null_string));
593          if(s.size())
594             this->m_custom_class_names[s] = masks[j];
595       }
596    }
597    //
598    // get the collation format used by m_pcollate:
599    //
600    m_collate_type = BOOST_REGEX_DETAIL_NS::find_sort_syntax(this, &m_collate_delim);
601 }
602 
603 template <class charT>
604 typename w32_regex_traits_implementation<charT>::char_class_type
lookup_classname_imp(const charT * p1,const charT * p2) const605    w32_regex_traits_implementation<charT>::lookup_classname_imp(const charT* p1, const charT* p2) const
606 {
607    static const char_class_type masks[22] =
608    {
609       0,
610       0x0104u, // C1_ALPHA | C1_DIGIT
611       0x0100u, // C1_ALPHA
612       0x0040u, // C1_BLANK
613       0x0020u, // C1_CNTRL
614       0x0004u, // C1_DIGIT
615       0x0004u, // C1_DIGIT
616       (~(0x0020u|0x0008u|0x0040) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE or C1_BLANK
617       w32_regex_traits_implementation<charT>::mask_horizontal,
618       0x0002u, // C1_LOWER
619       0x0002u, // C1_LOWER
620       (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL
621       0x0010u, // C1_PUNCT
622       0x0008u, // C1_SPACE
623       0x0008u, // C1_SPACE
624       0x0001u, // C1_UPPER
625       w32_regex_traits_implementation<charT>::mask_unicode,
626       0x0001u, // C1_UPPER
627       w32_regex_traits_implementation<charT>::mask_vertical,
628       0x0104u | w32_regex_traits_implementation<charT>::mask_word,
629       0x0104u | w32_regex_traits_implementation<charT>::mask_word,
630       0x0080u, // C1_XDIGIT
631    };
632    if(m_custom_class_names.size())
633    {
634       typedef typename std::map<std::basic_string<charT>, char_class_type>::const_iterator map_iter;
635       map_iter pos = m_custom_class_names.find(string_type(p1, p2));
636       if(pos != m_custom_class_names.end())
637          return pos->second;
638    }
639    std::size_t state_id = 1u + (std::size_t)BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2);
640    if(state_id < sizeof(masks) / sizeof(masks[0]))
641       return masks[state_id];
642    return masks[0];
643 }
644 
645 
646 template <class charT>
create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)647 std::shared_ptr<const w32_regex_traits_implementation<charT> > create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l)
648 {
649    // TODO: create a cache for previously constructed objects.
650    return boost::object_cache< ::boost::BOOST_REGEX_DETAIL_NS::lcid_type, w32_regex_traits_implementation<charT> >::get(l, 5);
651 }
652 
653 } // BOOST_REGEX_DETAIL_NS
654 
655 template <class charT>
656 class w32_regex_traits
657 {
658 public:
659    typedef charT                         char_type;
660    typedef std::size_t                   size_type;
661    typedef std::basic_string<char_type>  string_type;
662    typedef ::boost::BOOST_REGEX_DETAIL_NS::lcid_type locale_type;
663    typedef std::uint_least32_t         char_class_type;
664 
665    struct boost_extensions_tag{};
666 
w32_regex_traits()667    w32_regex_traits()
668       : m_pimpl(BOOST_REGEX_DETAIL_NS::create_w32_regex_traits<charT>(::boost::BOOST_REGEX_DETAIL_NS::w32_get_default_locale()))
669    { }
length(const char_type * p)670    static size_type length(const char_type* p)
671    {
672       return std::char_traits<charT>::length(p);
673    }
syntax_type(charT c) const674    regex_constants::syntax_type syntax_type(charT c)const
675    {
676       return m_pimpl->syntax_type(c);
677    }
escape_syntax_type(charT c) const678    regex_constants::escape_syntax_type escape_syntax_type(charT c) const
679    {
680       return m_pimpl->escape_syntax_type(c);
681    }
translate(charT c) const682    charT translate(charT c) const
683    {
684       return c;
685    }
translate_nocase(charT c) const686    charT translate_nocase(charT c) const
687    {
688       return this->m_pimpl->tolower(c);
689    }
translate(charT c,bool icase) const690    charT translate(charT c, bool icase) const
691    {
692       return icase ? this->m_pimpl->tolower(c) : c;
693    }
tolower(charT c) const694    charT tolower(charT c) const
695    {
696       return this->m_pimpl->tolower(c);
697    }
toupper(charT c) const698    charT toupper(charT c) const
699    {
700       return ::boost::BOOST_REGEX_DETAIL_NS::w32_toupper(c, this->m_pimpl->m_locale);
701    }
transform(const charT * p1,const charT * p2) const702    string_type transform(const charT* p1, const charT* p2) const
703    {
704       return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_pimpl->m_locale, p1, p2);
705    }
transform_primary(const charT * p1,const charT * p2) const706    string_type transform_primary(const charT* p1, const charT* p2) const
707    {
708       return m_pimpl->transform_primary(p1, p2);
709    }
lookup_classname(const charT * p1,const charT * p2) const710    char_class_type lookup_classname(const charT* p1, const charT* p2) const
711    {
712       return m_pimpl->lookup_classname(p1, p2);
713    }
lookup_collatename(const charT * p1,const charT * p2) const714    string_type lookup_collatename(const charT* p1, const charT* p2) const
715    {
716       return m_pimpl->lookup_collatename(p1, p2);
717    }
isctype(charT c,char_class_type f) const718    bool isctype(charT c, char_class_type f) const
719    {
720       if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_base)
721          && (this->m_pimpl->isctype(f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_base, c)))
722          return true;
723       else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_unicode) && BOOST_REGEX_DETAIL_NS::is_extended(c))
724          return true;
725       else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_word) && (c == '_'))
726          return true;
727       else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_vertical)
728          && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v')))
729          return true;
730       else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_horizontal)
731          && this->isctype(c, 0x0008u) && !this->isctype(c, BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT>::mask_vertical))
732          return true;
733       return false;
734    }
toi(const charT * & p1,const charT * p2,int radix) const735    std::intmax_t toi(const charT*& p1, const charT* p2, int radix)const
736    {
737       return ::boost::BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this);
738    }
value(charT c,int radix) const739    int value(charT c, int radix)const
740    {
741       int result = (int)::boost::BOOST_REGEX_DETAIL_NS::global_value(c);
742       return result < radix ? result : -1;
743    }
imbue(locale_type l)744    locale_type imbue(locale_type l)
745    {
746       ::boost::BOOST_REGEX_DETAIL_NS::lcid_type result(getloc());
747       m_pimpl = BOOST_REGEX_DETAIL_NS::create_w32_regex_traits<charT>(l);
748       return result;
749    }
getloc() const750    locale_type getloc()const
751    {
752       return m_pimpl->m_locale;
753    }
error_string(regex_constants::error_type n) const754    std::string error_string(regex_constants::error_type n) const
755    {
756       return m_pimpl->error_string(n);
757    }
758 
759    //
760    // extension:
761    // set the name of the message catalog in use (defaults to "boost_regex").
762    //
763    static std::string catalog_name(const std::string& name);
764    static std::string get_catalog_name();
765 
766 private:
767    std::shared_ptr<const BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation<charT> > m_pimpl;
768    //
769    // catalog name handler:
770    //
771    static std::string& get_catalog_name_inst();
772 
773 #ifdef BOOST_HAS_THREADS
774    static std::mutex& get_mutex_inst();
775 #endif
776 };
777 
778 template <class charT>
catalog_name(const std::string & name)779 std::string w32_regex_traits<charT>::catalog_name(const std::string& name)
780 {
781 #ifdef BOOST_HAS_THREADS
782    std::lock_guard<std::mutex> lk(get_mutex_inst());
783 #endif
784    std::string result(get_catalog_name_inst());
785    get_catalog_name_inst() = name;
786    return result;
787 }
788 
789 template <class charT>
get_catalog_name_inst()790 std::string& w32_regex_traits<charT>::get_catalog_name_inst()
791 {
792    static std::string s_name;
793    return s_name;
794 }
795 
796 template <class charT>
get_catalog_name()797 std::string w32_regex_traits<charT>::get_catalog_name()
798 {
799 #ifdef BOOST_HAS_THREADS
800    std::lock_guard<std::mutex> lk(get_mutex_inst());
801 #endif
802    std::string result(get_catalog_name_inst());
803    return result;
804 }
805 
806 #ifdef BOOST_HAS_THREADS
807 template <class charT>
get_mutex_inst()808 std::mutex& w32_regex_traits<charT>::get_mutex_inst()
809 {
810    static std::mutex s_mutex;
811    return s_mutex;
812 }
813 #endif
814 
815 namespace BOOST_REGEX_DETAIL_NS {
816 
817 #ifdef BOOST_NO_ANSI_APIS
get_code_page_for_locale_id(lcid_type idx)818    inline unsigned int get_code_page_for_locale_id(lcid_type idx)
819    {
820       wchar_t code_page_string[7];
821       if (boost::BOOST_REGEX_DETAIL_NS::GetLocaleInfoW(idx, locale_idefaultansicodepage, code_page_string, 7) == 0)
822          return 0;
823 
824       return static_cast<unsigned int>(_wtol(code_page_string));
825 }
826 #endif
827 
828    template <class U>
init()829    inline void w32_regex_traits_char_layer<char>::init()
830    {
831       // we need to start by initialising our syntax map so we know which
832       // character is used for which purpose:
833       std::memset(m_char_map, 0, sizeof(m_char_map));
834       cat_type cat;
835       std::string cat_name(w32_regex_traits<char>::get_catalog_name());
836       if (cat_name.size())
837       {
838          cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name);
839          if (!cat)
840          {
841             std::string m("Unable to open message catalog: ");
842             std::runtime_error err(m + cat_name);
843             ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err);
844          }
845       }
846       //
847       // if we have a valid catalog then load our messages:
848       //
849       if (cat)
850       {
851          for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
852          {
853             string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_syntax(i));
854             for (string_type::size_type j = 0; j < mss.size(); ++j)
855             {
856                m_char_map[static_cast<unsigned char>(mss[j])] = i;
857             }
858          }
859       }
860       else
861       {
862          for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i)
863          {
864             const char* ptr = get_default_syntax(i);
865             while (ptr && *ptr)
866             {
867                m_char_map[static_cast<unsigned char>(*ptr)] = i;
868                ++ptr;
869             }
870          }
871       }
872       //
873       // finish off by calculating our escape types:
874       //
875       unsigned char i = 'A';
876       do
877       {
878          if (m_char_map[i] == 0)
879          {
880             if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0002u, (char)i))
881                m_char_map[i] = regex_constants::escape_type_class;
882             else if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0001u, (char)i))
883                m_char_map[i] = regex_constants::escape_type_not_class;
884          }
885       } while (0xFF != i++);
886 
887       //
888       // fill in lower case map:
889       //
890       char char_map[1 << CHAR_BIT];
891       for (int ii = 0; ii < (1 << CHAR_BIT); ++ii)
892          char_map[ii] = static_cast<char>(ii);
893 #ifndef BOOST_NO_ANSI_APIS
894       int r = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(this->m_locale, lcmap_lowercase, char_map, 1 << CHAR_BIT, this->m_lower_map, 1 << CHAR_BIT);
895       BOOST_REGEX_ASSERT(r != 0);
896 #else
897       unsigned int code_page = get_code_page_for_locale_id(this->m_locale);
898       BOOST_REGEX_ASSERT(code_page != 0);
899 
900       wchar_t wide_char_map[1 << CHAR_BIT];
901       int conv_r = boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, char_map, 1 << CHAR_BIT, wide_char_map, 1 << CHAR_BIT);
902       BOOST_REGEX_ASSERT(conv_r != 0);
903 
904       wchar_t wide_lower_map[1 << CHAR_BIT];
905       int r = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(this->m_locale, lcmap_lowercase, wide_char_map, 1 << CHAR_BIT, wide_lower_map, 1 << CHAR_BIT);
906       BOOST_REGEX_ASSERT(r != 0);
907 
908       conv_r = boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, wide_lower_map, r, this->m_lower_map, 1 << CHAR_BIT, NULL, NULL);
909       BOOST_REGEX_ASSERT(conv_r != 0);
910 #endif
911       if (r < (1 << CHAR_BIT))
912       {
913          // if we have multibyte characters then not all may have been given
914          // a lower case mapping:
915          for (int jj = r; jj < (1 << CHAR_BIT); ++jj)
916             this->m_lower_map[jj] = static_cast<char>(jj);
917       }
918 
919 #ifndef BOOST_NO_ANSI_APIS
920       r = boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(this->m_locale, ct_ctype1, char_map, 1 << CHAR_BIT, this->m_type_map);
921 #else
922       r = boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(this->m_locale, ct_ctype1, wide_char_map, 1 << CHAR_BIT, this->m_type_map);
923 #endif
924       BOOST_REGEX_ASSERT(0 != r);
925    }
926 
w32_get_default_locale()927    inline lcid_type  w32_get_default_locale()
928    {
929       return boost::BOOST_REGEX_DETAIL_NS::GetUserDefaultLCID();
930    }
931 
w32_is_lower(char c,lcid_type idx)932    inline bool  w32_is_lower(char c, lcid_type idx)
933    {
934 #ifndef BOOST_NO_ANSI_APIS
935       word mask;
936       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_lower))
937          return true;
938       return false;
939 #else
940       unsigned int code_page = get_code_page_for_locale_id(idx);
941       if (code_page == 0)
942          return false;
943 
944       wchar_t wide_c;
945       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
946          return false;
947 
948       word mask;
949       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & c1_lower))
950          return true;
951       return false;
952 #endif
953    }
954 
w32_is_lower(wchar_t c,lcid_type idx)955    inline bool  w32_is_lower(wchar_t c, lcid_type idx)
956    {
957       word mask;
958       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_lower))
959          return true;
960       return false;
961    }
962 
w32_is_upper(char c,lcid_type idx)963    inline bool  w32_is_upper(char c, lcid_type idx)
964    {
965 #ifndef BOOST_NO_ANSI_APIS
966       word mask;
967       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_upper))
968          return true;
969       return false;
970 #else
971       unsigned int code_page = get_code_page_for_locale_id(idx);
972       if (code_page == 0)
973          return false;
974 
975       wchar_t wide_c;
976       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
977          return false;
978 
979       word mask;
980       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & c1_upper))
981          return true;
982       return false;
983 #endif
984    }
985 
w32_is_upper(wchar_t c,lcid_type idx)986    inline bool  w32_is_upper(wchar_t c, lcid_type idx)
987    {
988       word mask;
989       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_upper))
990          return true;
991       return false;
992    }
993 
free_module(void * mod)994    inline void free_module(void* mod)
995    {
996       boost::BOOST_REGEX_DETAIL_NS::FreeLibrary(static_cast<HMODULE>(mod));
997    }
998 
w32_cat_open(const std::string & name)999    inline cat_type  w32_cat_open(const std::string& name)
1000    {
1001 #ifndef BOOST_NO_ANSI_APIS
1002       cat_type result(boost::BOOST_REGEX_DETAIL_NS::LoadLibraryA(name.c_str()), &free_module);
1003       return result;
1004 #else
1005       wchar_t* wide_name = (wchar_t*)_alloca((name.size() + 1) * sizeof(wchar_t));
1006       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(cp_acp, 0, name.c_str(), (int)name.size(), wide_name, (int)(name.size() + 1)) == 0)
1007          return cat_type();
1008 
1009       cat_type result(boost::BOOST_REGEX_DETAIL_NS::LoadLibraryW(wide_name), &free_module);
1010       return result;
1011 #endif
1012    }
1013 
w32_cat_get(const cat_type & cat,lcid_type,int i,const std::string & def)1014    inline std::string  w32_cat_get(const cat_type& cat, lcid_type, int i, const std::string& def)
1015    {
1016 #ifndef BOOST_NO_ANSI_APIS
1017       char buf[256];
1018       if (0 == boost::BOOST_REGEX_DETAIL_NS::LoadStringA(
1019          static_cast<HMODULE>(cat.get()),
1020          i,
1021          buf,
1022          256
1023       ))
1024       {
1025          return def;
1026       }
1027 #else
1028       wchar_t wbuf[256];
1029       int r = boost::BOOST_REGEX_DETAIL_NS::LoadStringW(
1030          static_cast<HMODULE>(cat.get()),
1031          i,
1032          wbuf,
1033          256
1034       );
1035       if (r == 0)
1036          return def;
1037 
1038 
1039       int buf_size = 1 + boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(cp_acp, 0, wbuf, r, NULL, 0, NULL, NULL);
1040       char* buf = (char*)_alloca(buf_size);
1041       if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(cp_acp, 0, wbuf, r, buf, buf_size, NULL, NULL) == 0)
1042          return def; // failed conversion.
1043 #endif
1044       return std::string(buf);
1045    }
1046 
1047 #ifndef BOOST_NO_WREGEX
w32_cat_get(const cat_type & cat,lcid_type,int i,const std::wstring & def)1048    inline std::wstring  w32_cat_get(const cat_type& cat, lcid_type, int i, const std::wstring& def)
1049    {
1050       wchar_t buf[256];
1051       if (0 == boost::BOOST_REGEX_DETAIL_NS::LoadStringW(static_cast<HMODULE>(cat.get()), i, buf, 256))
1052       {
1053          return def;
1054       }
1055       return std::wstring(buf);
1056    }
1057 #endif
w32_transform(lcid_type idx,const char * p1,const char * p2)1058    inline std::string  w32_transform(lcid_type idx, const char* p1, const char* p2)
1059    {
1060 #ifndef BOOST_NO_ANSI_APIS
1061       int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1062          idx,       // locale identifier
1063          lcmap_sortkey,  // mapping transformation type
1064          p1,  // source string
1065          static_cast<int>(p2 - p1),        // number of characters in source string
1066          0,  // destination buffer
1067          0        // size of destination buffer
1068       );
1069       if (!bytes)
1070          return std::string(p1, p2);
1071       std::string result(++bytes, '\0');
1072       bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1073          idx,       // locale identifier
1074          lcmap_sortkey,  // mapping transformation type
1075          p1,  // source string
1076          static_cast<int>(p2 - p1),        // number of characters in source string
1077          &*result.begin(),  // destination buffer
1078          bytes        // size of destination buffer
1079       );
1080 #else
1081       unsigned int code_page = get_code_page_for_locale_id(idx);
1082       if (code_page == 0)
1083          return std::string(p1, p2);
1084 
1085       int src_len = static_cast<int>(p2 - p1);
1086       wchar_t* wide_p1 = (wchar_t*)_alloca((src_len + 1) * 2);
1087       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, p1, src_len, wide_p1, src_len + 1) == 0)
1088          return std::string(p1, p2);
1089 
1090       int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1091          idx,       // locale identifier
1092          lcmap_sortkey,  // mapping transformation type
1093          wide_p1,  // source string
1094          src_len,        // number of characters in source string
1095          0,  // destination buffer
1096          0        // size of destination buffer
1097       );
1098       if (!bytes)
1099          return std::string(p1, p2);
1100       std::string result(++bytes, '\0');
1101       bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1102          idx,       // locale identifier
1103          lcmap_sortkey,  // mapping transformation type
1104          wide_p1,  // source string
1105          src_len,        // number of characters in source string
1106          (wchar_t*) & *result.begin(),  // destination buffer
1107          bytes        // size of destination buffer
1108       );
1109 #endif
1110       if (bytes > static_cast<int>(result.size()))
1111          return std::string(p1, p2);
1112       while (result.size() && result[result.size() - 1] == '\0')
1113       {
1114          result.erase(result.size() - 1);
1115       }
1116       return result;
1117    }
1118 
1119 #ifndef BOOST_NO_WREGEX
w32_transform(lcid_type idx,const wchar_t * p1,const wchar_t * p2)1120    inline std::wstring  w32_transform(lcid_type idx, const wchar_t* p1, const wchar_t* p2)
1121    {
1122       int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1123          idx,       // locale identifier
1124          lcmap_sortkey,  // mapping transformation type
1125          p1,  // source string
1126          static_cast<int>(p2 - p1),        // number of characters in source string
1127          0,  // destination buffer
1128          0        // size of destination buffer
1129       );
1130       if (!bytes)
1131          return std::wstring(p1, p2);
1132       std::string result(++bytes, '\0');
1133       bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1134          idx,       // locale identifier
1135          lcmap_sortkey,  // mapping transformation type
1136          p1,  // source string
1137          static_cast<int>(p2 - p1),        // number of characters in source string
1138          reinterpret_cast<wchar_t*>(&*result.begin()),  // destination buffer *of bytes*
1139          bytes        // size of destination buffer
1140       );
1141       if (bytes > static_cast<int>(result.size()))
1142          return std::wstring(p1, p2);
1143       while (result.size() && result[result.size() - 1] == L'\0')
1144       {
1145          result.erase(result.size() - 1);
1146       }
1147       std::wstring r2;
1148       for (std::string::size_type i = 0; i < result.size(); ++i)
1149          r2.append(1, static_cast<wchar_t>(static_cast<unsigned char>(result[i])));
1150       return r2;
1151    }
1152 #endif
w32_tolower(char c,lcid_type idx)1153    inline char  w32_tolower(char c, lcid_type idx)
1154    {
1155       char result[2];
1156 #ifndef BOOST_NO_ANSI_APIS
1157       int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1158          idx,       // locale identifier
1159          lcmap_lowercase,  // mapping transformation type
1160          &c,  // source string
1161          1,        // number of characters in source string
1162          result,  // destination buffer
1163          1);        // size of destination buffer
1164       if (b == 0)
1165          return c;
1166 #else
1167       unsigned int code_page = get_code_page_for_locale_id(idx);
1168       if (code_page == 0)
1169          return c;
1170 
1171       wchar_t wide_c;
1172       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
1173          return c;
1174 
1175       wchar_t  wide_result;
1176       int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1177          idx,       // locale identifier
1178          lcmap_lowercase,  // mapping transformation type
1179          &wide_c,  // source string
1180          1,        // number of characters in source string
1181          &wide_result,  // destination buffer
1182          1);        // size of destination buffer
1183       if (b == 0)
1184          return c;
1185 
1186       if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0)
1187          return c;  // No single byte lower case equivalent available
1188 #endif
1189       return result[0];
1190    }
1191 
1192 #ifndef BOOST_NO_WREGEX
w32_tolower(wchar_t c,lcid_type idx)1193    inline wchar_t  w32_tolower(wchar_t c, lcid_type idx)
1194    {
1195       wchar_t result[2];
1196       int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1197          idx,       // locale identifier
1198          lcmap_lowercase,  // mapping transformation type
1199          &c,  // source string
1200          1,        // number of characters in source string
1201          result,  // destination buffer
1202          1);        // size of destination buffer
1203       if (b == 0)
1204          return c;
1205       return result[0];
1206    }
1207 #endif
w32_toupper(char c,lcid_type idx)1208    inline char  w32_toupper(char c, lcid_type idx)
1209    {
1210       char result[2];
1211 #ifndef BOOST_NO_ANSI_APIS
1212       int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(
1213          idx,       // locale identifier
1214          lcmap_uppercase,  // mapping transformation type
1215          &c,  // source string
1216          1,        // number of characters in source string
1217          result,  // destination buffer
1218          1);        // size of destination buffer
1219       if (b == 0)
1220          return c;
1221 #else
1222       unsigned int code_page = get_code_page_for_locale_id(idx);
1223       if (code_page == 0)
1224          return c;
1225 
1226       wchar_t wide_c;
1227       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
1228          return c;
1229 
1230       wchar_t wide_result;
1231       int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1232          idx,       // locale identifier
1233          lcmap_uppercase,  // mapping transformation type
1234          &wide_c,  // source string
1235          1,        // number of characters in source string
1236          &wide_result,  // destination buffer
1237          1);        // size of destination buffer
1238       if (b == 0)
1239          return c;
1240 
1241       if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0)
1242          return c;  // No single byte upper case equivalent available.
1243 #endif
1244       return result[0];
1245    }
1246 
1247 #ifndef BOOST_NO_WREGEX
w32_toupper(wchar_t c,lcid_type idx)1248    inline wchar_t  w32_toupper(wchar_t c, lcid_type idx)
1249    {
1250       wchar_t result[2];
1251       int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(
1252          idx,       // locale identifier
1253          lcmap_uppercase,  // mapping transformation type
1254          &c,  // source string
1255          1,        // number of characters in source string
1256          result,  // destination buffer
1257          1);        // size of destination buffer
1258       if (b == 0)
1259          return c;
1260       return result[0];
1261    }
1262 #endif
w32_is(lcid_type idx,std::uint32_t m,char c)1263    inline bool  w32_is(lcid_type idx, std::uint32_t m, char c)
1264    {
1265       word mask;
1266 #ifndef BOOST_NO_ANSI_APIS
1267       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation<char>::mask_base))
1268          return true;
1269 #else
1270       unsigned int code_page = get_code_page_for_locale_id(idx);
1271       if (code_page == 0)
1272          return false;
1273 
1274       wchar_t wide_c;
1275       if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0)
1276          return false;
1277 
1278       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & m & w32_regex_traits_implementation<char>::mask_base))
1279          return true;
1280 #endif
1281       if ((m & w32_regex_traits_implementation<char>::mask_word) && (c == '_'))
1282          return true;
1283       return false;
1284    }
1285 
1286 #ifndef BOOST_NO_WREGEX
w32_is(lcid_type idx,std::uint32_t m,wchar_t c)1287    inline bool  w32_is(lcid_type idx, std::uint32_t m, wchar_t c)
1288    {
1289       word mask;
1290       if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation<wchar_t>::mask_base))
1291          return true;
1292       if ((m & w32_regex_traits_implementation<wchar_t>::mask_word) && (c == '_'))
1293          return true;
1294       if ((m & w32_regex_traits_implementation<wchar_t>::mask_unicode) && (c > 0xff))
1295          return true;
1296       return false;
1297    }
1298 #endif
1299 
1300 } // BOOST_REGEX_DETAIL_NS
1301 
1302 
1303 } // boost
1304 
1305 #ifdef BOOST_REGEX_MSVC
1306 #pragma warning(pop)
1307 #endif
1308 
1309 #endif // BOOST_REGEX_NO_WIN32_LOCALE
1310 
1311 #endif
1312