Coverage Report

Created: 2026-09-14 06:53

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/private/bytebuffer_priv.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
  dst.increment_position(CharsetEncoder::putUTF8CodePoint(sv, dst.current()));
85
0
}
86
87
void Transcoder::encodeUTF16BE(unsigned int sv, ByteBuffer& dst)
88
0
{
89
0
  dst.increment_position(CharsetEncoder::putUTF16BECodePoint(sv, dst.current()));
90
0
}
91
92
void Transcoder::encodeUTF16LE(unsigned int sv, ByteBuffer& dst)
93
0
{
94
0
  dst.increment_position(CharsetEncoder::putUTF16LECodePoint(sv, dst.current()));
95
0
}
96
97
unsigned int Transcoder::decode(const std::string& src,
98
  std::string::const_iterator& iter)
99
0
{
100
0
  auto offset = iter - src.begin();
101
0
  auto remaining = src.size() - offset;
102
0
  ByteBufferPriv buf(const_cast<char*>(src.data() + offset), remaining);
103
0
  auto result = CharsetDecoder::getUTF8CodePoint(buf);
104
0
  iter += remaining - buf.remaining();
105
0
  return result;
106
0
}
107
108
  template <typename T>
109
unsigned int decodeCodePoint(const typename std::basic_string<T>& str, typename std::basic_string<T>::const_iterator& nextCodePoint)
110
45.1k
{
111
45.1k
  auto lastCodePoint = nextCodePoint;
112
45.1k
  auto ch = Transcoder::decode(str, nextCodePoint);
113
45.1k
  if (nextCodePoint == lastCodePoint) // failed to decode input?
114
0
  {
115
    // Skip the undecodable run and keep escaping the remaining input
116
    // instead of discarding it; the run collapses to one replacement.
117
0
    for (++nextCodePoint; nextCodePoint != str.end(); ++nextCodePoint)
118
0
    {
119
0
      auto probe = nextCodePoint;
120
0
      Transcoder::decode(str, probe);
121
0
      if (probe != nextCodePoint) // next unit starts a decodable sequence
122
0
        break;
123
0
    }
124
0
    ch = 0xFFFD; // The Unicode replacement character
125
0
  }
126
45.1k
  else if ( (0xD800 <= ch && ch <= 0xDFFF) // UTF-16 surrogate-range
127
45.1k
      || 0xFFFF == ch || 0x10FFFF < ch)
128
0
  {
129
0
    ch = 0xFFFD; // The Unicode replacement character
130
0
  }
131
45.1k
  return ch;
132
45.1k
}
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
110
45.1k
{
111
45.1k
  auto lastCodePoint = nextCodePoint;
112
45.1k
  auto ch = Transcoder::decode(str, nextCodePoint);
113
45.1k
  if (nextCodePoint == lastCodePoint) // failed to decode input?
114
0
  {
115
    // Skip the undecodable run and keep escaping the remaining input
116
    // instead of discarding it; the run collapses to one replacement.
117
0
    for (++nextCodePoint; nextCodePoint != str.end(); ++nextCodePoint)
118
0
    {
119
0
      auto probe = nextCodePoint;
120
0
      Transcoder::decode(str, probe);
121
0
      if (probe != nextCodePoint) // next unit starts a decodable sequence
122
0
        break;
123
0
    }
124
0
    ch = 0xFFFD; // The Unicode replacement character
125
0
  }
126
45.1k
  else if ( (0xD800 <= ch && ch <= 0xDFFF) // UTF-16 surrogate-range
127
45.1k
      || 0xFFFF == ch || 0x10FFFF < ch)
128
0
  {
129
0
    ch = 0xFFFD; // The Unicode replacement character
130
0
  }
131
45.1k
  return ch;
132
45.1k
}
133
134
unsigned int Transcoder::getCodePoint(const std::string& str, std::string::const_iterator& nextCodePoint)
135
0
{
136
0
  return decodeCodePoint<char>(str, nextCodePoint);
137
0
}
138
139
void Transcoder::encode(unsigned int sv, std::string& dst)
140
0
{
141
0
  char tmp[8];
142
0
  size_t bytes = CharsetEncoder::putUTF8CodePoint(sv, tmp);
143
0
  dst.append(tmp, bytes);
144
0
}
145
146
/// Does \c str contain the Unicode replacement character
147
bool Transcoder::hasReplacementCharacter(const std::string& str)
148
0
{
149
0
  return str.npos != str.find("\xEF\xBF\xBD");
150
0
}
151
152
void Transcoder::decode(const std::string& src, LogString& dst)
153
18.6k
{
154
#if LOG4CXX_CHARSET_UTF8 && LOG4CXX_LOGCHAR_IS_UTF8
155
  dst.append(src);
156
#else
157
18.6k
  static CharsetDecoderPtr decoder(CharsetDecoder::getDefaultDecoder());
158
18.6k
  dst.reserve(dst.size() + src.size());
159
18.6k
  std::string::const_iterator iter = src.begin();
160
18.6k
#if !LOG4CXX_CHARSET_EBCDIC
161
162
18.6k
  for (;
163
186k
    iter != src.end() && ((unsigned char) *iter) < 0x80;
164
168k
    iter++)
165
168k
  {
166
168k
    dst.append(1, *iter);
167
168k
  }
168
169
18.6k
#endif
170
171
18.6k
  if (iter != src.end())
172
2.66k
  {
173
2.66k
    size_t offset = iter - src.begin();
174
2.66k
    ByteBuffer buf(const_cast<char*>(src.data() + offset), src.size() - offset);
175
176
121k
    while (buf.remaining() > 0)
177
118k
    {
178
118k
      log4cxx_status_t stat = decoder->decode(buf, dst);
179
180
118k
      if (CharsetDecoder::isError(stat))
181
116k
      {
182
116k
        encode(LOSSCHAR, dst);
183
116k
        buf.increment_position(1);
184
116k
      }
185
118k
    }
186
187
2.66k
    decoder->decode(buf, dst);
188
2.66k
  }
189
190
18.6k
#endif
191
18.6k
}
192
193
#if LOG4CXX_ABI_VERSION <= 15
194
char* Transcoder::encode(const LogString& src, Pool& p)
195
0
{
196
#if LOG4CXX_CHARSET_UTF8 && LOG4CXX_LOGCHAR_IS_UTF8
197
  return p.pstrdup(src);
198
#else
199
0
  std::string tmp;
200
0
  encode(src, tmp);
201
0
  return p.pstrdup(tmp);
202
0
#endif
203
0
}
204
#endif
205
206
207
void Transcoder::encode(const LogString& src, std::string& dst)
208
1.15k
{
209
#if LOG4CXX_CHARSET_UTF8 && LOG4CXX_LOGCHAR_IS_UTF8
210
  dst.append(src);
211
#else
212
1.15k
  static CharsetEncoderPtr encoder(CharsetEncoder::getDefaultEncoder());
213
1.15k
  dst.reserve(dst.size() + src.size());
214
1.15k
  LogString::const_iterator iter = src.begin();
215
1.15k
#if !LOG4CXX_CHARSET_EBCDIC
216
217
1.15k
  for (;
218
45.4k
    iter != src.end() && ((unsigned int) *iter) < 0x80;
219
44.3k
    iter++)
220
44.3k
  {
221
44.3k
    dst.append(1, static_cast<char>(*iter));
222
44.3k
  }
223
224
1.15k
#endif
225
1.15k
  if (iter != src.end())
226
421
  {
227
421
    static const int BUFSIZE = 256;
228
421
    char buf[BUFSIZE];
229
421
    ByteBuffer out(buf, BUFSIZE);
230
231
1.15k
    while (iter != src.end())
232
735
    {
233
735
      log4cxx_status_t stat = encoder->encode(src, iter, out);
234
735
      out.flip();
235
735
      dst.append(out.data(), out.limit());
236
735
      out.clear();
237
238
735
      if (CharsetEncoder::isError(stat))
239
0
      {
240
0
        encode(LOSSCHAR, dst);
241
0
        iter++;
242
0
      }
243
735
    }
244
245
421
    encoder->encode(src, iter, out);
246
421
  }
247
248
1.15k
#endif
249
1.15k
}
250
251
252
template<class String, class Iterator>
253
static unsigned int decodeUTF16(const String& in, Iterator& iter)
254
{
255
  unsigned int ch1 = *iter;
256
257
  //
258
  //   if not surrogate pair
259
  //
260
  if (ch1 < 0xD800 || ch1 > 0xDFFF)
261
  {
262
    //
263
    //  then advance iterator and return wchar_t value
264
    //
265
    if (ch1 != 0xFFFF)
266
    {
267
      iter++;
268
    }
269
270
    return ch1;
271
  }
272
  else if (ch1 < 0xDC00)
273
  {
274
    //
275
    //  started with high-surrogate value
276
    //     if there is an additional wchar_t
277
    Iterator iter2 = iter + 1;
278
279
    if (iter2 != in.end())
280
    {
281
      unsigned int ch2 = *iter2;
282
283
      //
284
      //    if it is a matching low surrogate then
285
      //       advance the iterator and return the scalar value
286
      if (ch2 >= 0xDC00 && ch2 <= 0xDFFF)
287
      {
288
        iter += 2;
289
        return (ch1 - 0xD800) * 0x400 + (ch2 - 0xDC00) + 0x10000;
290
      }
291
    }
292
  }
293
294
  //
295
  //    unrecognized value, do not advance iterator
296
  //
297
  return 0xFFFF;
298
}
299
300
template<class String>
301
static void encodeUTF16(unsigned int sv, String& dst)
302
{
303
  if (sv < 0x10000)
304
  {
305
    dst.append(1, sv);
306
  }
307
  else
308
  {
309
    unsigned char u = (unsigned char) (sv >> 16);
310
    unsigned char w = (unsigned char) (u - 1);
311
    unsigned short hs = (0xD800 + ((w & 0xF) << 6) + ((sv & 0xFFFF) >> 10));
312
    unsigned short ls = (0xDC00 + (sv & 0x3FF));
313
    dst.append(1, hs);
314
    dst.append(1, ls);
315
  }
316
}
317
318
319
320
#if LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR || defined(WIN32) || defined(_WIN32)
321
void Transcoder::decode(const std::wstring& src, LogString& dst)
322
62.7k
{
323
62.7k
#if LOG4CXX_LOGCHAR_IS_WCHAR
324
62.7k
  dst.append(src);
325
#else
326
  std::wstring::const_iterator i = src.begin();
327
328
  while (i != src.end())
329
  {
330
    auto cp = getCodePoint(src, i);
331
    encode(cp, dst);
332
  }
333
334
#endif
335
62.7k
}
336
337
void Transcoder::encode(const LogString& src, std::wstring& dst)
338
0
{
339
0
#if LOG4CXX_LOGCHAR_IS_WCHAR
340
0
  dst.append(src);
341
#else
342
343
  for (LogString::const_iterator i = src.begin(); i != src.end();)
344
  {
345
    unsigned int cp = getCodePoint(src, i);
346
    encode(cp, dst);
347
  }
348
349
#endif
350
0
}
351
352
#if LOG4CXX_ABI_VERSION <= 15
353
wchar_t* Transcoder::wencode(const LogString& src, Pool& p)
354
0
{
355
0
#if LOG4CXX_LOGCHAR_IS_WCHAR
356
0
  const std::wstring& tmp = src;
357
#else
358
  std::wstring tmp;
359
  encode(src, tmp);
360
#endif
361
0
  wchar_t* dst = (wchar_t*) p.palloc((tmp.length() + 1) * sizeof(wchar_t));
362
0
  dst[tmp.length()] = 0;
363
0
  std::memcpy(dst, tmp.data(), tmp.length() * sizeof(wchar_t));
364
0
  return dst;
365
0
}
366
#endif
367
368
unsigned int Transcoder::decode(const std::wstring& in,
369
  std::wstring::const_iterator& iter)
370
45.1k
{
371
45.1k
#if defined(__STDC_ISO_10646__)
372
45.1k
  return *(iter++);
373
#else
374
  return decodeUTF16(in, iter);
375
#endif
376
45.1k
}
377
378
unsigned int Transcoder::getCodePoint(const std::wstring& str, std::wstring::const_iterator& nextCodePoint)
379
45.1k
{
380
45.1k
  return decodeCodePoint<wchar_t>(str, nextCodePoint);
381
45.1k
}
382
383
void Transcoder::encode(unsigned int sv, std::wstring& dst)
384
336k
{
385
336k
#if defined(__STDC_ISO_10646__)
386
336k
  dst.append(1, sv);
387
#else
388
389
  if (sizeof(wchar_t) == 4)
390
  {
391
    dst.append(1, sv);
392
  }
393
  else
394
  {
395
    encodeUTF16(sv, dst);
396
  }
397
398
#endif
399
336k
}
400
401
/// Does \c str contain the Unicode replacement character
402
bool Transcoder::hasReplacementCharacter(const std::wstring& str)
403
0
{
404
0
  return str.npos != str.find(LOSSCHAR);
405
0
}
406
#endif
407
408
409
410
#if LOG4CXX_UNICHAR_API || LOG4CXX_LOGCHAR_IS_UNICHAR
411
void Transcoder::decode(const std::basic_string<UniChar>& src, LogString& dst)
412
{
413
#if LOG4CXX_LOGCHAR_IS_UNICHAR
414
  dst.append(src);
415
#else
416
417
  for (std::basic_string<UniChar>::const_iterator i = src.begin();
418
    i != src.end();)
419
  {
420
    std::basic_string<UniChar>::const_iterator start = i;
421
    unsigned int cp = decode(src, i);
422
423
    if (cp != 0xFFFF)
424
    {
425
      encode(cp, dst);
426
    }
427
    else
428
    {
429
      encode(LOSSCHAR, dst);
430
      if (i == start)
431
      {
432
        i++;
433
      }
434
    }
435
  }
436
437
#endif
438
}
439
440
void Transcoder::encode(const LogString& src, std::basic_string<UniChar>& dst)
441
{
442
#if LOG4CXX_LOGCHAR_IS_UNICHAR
443
  dst.append(src);
444
#else
445
446
  for (LogString::const_iterator i = src.begin();
447
    i != src.end();)
448
  {
449
    LogString::const_iterator start = i;
450
    unsigned int cp = decode(src, i);
451
452
    if (cp != 0xFFFF)
453
    {
454
      encode(cp, dst);
455
    }
456
    else
457
    {
458
      encode(LOSSCHAR, dst);
459
      if (i == start)
460
      {
461
        i++;
462
      }
463
    }
464
  }
465
466
#endif
467
}
468
469
unsigned int Transcoder::decode(const std::basic_string<UniChar>& in,
470
  std::basic_string<UniChar>::const_iterator& iter)
471
{
472
  return decodeUTF16(in, iter);
473
}
474
475
unsigned int Transcoder::getCodePoint(const std::basic_string<UniChar>& str, std::basic_string<UniChar>::const_iterator& nextCodePoint)
476
{
477
  return decodeCodePoint<UniChar>(str, nextCodePoint);
478
}
479
480
void Transcoder::encode(unsigned int sv, std::basic_string<UniChar>& dst)
481
{
482
  encodeUTF16(sv, dst);
483
}
484
485
/// Does \c str contain the Unicode replacement character
486
bool Transcoder::hasReplacementCharacter(const std::basic_string<UniChar>& str)
487
{
488
  return str.npos != str.find(LOSSCHAR);
489
}
490
#endif
491
492
#if LOG4CXX_CFSTRING_API
493
void Transcoder::decode(const CFStringRef& src, LogString& dst)
494
{
495
  auto length = CFStringGetLength(src);
496
#if defined(_DEBUG)
497
  if (LogLog::isDebugEnabled())
498
  {
499
    LogString msg(LOG4CXX_STR("Transcoder::decodeCFString"));
500
    msg += LOG4CXX_STR(" length ");
501
    StringHelper::toString((size_t)length, msg);
502
    LogLog::debug(msg);
503
  }
504
#endif
505
506
  if (length > 0)
507
  {
508
    std::vector<unsigned short> tmp(length);
509
    CFStringGetCharacters(src, CFRangeMake(0, length), &tmp[0]);
510
    for (auto i = tmp.begin(); i != tmp.end(); )
511
    {
512
      auto start = i;
513
      unsigned int cp = decodeUTF16(tmp, i);
514
      if (cp != 0xFFFF)
515
      {
516
        encode(cp, dst);
517
      }
518
      else
519
      {
520
        encode(LOSSCHAR, dst);
521
        if (i == start)
522
        {
523
          i++;
524
        }
525
      }
526
    }
527
  }
528
}
529
530
CFStringRef Transcoder::encode(const LogString& src)
531
{
532
  std::basic_string<unsigned short> tmp;
533
  for (auto ch : src)
534
    encodeUTF16(ch, tmp);
535
  return CFStringCreateWithCharacters(kCFAllocatorDefault, tmp.data(), tmp.size());
536
}
537
#endif // #if LOG4CXX_CFSTRING_API
538
539
540
logchar Transcoder::decode(char val)
541
0
{
542
#if LOG4CXX_CHARSET_EBCDIC
543
  LogString dst;
544
  Transcoder::decode(std::string(1, val), dst);
545
  return dst[0];
546
#else
547
0
  return val;
548
0
#endif
549
0
}
550
551
LogString Transcoder::decode(const char* val)
552
2
{
553
#if LOG4CXX_LOGCHAR_IS_UTF8 && !LOG4CXX_CHARSET_EBCDIC
554
  return val;
555
#else
556
2
  LogString dst;
557
2
  Transcoder::decode(val, dst);
558
2
  return dst;
559
2
#endif
560
2
}
561
562
563
std::string Transcoder::encodeCharsetName(const LogString& val)
564
0
{
565
0
  char asciiTable[] = { ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
566
0
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
567
0
      '@', 'A', 'B', 'C', 'D', 'E', 'F',  'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
568
0
      'P', 'Q', 'R', 'S', 'T', 'U', 'V',  'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
569
0
      '`', 'a', 'b', 'c', 'd', 'e', 'f',  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
570
0
      'p', 'q', 'r', 's', 't', 'u', 'v',  'w', 'x', 'y', 'z', '{', '|', '}', '~'
571
0
    };
572
0
  std::string out;
573
574
0
  for (auto& item : val)
575
0
  {
576
0
    if (item >= 0x20 && item < 0x7F)
577
0
    {
578
0
      out.append(1, asciiTable[item - 0x20]);
579
0
    }
580
0
    else
581
0
    {
582
0
      out.append(1, '?');
583
0
    }
584
0
  }
585
586
0
  return out;
587
0
}