2 // Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
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)
8 #define BOOST_LOCALE_SOURCE
9 #include <boost/locale/conversion.hpp>
10 #include "all_generator.hpp"
11 #include <unicode/normlzr.h>
12 #include <unicode/ustring.h>
13 #include <unicode/locid.h>
14 #include <unicode/uversion.h>
15 #if U_ICU_VERSION_MAJOR_NUM*100 + U_ICU_VERSION_MINOR_NUM >= 308
16 #include <unicode/ucasemap.h>
17 #define WITH_CASE_MAPS
32 void normalize_string(icu::UnicodeString
&str
,int flags
)
34 UErrorCode code
=U_ZERO_ERROR
;
35 UNormalizationMode mode
=UNORM_DEFAULT
;
50 icu::UnicodeString tmp
;
51 icu::Normalizer::normalize(str
,mode
,0,tmp
,code
);
53 check_and_throw_icu_error(code
);
60 template<typename CharType
>
61 class converter_impl
: public converter
<CharType
> {
63 typedef CharType char_type
;
64 typedef std::basic_string
<char_type
> string_type
;
66 converter_impl(cdata
const &d
) :
72 virtual string_type
convert(converter_base::conversion_type how
,char_type
const *begin
,char_type
const *end
,int flags
= 0) const
74 icu_std_converter
<char_type
> cvt(encoding_
);
75 icu::UnicodeString str
=cvt
.icu(begin
,end
);
77 case converter_base::normalization
:
78 normalize_string(str
,flags
);
80 case converter_base::upper_case
:
83 case converter_base::lower_case
:
86 case converter_base::title_case
:
87 str
.toTitle(0,locale_
);
89 case converter_base::case_folding
:
100 std::string encoding_
;
103 #ifdef WITH_CASE_MAPS
105 raii_casemap(raii_casemap
const &);
106 void operator = (raii_casemap
const&);
108 raii_casemap(std::string
const &locale_id
) :
111 UErrorCode err
=U_ZERO_ERROR
;
112 map_
= ucasemap_open(locale_id
.c_str(),0,&err
);
113 check_and_throw_icu_error(err
);
115 throw std::runtime_error("Failed to create UCaseMap");
117 template<typename Conv
>
118 std::string
convert(Conv func
,char const *begin
,char const *end
) const
120 std::vector
<char> buf((end
-begin
)*11/10+1);
121 UErrorCode err
=U_ZERO_ERROR
;
122 int size
= func(map_
,&buf
.front(),buf
.size(),begin
,end
-begin
,&err
);
123 if(err
== U_BUFFER_OVERFLOW_ERROR
) {
126 size
= func(map_
,&buf
.front(),buf
.size(),begin
,end
-begin
,&err
);
128 check_and_throw_icu_error(err
);
129 return std::string(&buf
.front(),size
);
133 ucasemap_close(map_
);
139 class utf8_converter_impl
: public converter
<char> {
142 utf8_converter_impl(cdata
const &d
) :
143 locale_id_(d
.locale
.getName()),
148 virtual std::string
convert(converter_base::conversion_type how
,char const *begin
,char const *end
,int flags
= 0) const
151 if(how
== converter_base::normalization
) {
152 icu_std_converter
<char> cvt("UTF-8");
153 icu::UnicodeString str
=cvt
.icu(begin
,end
);
154 normalize_string(str
,flags
);
160 case converter_base::upper_case
:
161 return map_
.convert(ucasemap_utf8ToUpper
,begin
,end
);
162 case converter_base::lower_case
:
163 return map_
.convert(ucasemap_utf8ToLower
,begin
,end
);
164 case converter_base::title_case
:
166 // Non-const method, so need to create a separate map
167 raii_casemap
map(locale_id_
);
168 return map
.convert(ucasemap_utf8ToTitle
,begin
,end
);
170 case converter_base::case_folding
:
171 return map_
.convert(ucasemap_utf8FoldCase
,begin
,end
);
173 return std::string(begin
,end
-begin
);
177 std::string locale_id_
;
181 #endif // WITH_CASE_MAPS
183 std::locale
create_convert(std::locale
const &in
,cdata
const &cd
,character_facet_type type
)
187 #ifdef WITH_CASE_MAPS
189 return std::locale(in
,new utf8_converter_impl(cd
));
191 return std::locale(in
,new converter_impl
<char>(cd
));
193 return std::locale(in
,new converter_impl
<wchar_t>(cd
));
194 #ifdef BOOST_LOCALE_ENABLE_CHAR16_T
196 return std::locale(in
,new converter_impl
<char16_t
>(cd
));
198 #ifdef BOOST_LOCALE_ENABLE_CHAR32_T
200 return std::locale(in
,new converter_impl
<char32_t
>(cd
));
212 // vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4