1
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2
// utf8_codecvt_facet.cpp
4
// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
5
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
6
// Use, modification and distribution is subject to the Boost Software
7
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8
// http://www.boost.org/LICENSE_1_0.txt)
10
// Please see the comments in <boost/detail/utf8_codecvt_facet.hpp> to
11
// learn how this file should be used.
13
#include <boost/detail/utf8_codecvt_facet.hpp>
15
#include <cstdlib> // for multi-byte converson routines
18
#include <boost/limits.hpp>
19
#include <boost/config.hpp>
21
// If we don't have wstring, then Unicode support
22
// is not available anyway, so we don't need to even
23
// compiler this file. This also fixes the problem
24
// with mingw, which can compile this file, but will
25
// generate link error when building DLL.
26
#ifndef BOOST_NO_STD_WSTRING
28
BOOST_UTF8_BEGIN_NAMESPACE
30
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
31
// implementation for wchar_t
33
// Translate incoming UTF-8 into UCS-4
34
std::codecvt_base::result utf8_codecvt_facet::do_in(
35
std::mbstate_t& /*state*/,
37
const char * from_end,
38
const char * & from_next,
43
// Basic algorithm: The first octet determines how many
44
// octets total make up the UCS-4 character. The remaining
45
// "continuing octets" all begin with "10". To convert, subtract
46
// the amount that specifies the number of octets from the first
47
// octet. Subtract 0x80 (1000 0000) from each continuing octet,
48
// then mash the whole lot together. Note that each continuing
49
// octet only uses 6 bits as unique values, so only shift by
50
// multiples of 6 to combine.
51
while (from != from_end && to != to_end) {
53
// Error checking on the first octet
54
if (invalid_leading_octet(*from)){
57
return std::codecvt_base::error;
60
// The first octet is adjusted by a value dependent upon
61
// the number of "continuing octets" encoding the character
62
const int cont_octet_count = get_cont_octet_count(*from);
63
const wchar_t octet1_modifier_table[] = {
64
0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
67
// The unsigned char conversion is necessary in case char is
68
// signed (I learned this the hard way)
70
(unsigned char)(*from++) - octet1_modifier_table[cont_octet_count];
73
// 1) At the start of the loop, 'i' continuing characters have been
75
// 2) *from points to the next continuing character to be processed.
77
while(i != cont_octet_count && from != from_end) {
79
// Error checking on continuing characters
80
if (invalid_continuing_octet(*from)) {
83
return std::codecvt_base::error;
86
ucs_result *= (1 << 6);
88
// each continuing character has an extra (10xxxxxx)b attached to
89
// it that must be removed.
90
ucs_result += (unsigned char)(*from++) - 0x80;
94
// If the buffer ends with an incomplete unicode character...
95
if (from == from_end && i != cont_octet_count) {
96
// rewind "from" to before the current character translation
97
from_next = from - (i+1);
99
return std::codecvt_base::partial;
106
// Were we done converting or did we run out of destination space?
107
if(from == from_end) return std::codecvt_base::ok;
108
else return std::codecvt_base::partial;
111
std::codecvt_base::result utf8_codecvt_facet::do_out(
112
std::mbstate_t& /*state*/,
113
const wchar_t * from,
114
const wchar_t * from_end,
115
const wchar_t * & from_next,
121
// RG - consider merging this table with the other one
122
const wchar_t octet1_modifier_table[] = {
123
0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
126
wchar_t max_wchar = (std::numeric_limits<wchar_t>::max)();
127
while (from != from_end && to != to_end) {
129
// Check for invalid UCS-4 character
130
if (*from > max_wchar) {
133
return std::codecvt_base::error;
136
int cont_octet_count = get_cont_octet_out_count(*from);
138
// RG - comment this formula better
139
int shift_exponent = (cont_octet_count) * 6;
141
// Process the first character
142
*to++ = static_cast<char>(octet1_modifier_table[cont_octet_count] +
143
(unsigned char)(*from / (1 << shift_exponent)));
145
// Process the continuation characters
146
// Invariants: At the start of the loop:
147
// 1) 'i' continuing octets have been generated
148
// 2) '*to' points to the next location to place an octet
149
// 3) shift_exponent is 6 more than needed for the next octet
151
while (i != cont_octet_count && to != to_end) {
153
*to++ = static_cast<char>(0x80 + ((*from / (1 << shift_exponent)) % (1 << 6)));
156
// If we filled up the out buffer before encoding the character
157
if(to == to_end && i != cont_octet_count) {
159
to_next = to - (i+1);
160
return std::codecvt_base::partial;
166
// Were we done or did we run out of destination space
167
if(from == from_end) return std::codecvt_base::ok;
168
else return std::codecvt_base::partial;
171
// How many char objects can I process to get <= max_limit
173
int utf8_codecvt_facet::do_length(
174
BOOST_CODECVT_DO_LENGTH_CONST std::mbstate_t &,
176
const char * from_end,
177
std::size_t max_limit
178
#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
184
// RG - this code is confusing! I need a better way to express it.
188
// 1) last_octet_count has the size of the last measured character
189
// 2) char_count holds the number of characters shown to fit
190
// within the bounds so far (no greater than max_limit)
191
// 3) from_next points to the octet 'last_octet_count' before the
192
// last measured character.
193
int last_octet_count=0;
194
std::size_t char_count = 0;
195
const char* from_next = from;
196
// Use "<" because the buffer may represent incomplete characters
197
while (from_next+last_octet_count <= from_end && char_count <= max_limit) {
198
from_next += last_octet_count;
199
last_octet_count = (get_octet_count(*from_next));
202
return static_cast<int>(from_next-from_end);
205
unsigned int utf8_codecvt_facet::get_octet_count(
206
unsigned char lead_octet
208
// if the 0-bit (MSB) is 0, then 1 character
209
if (lead_octet <= 0x7f) return 1;
211
// Otherwise the count number of consecutive 1 bits starting at MSB
212
// assert(0xc0 <= lead_octet && lead_octet <= 0xfd);
214
if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2;
215
else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3;
216
else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4;
217
else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5;
220
BOOST_UTF8_END_NAMESPACE
223
template<std::size_t s>
224
int get_cont_octet_out_count_impl(wchar_t word){
235
int get_cont_octet_out_count_impl<4>(wchar_t word){
243
// Note that the following code will generate warnings on some platforms
244
// where wchar_t is defined as UCS2. The warnings are superfluous as the
245
// specialization is never instantitiated with such compilers, but this
246
// can cause problems if warnings are being treated as errors, so we guard
247
// against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
248
// should be enough to get WCHAR_MAX defined.
249
#if !defined(WCHAR_MAX)
250
# error WCHAR_MAX not defined!
252
// cope with VC++ 7.1 or earlier having invalid WCHAR_MAX
253
#if defined(_MSC_VER) && _MSC_VER <= 1310 // 7.1 or earlier
255
#elif WCHAR_MAX > 0x10000
257
if (word < 0x10000) {
260
if (word < 0x200000) {
263
if (word < 0x4000000) {
273
} // namespace anonymous
275
BOOST_UTF8_BEGIN_NAMESPACE
276
// How many "continuing octets" will be needed for this word
277
// == total octets - 1.
278
int utf8_codecvt_facet::get_cont_octet_out_count(
281
return get_cont_octet_out_count_impl<sizeof(wchar_t)>(word);
283
BOOST_UTF8_END_NAMESPACE