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 #define BOOST_LOCALE_SOURCE
9 #include <locale>
10 #include <string>
11 #include <ios>
12 #include <boost/locale/encoding.hpp>
13 #include <boost/locale/generator.hpp>
14 #include "api.hpp"
15 #include "../shared/mo_hash.hpp"
16 
17 namespace boost {
18 namespace locale {
19 namespace impl_win {
20 
21 class utf8_collator : public collator<char> {
22 public:
utf8_collator(winlocale lc,size_t refs=0)23     utf8_collator(winlocale lc,size_t refs = 0) :
24         collator<char>(refs),
25         lc_(lc)
26     {
27     }
do_compare(collator_base::level_type level,char const * lb,char const * le,char const * rb,char const * re) const28     virtual int do_compare(collator_base::level_type level,char const *lb,char const *le,char const *rb,char const *re) const
29     {
30         std::wstring l=conv::to_utf<wchar_t>(lb,le,"UTF-8");
31         std::wstring r=conv::to_utf<wchar_t>(rb,re,"UTF-8");
32         return wcscoll_l(level,l.c_str(),l.c_str()+l.size(),r.c_str(),r.c_str()+r.size(),lc_);
33     }
do_hash(collator_base::level_type level,char const * b,char const * e) const34     virtual long do_hash(collator_base::level_type level,char const *b,char const *e) const
35     {
36         std::string key = do_transform(level,b,e);
37         return gnu_gettext::pj_winberger_hash_function(key.c_str(),key.c_str() + key.size());
38     }
do_transform(collator_base::level_type level,char const * b,char const * e) const39     virtual std::string do_transform(collator_base::level_type level,char const *b,char const *e) const
40     {
41         std::wstring tmp=conv::to_utf<wchar_t>(b,e,"UTF-8");
42         std::wstring wkey = wcsxfrm_l(level,tmp.c_str(),tmp.c_str()+tmp.size(),lc_);
43         std::string key;
44         if(sizeof(wchar_t)==2)
45             key.reserve(wkey.size()*2);
46         else
47             key.reserve(wkey.size()*3);
48         for(unsigned i=0;i<wkey.size();i++) {
49             if(sizeof(wchar_t)==2) {
50                 uint16_t tv = static_cast<uint16_t>(wkey[i]);
51                 key += char(tv >> 8);
52                 key += char(tv & 0xFF);
53             }
54             else { // 4
55                 uint32_t tv = static_cast<uint32_t>(wkey[i]);
56                 // 21 bit
57                 key += char((tv >> 16) & 0xFF);
58                 key += char((tv >> 8) & 0xFF);
59                 key += char(tv & 0xFF);
60             }
61         }
62         return key;
63     }
64 private:
65     winlocale lc_;
66 };
67 
68 
69 class utf16_collator : public collator<wchar_t> {
70 public:
71     typedef std::collate<wchar_t> wfacet;
utf16_collator(winlocale lc,size_t refs=0)72     utf16_collator(winlocale lc,size_t refs = 0) :
73         collator<wchar_t>(refs),
74         lc_(lc)
75     {
76     }
do_compare(collator_base::level_type level,wchar_t const * lb,wchar_t const * le,wchar_t const * rb,wchar_t const * re) const77     virtual int do_compare(collator_base::level_type level,wchar_t const *lb,wchar_t const *le,wchar_t const *rb,wchar_t const *re) const
78     {
79         return wcscoll_l(level,lb,le,rb,re,lc_);
80     }
do_hash(collator_base::level_type level,wchar_t const * b,wchar_t const * e) const81     virtual long do_hash(collator_base::level_type level,wchar_t const *b,wchar_t const *e) const
82     {
83         std::wstring key = do_transform(level,b,e);
84         char const *begin = reinterpret_cast<char const *>(key.c_str());
85         char const *end = begin + key.size()*sizeof(wchar_t);
86         return gnu_gettext::pj_winberger_hash_function(begin,end);
87     }
do_transform(collator_base::level_type level,wchar_t const * b,wchar_t const * e) const88     virtual std::wstring do_transform(collator_base::level_type level,wchar_t const *b,wchar_t const *e) const
89     {
90         return wcsxfrm_l(level,b,e,lc_);
91     }
92 private:
93     winlocale lc_;
94 };
95 
96 
create_collate(std::locale const & in,winlocale const & lc,character_facet_type type)97 std::locale create_collate( std::locale const &in,
98                             winlocale const &lc,
99                             character_facet_type type)
100 {
101     if(lc.is_c()) {
102         switch(type) {
103         case char_facet:
104             return std::locale(in,new std::collate_byname<char>("C"));
105         case wchar_t_facet:
106             return std::locale(in,new std::collate_byname<wchar_t>("C"));
107         }
108     }
109     else {
110         switch(type) {
111         case char_facet:
112             return std::locale(in,new utf8_collator(lc));
113         case wchar_t_facet:
114             return std::locale(in,new utf16_collator(lc));
115         }
116     }
117     return in;
118 }
119 
120 
121 } // impl_std
122 } // locale
123 } //boost
124 
125 
126 
127 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
128