Coverage Report

Created: 2026-08-31 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/logging-log4cxx/src/main/cpp/transcoder.cpp
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
8
 *
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
#include <log4cxx/logstring.h>
19
#include <log4cxx/helpers/transcoder.h>
20
#include <log4cxx/helpers/pool.h>
21
#include <stdlib.h>
22
#include <log4cxx/helpers/exception.h>
23
#include <log4cxx/helpers/bytebuffer.h>
24
#include <log4cxx/helpers/charsetdecoder.h>
25
#include <log4cxx/helpers/charsetencoder.h>
26
#include <log4cxx/helpers/stringhelper.h>
27
#include <log4cxx/helpers/loglog.h>
28
#include <vector>
29
#include <cstring>
30
#if !defined(LOG4CXX)
31
  #define LOG4CXX 1
32
#endif
33
#include <log4cxx/private/log4cxx_private.h>
34
35
#if LOG4CXX_CFSTRING_API
36
  #include <CoreFoundation/CFString.h>
37
#endif
38
39
using namespace LOG4CXX_NS;
40
using namespace LOG4CXX_NS::helpers;
41
42
void Transcoder::decodeUTF8(const std::string& src, LogString& dst)
43
0
{
44
0
  std::string::const_iterator iter = src.begin();
45
46
0
  while (iter != src.end())
47
0
  {
48
0
    auto sv = getCodePoint(src, iter);
49
0
    encode(sv, dst);
50
0
  }
51
0
}
52
53
void Transcoder::encodeUTF8(const LogString& src, std::string& dst)
54
0
{
55
#if LOG4CXX_LOGCHAR_IS_UTF8
56
  dst.append(src);
57
#else
58
0
  LogString::const_iterator iter = src.begin();
59
60
0
  while (iter != src.end())
61
0
  {
62
0
    unsigned int sv = getCodePoint(src, iter);
63
0
    encode(sv, dst);
64
0
  }
65
66
0
#endif
67
0
}
68
69
#if LOG4CXX_ABI_VERSION <= 15
70
char* Transcoder::encodeUTF8(const LogString& src, Pool& p)
71
0
{
72
#if LOG4CXX_LOGCHAR_IS_UTF8
73
  return p.pstrdup(src);
74
#else
75
0
  std::string tmp;
76
0
  encodeUTF8(src, tmp);
77
0
  return p.pstrdup(tmp);
78
0
#endif
79
0
}
80
#endif
81
82
void Transcoder::encodeUTF8(unsigned int sv, ByteBuffer& dst)
83
0
{
84
0
  size_t bytes = encodeUTF8(sv, dst.current());
85
0
  dst.increment_position(bytes);
86
0
}
87
88
89
size_t Transcoder::encodeUTF8(unsigned int ch, char* dst)
90
0
{
91
0
  if (ch < 0x80)
92
0
  {
93
0
    dst[0] = (char) ch;
94
0
    return 1;
95
0
  }
96
0
  else if (ch < 0x800)
97
0
  {
98
0
    dst[0] = (char) (0xC0 + (ch >> 6));
99
0
    dst[1] = (char) (0x80 + (ch & 0x3F));
100
0
    return 2;
101
0
  }
102
0
  else if (ch < 0x10000)
103
0
  {
104
0
    dst[0] = (char) (0xE0 + (ch >> 12));
105
0
    dst[1] = (char) (0x80 + ((ch >> 6) & 0x3F));
106
0
    dst[2] = (char) (0x80 + (ch & 0x3F));
107
0
    return 3;
108
0
  }
109
0
  else if (ch <= 0x10FFFF)
110
0
  {
111
0
    dst[0] = (char) (0xF0 + (ch >> 18));
112
0
    dst[1] = (char) (0x80 + ((ch >> 12) & 0x3F));
113
0
    dst[2] = (char) (0x80 + ((ch >> 6) & 0x3F));
114
0
    dst[3] = (char) (0x80 + (ch & 0x3F));
115
0
    return 4;
116
0
  }
117
0
  else
118
0
  {
119
    //
120
    //  output UTF-8 encoding of 0xFFFF
121
    //
122
0
    dst[0] = (char) 0xEF;
123
0
    dst[1] = (char) 0xBF;
124
0
    dst[2] = (char) 0xBF;
125
0
    return 3;
126
0
  }
127
0
}
128
129
void Transcoder::encodeUTF16BE(unsigned int sv, ByteBuffer& dst)
130
0
{
131
0
  size_t bytes = encodeUTF16BE(sv, dst.current());
132
0
  dst.increment_position(bytes);
133
0
}
134
135
136
size_t Transcoder::encodeUTF16BE(unsigned int ch, char* dst)
137
0
{
138
0
  if (ch <= 0xFFFF)
139
0
  {
140
0
    dst[0] = (char) (ch >> 8);
141
0
    dst[1] = (char) (ch & 0xFF);
142
0
    return 2;
143
0
  }
144
145
0
  if (ch <= 0x10FFFF)
146
0
  {
147
0
    unsigned char w = (unsigned char) ((ch >> 16) - 1);
148
0
    dst[0] = (char) (0xD8 + (w >> 2));
149
0
    dst[1] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
150
0
    dst[2] = (char) (0xDC + ((ch >> 8) & 0x03));
151
0
    dst[3] = (char) (ch & 0xFF);
152
0
    return 4;
153
0
  }
154
155
0
  dst[0] = dst[1] = (char) 0xFF;
156
0
  return 2;
157
0
}
158
159
void Transcoder::encodeUTF16LE(unsigned int sv, ByteBuffer& dst)
160
0
{
161
0
  size_t bytes = encodeUTF16LE(sv, dst.current());
162
0
  dst.increment_position(bytes);
163
0
}
164
165
size_t Transcoder::encodeUTF16LE(unsigned int ch, char* dst)
166
0
{
167
0
  if (ch <= 0xFFFF)
168
0
  {
169
0
    dst[1] = (char) (ch >> 8);
170
0
    dst[0] = (char) (ch & 0xFF);
171
0
    return 2;
172
0
  }
173
174
0
  if (ch <= 0x10FFFF)
175
0
  {
176
0
    unsigned char w = (unsigned char) ((ch >> 16) - 1);
177
0
    dst[1] = (char) (0xD8 + (w >> 2));
178
0
    dst[0] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
179
0
    dst[3] = (char) (0xDC + ((ch >> 8) & 0x03));
180
0
    dst[2] = (char) (ch & 0xFF);
181
0
    return 4;
182
0
  }
183
184
0
  dst[0] = dst[1] = (char) 0xFF;
185
0
  return 2;
186
0
}
187
188
189
unsigned int Transcoder::decode(const std::string& src,
190
  std::string::const_iterator& iter)
191
0
{
192
0
  auto offset = iter - src.begin();
193
0
  auto remaining = src.size() - offset;
194
0
  ByteBuffer buf(const_cast<char*>(src.data() + offset), remaining);
195
0
  auto result = CharsetDecoder::getUTF8CodePoint(buf);
196
0
  iter += remaining - buf.remaining();
197
0
  return result;
198
0
}
199
200
  template <typename T>
201
unsigned int decodeCodePoint(const typename std::basic_string<T>& str, typename std::basic_string<T>::const_iterator& nextCodePoint)
202
255M
{
203
255M
  auto lastCodePoint = nextCodePoint;
204
255M
  auto ch = Transcoder::decode(str, nextCodePoint);
205
255M
  if (nextCodePoint == lastCodePoint) // failed to decode input?
206
0
  {
207
    // Skip the undecodable run and keep escaping the remaining input
208
    // instead of discarding it; the run collapses to one replacement.
209
0
    for (++nextCodePoint; nextCodePoint != str.end(); ++nextCodePoint)
210
0
    {
211
0
      auto probe = nextCodePoint;
212
0
      Transcoder::decode(str, probe);
213
0
      if (probe != nextCodePoint) // next unit starts a decodable sequence
214
0
        break;
215
0
    }
216
0
    ch = 0xFFFD; // The Unicode replacement character
217
0
  }
218
255M
  else if ( (0xD800 <= ch && ch <= 0xDFFF) // UTF-16 surrogate-range
219
255M
      || 0xFFFF == ch || 0x10FFFF < ch)
220
0
  {
221
0
    ch = 0xFFFD; // The Unicode replacement character
222
0
  }
223
255M
  return ch;
224
255M
}
Unexecuted instantiation: unsigned int decodeCodePoint<char>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::const_iterator&)
unsigned int decodeCodePoint<wchar_t>(std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> > const&, std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >::const_iterator&)
Line
Count
Source
202
255M
{
203
255M
  auto lastCodePoint = nextCodePoint;
204
255M
  auto ch = Transcoder::decode(str, nextCodePoint);
205
255M
  if (nextCodePoint == lastCodePoint) // failed to decode input?
206
0
  {
207
    // Skip the undecodable run and keep escaping the remaining input
208
    // instead of discarding it; the run collapses to one replacement.
209
0
    for (++nextCodePoint; nextCodePoint != str.end(); ++nextCodePoint)
210
0
    {
211
0
      auto probe = nextCodePoint;
212
0
      Transcoder::decode(str, probe);
213
0
      if (probe != nextCodePoint) // next unit starts a decodable sequence
214
0
        break;
215
0
    }
216
0
    ch = 0xFFFD; // The Unicode replacement character
217
0
  }
218
255M
  else if ( (0xD800 <= ch && ch <= 0xDFFF) // UTF-16 surrogate-range
219
255M
      || 0xFFFF == ch || 0x10FFFF < ch)
220
0
  {
221
0
    ch = 0xFFFD; // The Unicode replacement character
222
0
  }
223
255M
  return ch;
224
255M
}
225
226
unsigned int Transcoder::getCodePoint(const std::string& str, std::string::const_iterator& nextCodePoint)
227
0
{
228
0
  return decodeCodePoint<char>(str, nextCodePoint);
229
0
}
230
231
void Transcoder::encode(unsigned int sv, std::string& dst)
232
0
{
233
0
  char tmp[8];
234
0
  size_t bytes = encodeUTF8(sv, tmp);
235
0
  dst.append(tmp, bytes);
236
0
}
237
238
/// Does \c str contain the Unicode replacement character
239
bool Transcoder::hasReplacementCharacter(const std::string& str)
240
0
{
241
0
  return str.npos != str.find("\xEF\xBF\xBD");
242
0
}
243
244
void Transcoder::decode(const std::string& src, LogString& dst)
245
36.8k
{
246
#if LOG4CXX_CHARSET_UTF8 && LOG4CXX_LOGCHAR_IS_UTF8
247
  dst.append(src);
248
#else
249
36.8k
  static CharsetDecoderPtr decoder(CharsetDecoder::getDefaultDecoder());
250
36.8k
  dst.reserve(dst.size() + src.size());
251
36.8k
  std::string::const_iterator iter = src.begin();
252
36.8k
#if !LOG4CXX_CHARSET_EBCDIC
253
254
36.8k
  for (;
255
21.9M
    iter != src.end() && ((unsigned char) *iter) < 0x80;
256
21.9M
    iter++)
257
21.9M
  {
258
21.9M
    dst.append(1, *iter);
259
21.9M
  }
260
261
36.8k
#endif
262
263
36.8k
  if (iter != src.end())
264
5.16k
  {
265
5.16k
    size_t offset = iter - src.begin();
266
5.16k
    ByteBuffer buf(const_cast<char*>(src.data() + offset), src.size() - offset);
267
268
6.68M
    while (buf.remaining() > 0)
269
6.67M
    {
270
6.67M
      log4cxx_status_t stat = decoder->decode(buf, dst);
271
272
6.67M
      if (CharsetDecoder::isError(stat))
273
6.67M
      {
274
6.67M
        encode(LOSSCHAR, dst);
275
6.67M
        buf.increment_position(1);
276
6.67M
      }
277
6.67M
    }
278
279
5.16k
    decoder->decode(buf, dst);
280
5.16k
  }
281
282
36.8k
#endif
283
36.8k
}
284
285
#if LOG4CXX_ABI_VERSION <= 15
286
char* Transcoder::encode(const LogString& src, Pool& p)
287
0
{
288
#if LOG4CXX_CHARSET_UTF8 && LOG4CXX_LOGCHAR_IS_UTF8
289
  return p.pstrdup(src);
290
#else
291
0
  std::string tmp;
292
0
  encode(src, tmp);
293
0
  return p.pstrdup(tmp);
294
0
#endif
295
0
}
296
#endif
297
298
299
void Transcoder::encode(const LogString& src, std::string& dst)
300
0
{
301
#if LOG4CXX_CHARSET_UTF8 && LOG4CXX_LOGCHAR_IS_UTF8
302
  dst.append(src);
303
#else
304
0
  static CharsetEncoderPtr encoder(CharsetEncoder::getDefaultEncoder());
305
0
  dst.reserve(dst.size() + src.size());
306
0
  LogString::const_iterator iter = src.begin();
307
0
#if !LOG4CXX_CHARSET_EBCDIC
308
309
0
  for (;
310
0
    iter != src.end() && ((unsigned int) *iter) < 0x80;
311
0
    iter++)
312
0
  {
313
0
    dst.append(1, static_cast<char>(*iter));
314
0
  }
315
316
0
#endif
317
318
0
  if (iter != src.end())
319
0
  {
320
0
    char buf[BUFSIZE];
321
0
    ByteBuffer out(buf, BUFSIZE);
322
323
0
    while (iter != src.end())
324
0
    {
325
0
      log4cxx_status_t stat = encoder->encode(src, iter, out);
326
0
      out.flip();
327
0
      dst.append(out.data(), out.limit());
328
0
      out.clear();
329
330
0
      if (CharsetEncoder::isError(stat))
331
0
      {
332
0
        encode(LOSSCHAR, dst);
333
0
        iter++;
334
0
      }
335
0
    }
336
337
0
    encoder->encode(src, iter, out);
338
0
  }
339
340
0
#endif
341
0
}
342
343
344
template<class String, class Iterator>
345
static unsigned int decodeUTF16(const String& in, Iterator& iter)
346
{
347
  unsigned int ch1 = *iter;
348
349
  //
350
  //   if not surrogate pair
351
  //
352
  if (ch1 < 0xD800 || ch1 > 0xDFFF)
353
  {
354
    //
355
    //  then advance iterator and return wchar_t value
356
    //
357
    if (ch1 != 0xFFFF)
358
    {
359
      iter++;
360
    }
361
362
    return ch1;
363
  }
364
  else if (ch1 < 0xDC00)
365
  {
366
    //
367
    //  started with high-surrogate value
368
    //     if there is an additional wchar_t
369
    Iterator iter2 = iter + 1;
370
371
    if (iter2 != in.end())
372
    {
373
      unsigned int ch2 = *iter2;
374
375
      //
376
      //    if it is a matching low surrogate then
377
      //       advance the iterator and return the scalar value
378
      if (ch2 >= 0xDC00 && ch2 <= 0xDFFF)
379
      {
380
        iter += 2;
381
        return (ch1 - 0xD800) * 0x400 + (ch2 - 0xDC00) + 0x10000;
382
      }
383
    }
384
  }
385
386
  //
387
  //    unrecognized value, do not advance iterator
388
  //
389
  return 0xFFFF;
390
}
391
392
template<class String>
393
static void encodeUTF16(unsigned int sv, String& dst)
394
{
395
  if (sv < 0x10000)
396
  {
397
    dst.append(1, sv);
398
  }
399
  else
400
  {
401
    unsigned char u = (unsigned char) (sv >> 16);
402
    unsigned char w = (unsigned char) (u - 1);
403
    unsigned short hs = (0xD800 + ((w & 0xF) << 6) + ((sv & 0xFFFF) >> 10));
404
    unsigned short ls = (0xDC00 + (sv & 0x3FF));
405
    dst.append(1, hs);
406
    dst.append(1, ls);
407
  }
408
}
409
410
411
412
#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR || defined(WIN32) || defined(_WIN32)
413
void Transcoder::decode(const std::wstring& src, LogString& dst)
414
0
{
415
0
#if LOG4CXX_LOGCHAR_IS_WCHAR
416
0
  dst.append(src);
417
#else
418
  std::wstring::const_iterator i = src.begin();
419
420
  while (i != src.end())
421
  {
422
    auto cp = getCodePoint(src, i);
423
    encode(cp, dst);
424
  }
425
426
#endif
427
0
}
428
429
void Transcoder::encode(const LogString& src, std::wstring& dst)
430
0
{
431
0
#if LOG4CXX_LOGCHAR_IS_WCHAR
432
0
  dst.append(src);
433
#else
434
435
  for (LogString::const_iterator i = src.begin(); i != src.end();)
436
  {
437
    unsigned int cp = getCodePoint(src, i);
438
    encode(cp, dst);
439
  }
440
441
#endif
442
0
}
443
444
#if LOG4CXX_ABI_VERSION <= 15
445
wchar_t* Transcoder::wencode(const LogString& src, Pool& p)
446
0
{
447
0
#if LOG4CXX_LOGCHAR_IS_WCHAR
448
0
  const std::wstring& tmp = src;
449
#else
450
  std::wstring tmp;
451
  encode(src, tmp);
452
#endif
453
0
  wchar_t* dst = (wchar_t*) p.palloc((tmp.length() + 1) * sizeof(wchar_t));
454
0
  dst[tmp.length()] = 0;
455
0
  std::memcpy(dst, tmp.data(), tmp.length() * sizeof(wchar_t));
456
0
  return dst;
457
0
}
458
#endif
459
460
unsigned int Transcoder::decode(const std::wstring& in,
461
  std::wstring::const_iterator& iter)
462
256M
{
463
256M
#if defined(__STDC_ISO_10646__)
464
256M
  return *(iter++);
465
#else
466
  return decodeUTF16(in, iter);
467
#endif
468
256M
}
469
470
unsigned int Transcoder::getCodePoint(const std::wstring& str, std::wstring::const_iterator& nextCodePoint)
471
255M
{
472
255M
  return decodeCodePoint<wchar_t>(str, nextCodePoint);
473
255M
}
474
475
void Transcoder::encode(unsigned int sv, std::wstring& dst)
476
233M
{
477
233M
#if defined(__STDC_ISO_10646__)
478
233M
  dst.append(1, sv);
479
#else
480
481
  if (sizeof(wchar_t) == 4)
482
  {
483
    dst.append(1, sv);
484
  }
485
  else
486
  {
487
    encodeUTF16(sv, dst);
488
  }
489
490
#endif
491
233M
}
492
493
/// Does \c str contain the Unicode replacement character
494
bool Transcoder::hasReplacementCharacter(const std::wstring& str)
495
0
{
496
0
  return str.npos != str.find(LOSSCHAR);
497
0
}
498
#endif
499
500
501
502
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
503
void Transcoder::decode(const std::basic_string<UniChar>& src, LogString& dst)
504
{
505
#if LOG4CXX_LOGCHAR_IS_UNICHAR
506
  dst.append(src);
507
#else
508
509
  for (std::basic_string<UniChar>::const_iterator i = src.begin();
510
    i != src.end();)
511
  {
512
    std::basic_string<UniChar>::const_iterator start = i;
513
    unsigned int cp = decode(src, i);
514
515
    if (cp != 0xFFFF)
516
    {
517
      encode(cp, dst);
518
    }
519
    else
520
    {
521
      encode(LOSSCHAR, dst);
522
      if (i == start)
523
      {
524
        i++;
525
      }
526
    }
527
  }
528
529
#endif
530
}
531
532
void Transcoder::encode(const LogString& src, std::basic_string<UniChar>& dst)
533
{
534
#if LOG4CXX_LOGCHAR_IS_UNICHAR
535
  dst.append(src);
536
#else
537
538
  for (LogString::const_iterator i = src.begin();
539
    i != src.end();)
540
  {
541
    LogString::const_iterator start = i;
542
    unsigned int cp = decode(src, i);
543
544
    if (cp != 0xFFFF)
545
    {
546
      encode(cp, dst);
547
    }
548
    else
549
    {
550
      encode(LOSSCHAR, dst);
551
      if (i == start)
552
      {
553
        i++;
554
      }
555
    }
556
  }
557
558
#endif
559
}
560
561
unsigned int Transcoder::decode(const std::basic_string<UniChar>& in,
562
  std::basic_string<UniChar>::const_iterator& iter)
563
{
564
  return decodeUTF16(in, iter);
565
}
566
567
unsigned int Transcoder::getCodePoint(const std::basic_string<UniChar>& str, std::basic_string<UniChar>::const_iterator& nextCodePoint)
568
{
569
  return decodeCodePoint<UniChar>(str, nextCodePoint);
570
}
571
572
void Transcoder::encode(unsigned int sv, std::basic_string<UniChar>& dst)
573
{
574
  encodeUTF16(sv, dst);
575
}
576
577
/// Does \c str contain the Unicode replacement character
578
bool Transcoder::hasReplacementCharacter(const std::basic_string<UniChar>& str)
579
{
580
  return str.npos != str.find(LOSSCHAR);
581
}
582
#endif
583
584
#if LOG4CXX_CFSTRING_API
585
void Transcoder::decode(const CFStringRef& src, LogString& dst)
586
{
587
  auto length = CFStringGetLength(src);
588
#if defined(_DEBUG)
589
  if (LogLog::isDebugEnabled())
590
  {
591
    LogString msg(LOG4CXX_STR("Transcoder::decodeCFString"));
592
    msg += LOG4CXX_STR(" length ");
593
    StringHelper::toString((size_t)length, msg);
594
    LogLog::debug(msg);
595
  }
596
#endif
597
598
  if (length > 0)
599
  {
600
    std::vector<unsigned short> tmp(length);
601
    CFStringGetCharacters(src, CFRangeMake(0, length), &tmp[0]);
602
    for (auto i = tmp.begin(); i != tmp.end(); )
603
    {
604
      auto start = i;
605
      unsigned int cp = decodeUTF16(tmp, i);
606
      if (cp != 0xFFFF)
607
      {
608
        encode(cp, dst);
609
      }
610
      else
611
      {
612
        encode(LOSSCHAR, dst);
613
        if (i == start)
614
        {
615
          i++;
616
        }
617
      }
618
    }
619
  }
620
}
621
622
CFStringRef Transcoder::encode(const LogString& src)
623
{
624
  std::basic_string<unsigned short> tmp;
625
  for (auto ch : src)
626
    encodeUTF16(ch, tmp);
627
  return CFStringCreateWithCharacters(kCFAllocatorDefault, tmp.data(), tmp.size());
628
}
629
#endif // #if LOG4CXX_CFSTRING_API
630
631
632
logchar Transcoder::decode(char val)
633
0
{
634
#if LOG4CXX_CHARSET_EBCDIC
635
  LogString dst;
636
  Transcoder::decode(std::string(1, val), dst);
637
  return dst[0];
638
#else
639
0
  return val;
640
0
#endif
641
0
}
642
643
LogString Transcoder::decode(const char* val)
644
2
{
645
#if LOG4CXX_LOGCHAR_IS_UTF8 && !LOG4CXX_CHARSET_EBCDIC
646
  return val;
647
#else
648
2
  LogString dst;
649
2
  Transcoder::decode(val, dst);
650
2
  return dst;
651
2
#endif
652
2
}
653
654
655
std::string Transcoder::encodeCharsetName(const LogString& val)
656
0
{
657
0
  char asciiTable[] = { ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
658
0
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
659
0
      '@', 'A', 'B', 'C', 'D', 'E', 'F',  'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
660
0
      'P', 'Q', 'R', 'S', 'T', 'U', 'V',  'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
661
0
      '`', 'a', 'b', 'c', 'd', 'e', 'f',  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
662
0
      'p', 'q', 'r', 's', 't', 'u', 'v',  'w', 'x', 'y', 'z', '{', '|', '}', '~'
663
0
    };
664
0
  std::string out;
665
666
0
  for (auto& item : val)
667
0
  {
668
0
    if (item >= 0x20 && item < 0x7F)
669
0
    {
670
0
      out.append(1, asciiTable[item - 0x20]);
671
0
    }
672
0
    else
673
0
    {
674
0
      out.append(1, '?');
675
0
    }
676
0
  }
677
678
0
  return out;
679
0
}