Line data Source code
1 : // file : xsd/cxx/xml/char-utf8.txx
2 : // copyright : Copyright (c) 2005-2017 Code Synthesis Tools CC
3 : // license : GNU GPL v2 + exceptions; see accompanying LICENSE file
4 :
5 : #include <xsd/cxx/config.hxx> // XSD_CXX11
6 :
7 : #ifdef XSD_CXX11
8 : # include <memory> // std::unique_ptr
9 : #else
10 : # include <xsd/cxx/auto-array.hxx>
11 : #endif
12 :
13 : namespace xsd
14 : {
15 : namespace cxx
16 : {
17 : namespace xml
18 : {
19 : template <typename C>
20 : const unsigned char char_utf8_transcoder<C>::first_byte_mask_[5] =
21 : {
22 : 0x00, 0x00, 0xC0, 0xE0, 0xF0
23 : };
24 :
25 : template <typename C>
26 0 : std::basic_string<C> char_utf8_transcoder<C>::
27 : to (const XMLCh* s, std::size_t len)
28 : {
29 0 : const XMLCh* end (s + len);
30 :
31 : // Find what the resulting buffer size will be.
32 : //
33 0 : std::size_t rl (0);
34 0 : unsigned int u (0); // Four byte UCS-4 char.
35 :
36 0 : bool valid (true);
37 0 : const XMLCh* p (s);
38 :
39 0 : for (; p < end; ++p)
40 : {
41 0 : XMLCh x (*p);
42 :
43 0 : if (x < 0xD800 || x > 0xDBFF)
44 0 : u = x;
45 : else
46 : {
47 : // Make sure we have one more char and it has a valid
48 : // value for the second char in a surrogate pair.
49 : //
50 0 : if (++p == end || !((*p >= 0xDC00) && (*p <= 0xDFFF)))
51 : {
52 0 : valid = false;
53 0 : break;
54 : }
55 :
56 0 : u = ((x - 0xD800) << 10) + (*p - 0xDC00) + 0x10000;
57 : }
58 :
59 0 : if (u < 0x80)
60 0 : rl++;
61 0 : else if (u < 0x800)
62 0 : rl += 2;
63 0 : else if (u < 0x10000)
64 0 : rl += 3;
65 0 : else if (u < 0x110000)
66 0 : rl += 4;
67 : else
68 : {
69 0 : valid = false;
70 0 : break;
71 : }
72 : }
73 :
74 0 : if (!valid)
75 0 : throw invalid_utf16_string ();
76 :
77 0 : std::basic_string<C> r;
78 0 : r.reserve (rl + 1);
79 0 : r.resize (rl);
80 0 : C* rs (const_cast<C*> (r.c_str ()));
81 :
82 0 : std::size_t i (0);
83 0 : unsigned int count (0);
84 :
85 0 : p = s;
86 :
87 : // Tight first loop for the common case.
88 : //
89 0 : for (; p < end && *p < 0x80; ++p)
90 0 : rs[i++] = C (*p);
91 :
92 0 : for (; p < end; ++p)
93 : {
94 0 : XMLCh x (*p);
95 :
96 0 : if ((x >= 0xD800) && (x <= 0xDBFF))
97 : {
98 0 : u = ((x - 0xD800) << 10) + (*++p - 0xDC00) + 0x10000;
99 : }
100 : else
101 0 : u = x;
102 :
103 0 : if (u < 0x80)
104 0 : count = 1;
105 0 : else if (u < 0x800)
106 0 : count = 2;
107 0 : else if (u < 0x10000)
108 0 : count = 3;
109 0 : else if (u < 0x110000)
110 0 : count = 4;
111 :
112 0 : switch(count)
113 : {
114 0 : case 4:
115 : {
116 0 : rs[i + 3] = C ((u | 0x80UL) & 0xBFUL);
117 0 : u >>= 6;
118 : }
119 0 : case 3:
120 : {
121 0 : rs[i + 2] = C ((u | 0x80UL) & 0xBFUL);
122 0 : u >>= 6;
123 : }
124 0 : case 2:
125 : {
126 0 : rs[i + 1] = C ((u | 0x80UL) & 0xBFUL);
127 0 : u >>= 6;
128 : }
129 0 : case 1:
130 : {
131 0 : rs[i] = C (u | first_byte_mask_[count]);
132 : }
133 : }
134 :
135 0 : i += count;
136 : }
137 :
138 0 : return r;
139 0 : }
140 :
141 : template <typename C>
142 0 : XMLCh* char_utf8_transcoder<C>::
143 : from (const C* s, std::size_t len)
144 : {
145 0 : bool valid (true);
146 0 : const C* end (s + len);
147 :
148 : // Find what the resulting buffer size will be.
149 : //
150 0 : std::size_t rl (0);
151 0 : unsigned int count (0);
152 :
153 0 : for (const C* p (s); p < end; ++p)
154 : {
155 0 : unsigned char c (static_cast<unsigned char> (*p));
156 :
157 0 : if (c < 0x80)
158 : {
159 : // Fast path.
160 : //
161 0 : rl += 1;
162 0 : continue;
163 : }
164 0 : else if ((c >> 5) == 0x06)
165 0 : count = 2;
166 0 : else if ((c >> 4) == 0x0E)
167 0 : count = 3;
168 0 : else if ((c >> 3) == 0x1E)
169 0 : count = 4;
170 : else
171 : {
172 0 : valid = false;
173 0 : break;
174 : }
175 :
176 0 : p += count - 1; // One will be added in the for loop
177 :
178 0 : if (p + 1 > end)
179 : {
180 0 : valid = false;
181 0 : break;
182 : }
183 :
184 : // BMP is represented by up to 3 code points in UTF-8.
185 : //
186 0 : rl += count > 3 ? 2 : 1;
187 : }
188 :
189 0 : if (!valid)
190 0 : throw invalid_utf8_string ();
191 :
192 : #ifdef XSD_CXX11
193 0 : std::unique_ptr<XMLCh[]> r (
194 : #else
195 : auto_array<XMLCh> r (
196 : #endif
197 0 : new XMLCh[rl + 1]);
198 0 : XMLCh* ir (r.get ());
199 :
200 0 : unsigned int u (0); // Four byte UCS-4 char.
201 :
202 0 : for (const C* p (s); p < end; ++p)
203 : {
204 0 : unsigned char c (static_cast<unsigned char> (*p));
205 :
206 0 : if (c < 0x80)
207 : {
208 : // Fast path.
209 : //
210 0 : *ir++ = static_cast<XMLCh> (c);
211 0 : continue;
212 : }
213 0 : else if ((c >> 5) == 0x06)
214 : {
215 : // UTF-8: 110yyyyy 10zzzzzz
216 : // Unicode: 00000yyy yyzzzzzz
217 : //
218 0 : u = (c & 0x1F) << 6;
219 :
220 0 : c = *++p;
221 0 : if ((c >> 6) != 2)
222 : {
223 0 : valid = false;
224 0 : break;
225 : }
226 0 : u |= c & 0x3F;
227 : }
228 0 : else if ((c >> 4) == 0x0E)
229 : {
230 : // UTF-8: 1110xxxx 10yyyyyy 10zzzzzz
231 : // Unicode: xxxxyyyy yyzzzzzz
232 : //
233 0 : u = (c & 0x0F) << 6;
234 :
235 0 : c = *++p;
236 0 : if ((c >> 6) != 2)
237 : {
238 0 : valid = false;
239 0 : break;
240 : }
241 0 : u = (u | (c & 0x3F)) << 6;
242 :
243 0 : c = *++p;
244 0 : if ((c >> 6) != 2)
245 : {
246 0 : valid = false;
247 0 : break;
248 : }
249 0 : u |= c & 0x3F;
250 : }
251 0 : else if ((c >> 3) == 0x1E)
252 : {
253 : // UTF-8: 000wwwxx xxxxyyyy yyzzzzzz
254 : // Unicode: 11110www 10xxxxxx 10yyyyyy 10zzzzzz
255 : //
256 0 : u = (c & 0x07) << 6;
257 :
258 0 : c = *++p;
259 0 : if ((c >> 6) != 2)
260 : {
261 0 : valid = false;
262 0 : break;
263 : }
264 0 : u = (u | (c & 0x3F)) << 6;
265 :
266 0 : c = *++p;
267 0 : if ((c >> 6) != 2)
268 : {
269 0 : valid = false;
270 0 : break;
271 : }
272 0 : u = (u | (c & 0x3F)) << 6;
273 :
274 0 : c = *++p;
275 0 : if ((c >> 6) != 2)
276 : {
277 0 : valid = false;
278 0 : break;
279 : }
280 0 : u |= c & 0x3F;
281 : }
282 :
283 0 : if (u & 0xFFFF0000)
284 : {
285 : // Surrogate pair.
286 : //
287 0 : *ir++ = static_cast<XMLCh> (((u - 0x10000) >> 10) + 0xD800);
288 0 : *ir++ = static_cast<XMLCh> ((u & 0x3FF) + 0xDC00);
289 : }
290 : else
291 0 : *ir++ = static_cast<XMLCh> (u);
292 : }
293 :
294 0 : if (!valid)
295 0 : throw invalid_utf8_string ();
296 :
297 0 : *ir = XMLCh (0);
298 :
299 0 : return r.release ();
300 0 : }
301 : }
302 : }
303 : }
|