Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
BasicTranscoder.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* BasicTranscoder.cc (C) 2000-2024 */
9/* */
10/* Conversions entre utf8 et utf16. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arccore/base/CoreArray.h"
15#include "arccore/base/BasicTranscoder.h"
16
17#ifdef ARCCORE_HAS_GLIB
18#include <glib.h>
19#else
20#include <cwctype>
21#endif
22
23#include <iostream>
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28namespace
29{
30using namespace Arccore;
31
32bool _isSpace(Int32 wc)
33{
34#ifdef ARCCORE_HAS_GLIB
35 return g_unichar_isspace(wc);
36#else
37 return std::iswspace(wc);
38#endif
39}
40Int32 _toUpper(Int32 wc)
41{
42#ifdef ARCCORE_HAS_GLIB
43 return g_unichar_toupper(wc);
44#else
45 return std::towupper(wc);
46#endif
47}
48Int32 _toLower(Int32 wc)
49{
50#ifdef ARCCORE_HAS_GLIB
51 return g_unichar_tolower(wc);
52#else
53 return std::towlower(wc);
54#endif
55}
56
57int _invalidChar(Int32 pos, Int32& wc)
58{
59 std::cout << "WARNING: Invalid sequence '" << wc << "' in conversion input (position=" << pos << ")\n";
60 wc = '?';
61 return 1;
62}
63
64int _notEnoughChar(Int32& wc)
65{
66 std::cout << "WARNING: Invalid sequence '" << wc << "' in conversion input (unexpected eof)\n";
67 wc = '?';
68 return 1;
69}
70
71/*---------------------------------------------------------------------------*/
72/*---------------------------------------------------------------------------*/
73/*!
74 * \brief Converti un caractère unicode (UCS4) en utf8.
75 *
76 * Routine récupérée dans libiconv.
77 *
78 * Un caractère ucs4 génère entre 1 et 6 caractères utf8.
79 * Les caractères convertis sont ajoutés au tableau \a utf8.
80 *
81 * \param wc valeur ucs4 du caractère à convertir
82 * \param utf8[out] Tableau contenant les caractères utf8 convertis
83 */
84void ucs4_to_utf8(Int32 wc, CoreArray<Byte>& utf8)
85{
86 Int32 r[6];
87 int count;
88 if (wc < 0x80)
89 count = 1;
90 else if (wc < 0x800)
91 count = 2;
92 else if (wc < 0x10000)
93 count = 3;
94 else if (wc < 0x200000)
95 count = 4;
96 else if (wc < 0x4000000)
97 count = 5;
98 else
99 count = 6;
100 switch (count) { /* note: code falls through cases! */
101 case 6:
102 r[5] = 0x80 | (wc & 0x3f);
103 wc = wc >> 6;
104 wc |= 0x4000000;
105 [[fallthrough]];
106 case 5:
107 r[4] = 0x80 | (wc & 0x3f);
108 wc = wc >> 6;
109 wc |= 0x200000;
110 [[fallthrough]];
111 case 4:
112 r[3] = 0x80 | (wc & 0x3f);
113 wc = wc >> 6;
114 wc |= 0x10000;
115 [[fallthrough]];
116 case 3:
117 r[2] = 0x80 | (wc & 0x3f);
118 wc = wc >> 6;
119 wc |= 0x800;
120 [[fallthrough]];
121 case 2:
122 r[1] = 0x80 | (wc & 0x3f);
123 wc = wc >> 6;
124 wc |= 0xc0;
125 [[fallthrough]];
126 case 1:
127 r[0] = wc;
128 }
129 for (int i = 0; i < count; ++i)
130 utf8.add((Byte)r[i]);
131}
132/*---------------------------------------------------------------------------*/
133/*---------------------------------------------------------------------------*/
134/*!
135 * \brief Converti un caractère utf8 en unicode (UCS4).
136 *
137 * Routine récupérée dans libiconv.
138 *
139 * Un caractère ucs4 est créé à partir de 1 à 6 caractères utf8.
140 *
141 * \param uchar Tableau contenant les caractères utf8 à convertir
142 * \param index indice du premier élément du tableau à convertir
143 * \param wc [out] valeur ucs4 du caractère.
144 * \return le nombre de caractères utf8 lus.
145 */
146Int64 utf8_to_ucs4(Span<const Byte> uchar, Int64 index, Int32& wc)
147{
148 const Byte* s = uchar.data() + index;
149 unsigned char c = s[0];
150 Int64 n = uchar.size() - index;
151 if (c < 0x80) {
152 wc = c;
153 return 1;
154 }
155
156 if (c < 0xc2)
157 return _invalidChar(1, wc);
158
159 if (c < 0xe0) {
160 if (n < 2)
161 return _notEnoughChar(wc);
162 if (!((s[1] ^ 0x80) < 0x40))
163 return _invalidChar(2, wc);
164 wc = ((Int32)(c & 0x1f) << 6) | (Int32)(s[1] ^ 0x80);
165 return 2;
166 }
167
168 if (c < 0xf0) {
169 if (n < 3)
170 return _notEnoughChar(wc);
171 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0)))
172 return _invalidChar(4, wc);
173 wc = ((Int32)(c & 0x0f) << 12) | ((Int32)(s[1] ^ 0x80) << 6) | (Int32)(s[2] ^ 0x80);
174 return 3;
175 }
176
177 if (c < 0xf8) {
178 if (n < 4)
179 return _notEnoughChar(wc);
180 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (c >= 0xf1 || s[1] >= 0x90)))
181 return _invalidChar(5, wc);
182 wc = ((Int32)(c & 0x07) << 18) | ((Int32)(s[1] ^ 0x80) << 12) | ((Int32)(s[2] ^ 0x80) << 6) | (Int32)(s[3] ^ 0x80);
183 return 4;
184 }
185
186 // On ne devrait jamais arriver ici
187 // car il n'y a plus (depuis la norme 2003) de caractères UTF-8
188 // encodés sur 5 ou 6 octets.
189
190 if (c < 0xfc) {
191 if (n < 5)
192 return _notEnoughChar(wc);
193 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (c >= 0xf9 || s[1] >= 0x88)))
194 return _invalidChar(7, wc);
195 wc = ((Int32)(c & 0x03) << 24) | ((Int32)(s[1] ^ 0x80) << 18) | ((Int32)(s[2] ^ 0x80) << 12) | ((Int32)(s[3] ^ 0x80) << 6) | (Int32)(s[4] ^ 0x80);
196 return 5;
197 }
198 if (c < 0xfe) {
199 if (n < 6)
200 return _notEnoughChar(wc);
201 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (s[5] ^ 0x80) < 0x40 && (c >= 0xfd || s[1] >= 0x84)))
202 return _invalidChar(8, wc);
203 wc = ((Int32)(c & 0x01) << 30) | ((Int32)(s[1] ^ 0x80) << 24) | ((Int32)(s[2] ^ 0x80) << 18) | ((Int32)(s[3] ^ 0x80) << 12) | ((Int32)(s[4] ^ 0x80) << 6) | (Int32)(s[5] ^ 0x80);
204 return 6;
205 }
206 return _invalidChar(9, wc);
207}
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211/*!
212 * \brief Converti un caractère utf16 en unicode (UCS4).
213 *
214 * Routine récupérée dans libiconv.
215 *
216 * Un caractère ucs4 est créé à partir de 1 ou 2 caractères utf16.
217 *
218 * \param uchar Tableau contenant les caractères utf16 à convertir
219 * \param index indice du premier élément du tableau à convertir
220 * \param wc [out] valeur ucs4 du caractère.
221 * \return le nombre de caractères utf16 lus.
222 */
223Int64 utf16_to_ucs4(Span<const UChar> uchar, Int64 index, Int32& wc)
224{
225 wc = uchar[index];
226 if (wc >= 0xd800 && wc < 0xdc00) {
227 if ((index + 1) == uchar.size()) {
228 std::cout << "WARNING: utf16_to_ucs4(): Invalid sequence in conversion input (unexpected eof)\n";
229 wc = 0x1A;
230 return 1;
231 }
232 Int32 wc2 = uchar[index + 1];
233 if (!(wc2 >= 0xdc00 && wc2 < 0xe000)) {
234 std::cout << "WARNING: utf16_to_ucs4(): Invalid sequence (1) '" << wc2 << "' in conversion input\n";
235 wc = 0x1A;
236 return 1;
237 }
238 wc = (0x10000 + ((wc - 0xd800) << 10) + (wc2 - 0xdc00));
239 return 2;
240 }
241 else if (wc >= 0xdc00 && wc < 0xe0000) {
242 std::cout << "WARNING: utf16_to_ucs4(): Invalid sequence (2) '" << wc << "' in conversion input\n";
243 wc = 0x1A;
244 return 1;
245 }
246 return 1;
247}
248
249/*---------------------------------------------------------------------------*/
250/*---------------------------------------------------------------------------*/
251
252} // namespace
253
254/*---------------------------------------------------------------------------*/
255/*---------------------------------------------------------------------------*/
256/*!
257 * \brief Converti un caractère (UCS4) en utf16 big-endian.
258 *
259 * Routine récupérée dans libiconv.
260 *
261 * Un caractère ucs4 est génère 1 ou 2 caractères utf16. Les
262 * caractères convertis sont ajoutés au tableau \a uchar
263 *
264 * \param wc valeur ucs4 du caractère à convertir
265 * \param uchar[out] Tableau contenant les caractères utf16 convertis
266 */
267void
268ucs4_to_utf16(Int32 wc,CoreArray<UChar>& uchar)
269{
270 if (wc < 0xd800){
271 uchar.add((UChar)wc);
272 return;
273 }
274 if (wc < 0xe000){
275 std::cout << "WARNING: ucs4_to_utf16(): Invalid sequence in conversion input\n";
276 uchar.add(0x1A);
277 return;
278 }
279 if (wc < 0x10000){
280 uchar.add((UChar)wc);
281 return;
282 }
283 if (wc < 0x110000){
284 uchar.add( (UChar) ((wc - 0x10000) / 0x400 + 0xd800) );
285 uchar.add( (UChar) ((wc - 0x10000) % 0x400 + 0xdc00) );
286 return;
287 }
288 std::cerr << "WARNING: ucs4_to_utf16(): Invalid sequence in conversion input\n";
289 uchar.add(0x1A);
290}
291
292namespace Arccore
293{
294
295/*---------------------------------------------------------------------------*/
296/*---------------------------------------------------------------------------*/
297
298Int64 BasicTranscoder::
299stringLen(const UChar* ustr)
300{
301 if (!ustr || ustr[0] == 0)
302 return 0;
303 const UChar* u = ustr + 1;
304 while ((*u)!=0)
305 ++u;
306 return arccoreCheckLargeArraySize((std::size_t)(u - ustr));
307}
308
309/*---------------------------------------------------------------------------*/
310/*---------------------------------------------------------------------------*/
311
312//! Traduit depuis UTF16 vers UTF8
315{
316 for( Int64 i=0, n=utf16.size(); i<n; ){
317 Int32 wc;
318 i += utf16_to_ucs4(utf16,i,wc);
319 ucs4_to_utf8(wc,utf8);
320 }
321}
322
323/*---------------------------------------------------------------------------*/
324/*---------------------------------------------------------------------------*/
325
326void BasicTranscoder::
327transcodeFromUtf8ToUtf16(Span<const Byte> utf8,CoreArray<UChar>& utf16)
328{
329 for( Int64 i=0, n=utf8.size(); i<n; ){
330 Int32 wc;
331 i += utf8_to_ucs4(utf8,i,wc);
332 ucs4_to_utf16(wc,utf16);
333 }
334}
335
336/*---------------------------------------------------------------------------*/
337/*---------------------------------------------------------------------------*/
338
339void BasicTranscoder::
340replaceWS(CoreArray<Byte>& out_utf8)
341{
342 CoreArray<Byte> copy_utf8(out_utf8);
343 Span<const Byte> utf8(copy_utf8.view());
344 out_utf8.clear();
345 for (Int64 i = 0, n = utf8.size(); i < n;) {
346 Int32 wc;
347 i += utf8_to_ucs4(utf8, i, wc);
348 if (_isSpace(wc))
349 out_utf8.add(' ');
350 else
351 ucs4_to_utf8(wc, out_utf8);
352 }
353}
354
355/*---------------------------------------------------------------------------*/
356/*---------------------------------------------------------------------------*/
357
358void BasicTranscoder::
359collapseWS(CoreArray<Byte>& out_utf8)
360{
361 CoreArray<Byte> copy_utf8(out_utf8);
362 Span<const Byte> utf8(copy_utf8.view());
363 out_utf8.clear();
364 Int64 i = 0;
365 Int64 n = utf8.size();
366 // Si la chaîne est vide, retourne une chaîne vide.
367 if (n == 1) {
368 out_utf8.add('\0');
369 return;
370 }
371 bool old_is_space = true;
372 bool has_spaces_only = true;
373 for (; i < n;) {
374 if (utf8[i] == 0)
375 break;
376 Int32 wc;
377 i += utf8_to_ucs4(utf8, i, wc);
378 if (_isSpace(wc)) {
379 if (!old_is_space)
380 out_utf8.add(' ');
381 old_is_space = true;
382 }
383 else {
384 old_is_space = false;
385 ucs4_to_utf8(wc, out_utf8);
386 has_spaces_only = false;
387 }
388 }
389 if (old_is_space && (!has_spaces_only)) {
390 if (out_utf8.size() > 0)
391 out_utf8.back() = 0;
392 }
393 else {
394 if (has_spaces_only)
395 out_utf8.add(' ');
396 out_utf8.add(0);
397 }
398}
399
400/*---------------------------------------------------------------------------*/
401/*---------------------------------------------------------------------------*/
402
403void BasicTranscoder::
404upperCase(CoreArray<Byte>& out_utf8)
405{
406 CoreArray<Byte> copy_utf8(out_utf8);
407 Span<const Byte> utf8(copy_utf8.view());
408 out_utf8.clear();
409 for (Int64 i = 0, n = utf8.size(); i < n;) {
410 Int32 wc;
411 i += utf8_to_ucs4(utf8, i, wc);
412 Int32 upper_wc = _toUpper(wc);
413 ucs4_to_utf8(upper_wc, out_utf8);
414 }
415}
416
417/*---------------------------------------------------------------------------*/
418/*---------------------------------------------------------------------------*/
419
420void BasicTranscoder::
421lowerCase(CoreArray<Byte>& out_utf8)
422{
423 CoreArray<Byte> copy_utf8(out_utf8);
424 Span<const Byte> utf8(copy_utf8.view());
425 out_utf8.clear();
426 for (Int64 i = 0, n = utf8.size(); i < n;) {
427 Int32 wc;
428 i += utf8_to_ucs4(utf8, i, wc);
429 Int32 upper_wc = _toLower(wc);
430 ucs4_to_utf8(upper_wc, out_utf8);
431 }
432}
433
434/*---------------------------------------------------------------------------*/
435/*---------------------------------------------------------------------------*/
436
437void BasicTranscoder::
438substring(CoreArray<Byte>& out_utf8,Span<const Byte> utf8,Int64 pos,Int64 len)
439{
440 // Copie les \a len caractères unicodes de \a utf8 à partir de la position \a pos
441 Int64 current_pos = 0;
442 for( Int64 i=0, n=utf8.size(); i<n; ){
443 Int32 wc;
444 i += utf8_to_ucs4(utf8,i,wc);
445 if (current_pos>=pos && current_pos<(pos+len)){
446 // Pour être sur de ne pas ajouter le 0 terminal
447 if (wc!=0)
448 ucs4_to_utf8(wc,out_utf8);
449 }
450 ++current_pos;
451 }
452 // Ajoute le 0 terminal
453 ucs4_to_utf8(0,out_utf8);
454}
455
456/*---------------------------------------------------------------------------*/
457/*---------------------------------------------------------------------------*/
458
459}
460
461/*---------------------------------------------------------------------------*/
462/*---------------------------------------------------------------------------*/
static void transcodeFromUtf16ToUtf8(Span< const UChar > utf16, CoreArray< Byte > &utf8)
Traduit depuis UTF16 vers UTF8.
Int64 size() const
Retourne la taille du tableau.
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:209
constexpr __host__ __device__ pointer data() const noexcept
Pointeur sur le début de la vue.
Definition Span.h:419
Vue d'un tableau d'éléments de type T.
Definition Span.h:510
Espace de nom de Arccore.
Definition ArcaneTypes.h:24
unsigned short UChar
Type d'un caractère unicode.
Definition BaseTypes.h:47
constexpr __host__ __device__ Int64 arccoreCheckLargeArraySize(size_t size)
Vérifie que size peut être converti dans un 'Int64' pour servir de taille à un tableau.
std::int64_t Int64
Type entier signé sur 64 bits.
std::int32_t Int32
Type entier signé sur 32 bits.
unsigned char Byte
Type d'un octet.
Definition BaseTypes.h:43