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/charsetencoder.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
#include <log4cxx/logstring.h>
18
#include <log4cxx/helpers/charsetencoder.h>
19
#include <log4cxx/private/bytebuffer_priv.h>
20
#include <log4cxx/helpers/exception.h>
21
#include <apr_xlate.h>
22
#include <log4cxx/helpers/stringhelper.h>
23
#include <log4cxx/helpers/transcoder.h>
24
#include <algorithm>
25
26
#if !defined(LOG4CXX)
27
  #define LOG4CXX 1
28
#endif
29
30
#include <log4cxx/private/log4cxx_private.h>
31
#include <apr_portable.h>
32
#include <mutex>
33
34
#ifdef LOG4CXX_HAS_WCSTOMBS
35
  #include <stdlib.h>
36
#endif
37
38
#if 15 < LOG4CXX_ABI_VERSION
39
#define LOG4CXX_16_VIRTUAL_SPECIFIER override
40
#else
41
#define LOG4CXX_16_VIRTUAL_SPECIFIER
42
#endif
43
44
using namespace LOG4CXX_NS;
45
using namespace LOG4CXX_NS::helpers;
46
47
IMPLEMENT_LOG4CXX_OBJECT(CharsetEncoder)
48
49
namespace LOG4CXX_NS
50
{
51
52
namespace helpers
53
{
54
55
#if APR_HAS_XLATE
56
/**
57
* A character encoder implemented using apr_xlate.
58
*/
59
class APRCharsetEncoder : public CharsetEncoder
60
{
61
  public:
62
0
    APRCharsetEncoder(const LogString& topage) : pool()
63
0
    {
64
#if LOG4CXX_LOGCHAR_IS_WCHAR
65
      const char* frompage = "WCHAR_T";
66
#endif
67
0
#if LOG4CXX_LOGCHAR_IS_UTF8
68
0
      const char* frompage = "UTF-8";
69
0
#endif
70
#if LOG4CXX_LOGCHAR_IS_UNICHAR
71
      const char* frompage = "UTF-16";
72
#endif
73
0
      std::string tpage(Transcoder::encodeCharsetName(topage));
74
0
      apr_status_t stat = apr_xlate_open(&convset,
75
0
          tpage.c_str(),
76
0
          frompage,
77
0
          pool.getAPRPool());
78
79
0
      if (stat != APR_SUCCESS)
80
0
      {
81
0
        throw IllegalArgumentException(topage);
82
0
      }
83
0
    }
84
85
    virtual ~APRCharsetEncoder()
86
0
    {
87
0
    }
88
89
    virtual log4cxx_status_t encode(const LogString& in,
90
      LogString::const_iterator& iter,
91
      ByteBuffer& out_param) override
92
0
    {
93
0
      auto& out = out_param.impl();
94
0
      apr_status_t stat;
95
0
      size_t outbytes_left = out.remaining();
96
0
      size_t initial_outbytes_left = outbytes_left;
97
0
      size_t position = out.position();
98
99
0
      if (iter == in.end())
100
0
      {
101
0
        std::lock_guard<std::mutex> lock(mutex);
102
0
        stat = apr_xlate_conv_buffer(convset, NULL, NULL,
103
0
            out.data() + position, &outbytes_left);
104
0
      }
105
0
      else
106
0
      {
107
0
        LogString::size_type inOffset = (iter - in.begin());
108
0
        apr_size_t inbytes_left =
109
0
          (in.size() - inOffset) * sizeof(LogString::value_type);
110
0
        apr_size_t initial_inbytes_left = inbytes_left;
111
0
        {
112
0
          std::lock_guard<std::mutex> lock(mutex);
113
0
          stat = apr_xlate_conv_buffer(convset,
114
0
              (const char*) (in.data() + inOffset),
115
0
              &inbytes_left,
116
0
              out.data() + position,
117
0
              &outbytes_left);
118
0
        }
119
0
        iter += ((initial_inbytes_left - inbytes_left) / sizeof(LogString::value_type));
120
0
      }
121
122
0
      out.increment_position((initial_outbytes_left - outbytes_left));
123
0
      return stat;
124
0
    }
125
126
    /**
127
     * Add onto \c out an encoded equivalent of \c codePoint.
128
     */
129
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
130
0
    {
131
0
      apr_status_t result = APR_SUCCESS;
132
0
      if (codePoint <= 0x10FFFF && 4 <= out.remaining())
133
0
        out.increment_position(putUTF8CodePoint(codePoint, out.current()));
134
0
      else
135
0
        result = APR_BADARG;
136
0
      return result;
137
0
    }
138
139
  private:
140
    APRCharsetEncoder(const APRCharsetEncoder&);
141
    APRCharsetEncoder& operator=(const APRCharsetEncoder&);
142
    Pool pool;
143
    std::mutex mutex;
144
    apr_xlate_t* convset;
145
};
146
#endif
147
148
#if LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_WCSTOMBS
149
/**
150
 *  A character encoder implemented using wcstombs.
151
*/
152
class WcstombsCharsetEncoder : public CharsetEncoder
153
{
154
  public:
155
    WcstombsCharsetEncoder()
156
    {
157
    }
158
159
    /**
160
     *   Converts a wchar_t to the default external multibyte encoding.
161
     */
162
    log4cxx_status_t encode(const LogString& in,
163
      LogString::const_iterator& iter,
164
      ByteBuffer& out_param) override
165
    {
166
      auto& out = out_param.impl();
167
      log4cxx_status_t stat = APR_SUCCESS;
168
169
      if (iter != in.end())
170
      {
171
        size_t outbytes_left = out.remaining();
172
        size_t position = out.position();
173
        std::wstring::size_type inOffset = (iter - in.begin());
174
        enum { BUFSIZE = 256 };
175
        wchar_t buf[BUFSIZE];
176
        size_t chunkSize = BUFSIZE - 1;
177
178
        if (chunkSize * MB_LEN_MAX > outbytes_left)
179
        {
180
          chunkSize = outbytes_left / MB_LEN_MAX;
181
        }
182
183
        if (chunkSize > in.length() - inOffset)
184
        {
185
          chunkSize = in.length() - inOffset;
186
        }
187
188
        memset(buf, 0, BUFSIZE * sizeof(wchar_t));
189
        memcpy(buf,
190
          in.data() + inOffset,
191
          chunkSize * sizeof(wchar_t));
192
        size_t converted = wcstombs(out.data() + position, buf, outbytes_left);
193
194
        if (converted == (size_t) -1)
195
        {
196
          stat = APR_BADARG;
197
198
          //
199
          //   if unconvertable character was encountered
200
          //       repeatedly halve source to get fragment that
201
          //       can be converted
202
          for (chunkSize /= 2;
203
            chunkSize > 0;
204
            chunkSize /= 2)
205
          {
206
            buf[chunkSize] = 0;
207
            converted = wcstombs(out.data() + position, buf, outbytes_left);
208
209
            if (converted != (size_t) -1)
210
            {
211
              iter += chunkSize;
212
              out.increment_position(converted);
213
              break;
214
            }
215
          }
216
        }
217
        else
218
        {
219
          iter += chunkSize;
220
          out.increment_position(converted);
221
        }
222
      }
223
224
      return stat;
225
    }
226
227
    /**
228
     * Add onto \c out an encoded equivalent of \c codePoint.
229
     */
230
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
231
    {
232
      apr_status_t result = APR_SUCCESS;
233
      if (codePoint <= 0x10FFFF && MB_LEN_MAX <= out.remaining())
234
      {
235
        auto ch = static_cast<wchar_t>(codePoint);
236
        auto converted = wcstombs(out.current(), &ch, 1);
237
        if (static_cast<std::size_t>(-1) == converted)
238
          result = APR_BADARG;
239
        else
240
          out.increment_position(converted);
241
      }
242
      else
243
        result = APR_BADARG;
244
      return result;
245
    }
246
247
  private:
248
    WcstombsCharsetEncoder(const WcstombsCharsetEncoder&);
249
    WcstombsCharsetEncoder& operator=(const WcstombsCharsetEncoder&);
250
};
251
#endif
252
253
254
/**
255
*   Encodes a LogString to US-ASCII.
256
*/
257
class USASCIICharsetEncoder : public CharsetEncoder
258
{
259
  public:
260
    USASCIICharsetEncoder()
261
288
    {
262
288
    }
263
264
    virtual log4cxx_status_t encode(const LogString& in,
265
      LogString::const_iterator& iter,
266
      ByteBuffer& out_param) override
267
306k
    {
268
306k
      auto& out = out_param.impl();
269
306k
      log4cxx_status_t stat = APR_SUCCESS;
270
271
306k
      if (iter != in.end())
272
306k
      {
273
1.04M
        while (out.remaining() > 0 && iter != in.end())
274
1.03M
        {
275
1.03M
          LogString::const_iterator prev(iter);
276
1.03M
          unsigned int sv = Transcoder::decode(in, iter);
277
278
1.03M
          if (sv <= 0x7F)
279
734k
          {
280
734k
            out.put((char) sv);
281
734k
          }
282
302k
          else
283
302k
          {
284
302k
            iter = prev;
285
302k
            stat = APR_BADARG;
286
302k
            break;
287
302k
          }
288
1.03M
        }
289
306k
      }
290
291
306k
      return stat;
292
306k
    }
293
294
    /**
295
     * Add onto \c out an encoded equivalent of \c codePoint.
296
     */
297
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
298
0
    {
299
0
      apr_status_t result = APR_SUCCESS;
300
0
      if (out.remaining() < 1)
301
0
        result = APR_BADARG;
302
0
      else if (codePoint <= 0x7F)
303
0
        out.put(static_cast<char>(codePoint));
304
0
      else if (Transcoder::LOSSCHAR == codePoint)
305
0
        out.put('?');
306
0
      else
307
0
        result = APR_BADARG;
308
0
      return result;
309
0
    }
310
311
  private:
312
    USASCIICharsetEncoder(const USASCIICharsetEncoder&);
313
    USASCIICharsetEncoder& operator=(const USASCIICharsetEncoder&);
314
};
315
316
/**
317
*   Converts a LogString to ISO-8859-1.
318
*/
319
class ISOLatinCharsetEncoder : public CharsetEncoder
320
{
321
  public:
322
    ISOLatinCharsetEncoder()
323
209
    {
324
209
    }
325
326
    virtual log4cxx_status_t encode(const LogString& in,
327
      LogString::const_iterator& iter,
328
      ByteBuffer& out_param) override
329
1.02M
    {
330
1.02M
      auto& out = out_param.impl();
331
1.02M
      log4cxx_status_t stat = APR_SUCCESS;
332
333
1.62M
      while (out.remaining() > 0 && iter != in.end())
334
1.62M
      {
335
1.62M
        LogString::const_iterator prev(iter);
336
1.62M
        unsigned int sv = Transcoder::decode(in, iter);
337
1.62M
        if (sv <= 0xFF)
338
595k
          out.put(static_cast<char>(sv));
339
1.02M
        else
340
1.02M
        {
341
1.02M
          iter = prev;
342
1.02M
          stat = APR_BADARG;
343
1.02M
          break;
344
1.02M
        }
345
1.62M
      }
346
1.02M
      return stat;
347
1.02M
    }
348
349
    /**
350
     * Add onto \c out an encoded equivalent of \c codePoint.
351
     */
352
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
353
0
    {
354
0
      apr_status_t result = APR_SUCCESS;
355
0
      if (out.remaining() < 1)
356
0
        result = APR_BADARG;
357
0
      else if (codePoint <= 0xFF)
358
0
        out.put(static_cast<char>(codePoint));
359
0
      else if (Transcoder::LOSSCHAR == codePoint)
360
0
        out.put('?');
361
0
      else
362
0
        result = APR_BADARG;
363
0
      return result;
364
0
    }
365
366
  private:
367
    ISOLatinCharsetEncoder(const ISOLatinCharsetEncoder&);
368
    ISOLatinCharsetEncoder& operator=(const ISOLatinCharsetEncoder&);
369
};
370
371
/**
372
*   Encodes a LogString to a byte array when the encodings are identical.
373
*/
374
class TrivialCharsetEncoder : public CharsetEncoder
375
{
376
  public:
377
    TrivialCharsetEncoder()
378
0
    {
379
0
    }
380
381
382
    virtual log4cxx_status_t encode(const LogString& in,
383
      LogString::const_iterator& iter,
384
      ByteBuffer& out_param) override
385
0
    {
386
0
      auto& out = out_param.impl();
387
0
      if (iter != in.end())
388
0
      {
389
0
        size_t requested = in.length() - (iter - in.begin());
390
391
0
        if (requested > out.remaining() / sizeof(logchar))
392
0
        {
393
0
          requested = out.remaining() / sizeof(logchar);
394
0
        }
395
396
0
        memcpy(out.current(),
397
0
          (const char*) in.data() + (iter - in.begin()),
398
0
          requested * sizeof(logchar));
399
0
        iter += requested;
400
0
        out.increment_position(requested * sizeof(logchar));
401
0
      }
402
403
0
      return APR_SUCCESS;
404
0
    }
405
406
    /**
407
     * Add onto \c out an encoded equivalent of \c codePoint.
408
     */
409
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
410
0
    {
411
0
      apr_status_t result = APR_SUCCESS;
412
0
      if (out.remaining() < 1)
413
0
        result = APR_BADARG;
414
0
      else if (codePoint <= 0xFF)
415
0
        out.put(static_cast<char>(codePoint));
416
0
      else if (Transcoder::LOSSCHAR == codePoint)
417
0
        out.put('?');
418
0
      else
419
0
        result = APR_BADARG;
420
0
      return result;
421
0
    }
422
423
  private:
424
    TrivialCharsetEncoder(const TrivialCharsetEncoder&);
425
    TrivialCharsetEncoder& operator=(const TrivialCharsetEncoder&);
426
};
427
428
/**
429
 *  Converts a LogString to UTF-8.
430
 */
431
class UTF8CharsetEncoder : public CharsetEncoder
432
{
433
  public:
434
    UTF8CharsetEncoder()
435
297
    {
436
297
    }
437
438
    virtual log4cxx_status_t encode(const LogString& in,
439
      LogString::const_iterator& iter,
440
      ByteBuffer& out_param) override
441
11.1k
    {
442
11.1k
      auto& out = out_param.impl();
443
952k
      while (iter != in.end() && 4 <= out.remaining())
444
941k
      {
445
941k
        auto sv = Transcoder::getCodePoint(in, iter);
446
941k
        out.increment_position(putUTF8CodePoint(sv, out.current()));
447
941k
      }
448
449
11.1k
      return APR_SUCCESS;
450
11.1k
    }
451
452
    /**
453
     * Add onto \c out an encoded equivalent of \c codePoint.
454
     */
455
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
456
0
    {
457
0
      apr_status_t result = APR_SUCCESS;
458
0
      if (codePoint <= 0x10FFFF && 4 <= out.remaining())
459
0
        out.increment_position(putUTF8CodePoint(codePoint, out.current()));
460
0
      else
461
0
        result = APR_BADARG;
462
0
      return result;
463
0
    }
464
465
  private:
466
    UTF8CharsetEncoder(const UTF8CharsetEncoder&);
467
    UTF8CharsetEncoder& operator=(const UTF8CharsetEncoder&);
468
};
469
470
/**
471
 *   Encodes a LogString to UTF16-BE.
472
 */
473
class UTF16BECharsetEncoder : public CharsetEncoder
474
{
475
  public:
476
    UTF16BECharsetEncoder()
477
229
    {
478
229
    }
479
480
    virtual log4cxx_status_t encode(const LogString& in,
481
      LogString::const_iterator& iter,
482
      ByteBuffer& out_param) override
483
13.7k
    {
484
13.7k
      auto& out = out_param.impl();
485
856k
      while (iter != in.end() && 4 <= out.remaining())
486
842k
      {
487
842k
        auto sv = Transcoder::getCodePoint(in, iter);
488
842k
        out.increment_position(putUTF16BECodePoint(sv, out.current()));
489
842k
      }
490
491
13.7k
      return APR_SUCCESS;
492
13.7k
    }
493
494
    /**
495
     * Add onto \c out an encoded equivalent of \c codePoint.
496
     */
497
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
498
0
    {
499
0
      apr_status_t result = APR_SUCCESS;
500
0
      if (codePoint <= 0x10FFFF && 4 <= out.remaining())
501
0
        Transcoder::encodeUTF16BE(codePoint, out);
502
0
      else
503
0
        result = APR_BADARG;
504
0
      return result;
505
0
    }
506
507
  private:
508
    UTF16BECharsetEncoder(const UTF16BECharsetEncoder&);
509
    UTF16BECharsetEncoder& operator=(const UTF16BECharsetEncoder&);
510
};
511
512
/**
513
 *   Encodes a LogString to UTF16-LE.
514
 */
515
class UTF16LECharsetEncoder : public CharsetEncoder
516
{
517
  public:
518
    UTF16LECharsetEncoder()
519
247
    {
520
247
    }
521
522
523
    virtual log4cxx_status_t encode(const LogString& in,
524
      LogString::const_iterator& iter,
525
      ByteBuffer& out_param) override
526
16.1k
    {
527
16.1k
      auto& out = out_param.impl();
528
1.00M
      while (iter != in.end() && 4 <= out.remaining())
529
988k
      {
530
988k
        auto sv = Transcoder::getCodePoint(in, iter);
531
988k
        out.increment_position(putUTF16LECodePoint(sv, out.current()));
532
988k
      }
533
534
16.1k
      return APR_SUCCESS;
535
16.1k
    }
536
537
    /**
538
     * Add onto \c out an encoded equivalent of \c codePoint.
539
     */
540
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
541
0
    {
542
0
      apr_status_t result = APR_SUCCESS;
543
0
      if (codePoint <= 0x10FFFF && 4 <= out.remaining())
544
0
        out.increment_position(putUTF16LECodePoint(codePoint, out.current()));
545
0
      else
546
0
        result = APR_BADARG;
547
0
      return result;
548
0
    }
549
  private:
550
    UTF16LECharsetEncoder(const UTF16LECharsetEncoder&);
551
    UTF16LECharsetEncoder& operator=(const UTF16LECharsetEncoder&);
552
};
553
554
/**
555
 *    Charset encoder that uses current locale settings.
556
 */
557
class LocaleCharsetEncoder : public CharsetEncoder
558
{
559
  public:
560
0
    LocaleCharsetEncoder() : state()
561
0
    {
562
0
    }
563
    log4cxx_status_t encode
564
      ( const LogString&           in
565
      , LogString::const_iterator& nextCodePoint
566
      , ByteBuffer&                out_param
567
      ) override
568
0
    {
569
0
      auto& out = out_param.impl();
570
0
      log4cxx_status_t result = APR_SUCCESS;
571
0
#if !LOG4CXX_CHARSET_EBCDIC
572
0
      char* current = out.current();
573
0
      size_t availableByteCount = out.remaining();
574
0
      size_t byteCount = 0;
575
0
      if (std::mbsinit(&this->state)) // ByteBuffer not partially encoded?
576
0
      {
577
        // Copy single byte characters
578
0
        for (;
579
0
          nextCodePoint != in.end() && byteCount < availableByteCount && static_cast<unsigned int>(*nextCodePoint) < 0x80;
580
0
          ++nextCodePoint, ++byteCount, ++current)
581
0
        {
582
0
          *current = static_cast<char>(*nextCodePoint);
583
0
        }
584
0
      }
585
0
#endif
586
      // Encode characters that may require multiple bytes
587
0
      while (nextCodePoint != in.end() && byteCount < availableByteCount && MB_CUR_MAX <= (availableByteCount - byteCount))
588
0
      {
589
0
        auto ch = Transcoder::getCodePoint(in, nextCodePoint);
590
0
        auto n = std::wcrtomb(current, ch, &this->state);
591
0
        if (static_cast<std::size_t>(-1) == n) // not a valid wide character?
592
0
        {
593
0
          result = APR_BADARG;
594
0
          break;
595
0
        }
596
0
        byteCount += n;
597
0
        current += n;
598
0
      }
599
0
      out.increment_position(byteCount);
600
0
      return result;
601
0
    }
602
603
    /**
604
     * Add onto \c out an encoded equivalent of \c codePoint.
605
     */
606
    log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) LOG4CXX_16_VIRTUAL_SPECIFIER
607
0
    {
608
0
      apr_status_t result = APR_SUCCESS;
609
0
      if (MB_CUR_MAX <= out.remaining())
610
0
      {
611
0
        auto n = std::wcrtomb(out.current(), codePoint, &this->state);
612
0
        if (static_cast<std::size_t>(-1) == n) // not a valid wide character?
613
0
          result = APR_BADARG;
614
0
        else
615
0
          out.increment_position(n);
616
0
      }
617
0
      else
618
0
        result = APR_BADARG;
619
0
      return result;
620
0
    }
621
622
  private:
623
    std::mbstate_t state;
624
};
625
626
627
} // namespace helpers
628
629
}  //namespace log4cxx
630
631
632
633
CharsetEncoder::CharsetEncoder()
634
1.27k
{
635
1.27k
}
636
637
CharsetEncoder::~CharsetEncoder()
638
1.27k
{
639
1.27k
}
640
641
CharsetEncoderPtr CharsetEncoder::getDefaultEncoder()
642
0
{
643
0
  static WideLife<CharsetEncoderPtr> encoder(createDefaultEncoder());
644
645
  //
646
  //  if invoked after static variable destruction
647
  //     (if logging is called in the destructor of a static object)
648
  //     then create a new decoder.
649
  //
650
0
  if (encoder.value() == 0)
651
0
  {
652
0
    return CharsetEncoderPtr( createDefaultEncoder() );
653
0
  }
654
655
0
  return encoder;
656
0
}
657
658
CharsetEncoder* CharsetEncoder::createDefaultEncoder()
659
0
{
660
0
#if LOG4CXX_CHARSET_UTF8
661
0
#if LOG4CXX_LOGCHAR_IS_UTF8
662
0
  return new TrivialCharsetEncoder();
663
#else
664
  return new UTF8CharsetEncoder();
665
#endif
666
#elif LOG4CXX_CHARSET_ISO88591
667
  return new ISOLatinCharsetEncoder();
668
#elif LOG4CXX_CHARSET_USASCII
669
  return new USASCIICharsetEncoder();
670
#elif LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_WCSTOMBS
671
  return new WcstombsCharsetEncoder();
672
#else
673
  return new LocaleCharsetEncoder();
674
#endif
675
0
}
676
677
678
CharsetEncoderPtr CharsetEncoder::getUTF8Encoder()
679
0
{
680
0
  return std::make_shared<UTF8CharsetEncoder>();
681
0
}
682
683
684
685
CharsetEncoderPtr CharsetEncoder::getEncoder(const LogString& charset)
686
1.27k
{
687
1.27k
  if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-8"), LOG4CXX_STR("utf-8"))
688
973
    || StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP65001"), LOG4CXX_STR("cp65001")))
689
297
  {
690
297
    return std::make_shared<UTF8CharsetEncoder>();
691
297
  }
692
973
  else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("C"), LOG4CXX_STR("c")) ||
693
973
    charset == LOG4CXX_STR("646") ||
694
973
    StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("US-ASCII"), LOG4CXX_STR("us-ascii")) ||
695
685
    StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO646-US"), LOG4CXX_STR("iso646-US")) ||
696
685
    StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ANSI_X3.4-1968"), LOG4CXX_STR("ansi_x3.4-1968")) ||
697
685
    StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP20127"), LOG4CXX_STR("cp20127")))
698
288
  {
699
288
    return std::make_shared<USASCIICharsetEncoder>();
700
288
  }
701
685
  else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO-8859-1"), LOG4CXX_STR("iso-8859-1")) ||
702
476
    StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO-LATIN-1"), LOG4CXX_STR("iso-latin-1")) ||
703
476
    StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP1252"), LOG4CXX_STR("cp1252")))
704
209
  {
705
209
    return std::make_shared<ISOLatinCharsetEncoder>();
706
209
  }
707
476
  else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-16BE"), LOG4CXX_STR("utf-16be"))
708
247
    || StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-16"), LOG4CXX_STR("utf-16"))
709
247
    || StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP1200"), LOG4CXX_STR("cp1200")))
710
229
  {
711
229
    return std::make_shared<UTF16BECharsetEncoder>();
712
229
  }
713
247
  else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-16LE"), LOG4CXX_STR("utf-16le")))
714
247
  {
715
247
    return std::make_shared<UTF16LECharsetEncoder>();
716
247
  }
717
0
  else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("LOCALE"), LOG4CXX_STR("locale")))
718
0
  {
719
0
    return std::make_shared<LocaleCharsetEncoder>();
720
0
  }
721
722
0
#if APR_HAS_XLATE
723
0
  return std::make_shared<APRCharsetEncoder>(charset);
724
#else
725
  throw IllegalArgumentException(charset);
726
#endif
727
1.27k
}
728
729
730
void CharsetEncoder::reset()
731
0
{
732
0
}
733
734
#if LOG4CXX_ABI_VERSION <= 15
735
void CharsetEncoder::flush(ByteBuffer& /* out */ )
736
1.27k
{
737
1.27k
}
738
#endif
739
740
void CharsetEncoder::encode(CharsetEncoderPtr& enc,
741
  const LogString& src,
742
  LogString::const_iterator& iter,
743
  ByteBuffer& dst)
744
0
{
745
0
  log4cxx_status_t stat = enc->encode(src, iter, dst);
746
747
0
  if (stat != APR_SUCCESS && iter != src.end())
748
0
  {
749
#if LOG4CXX_LOGCHAR_IS_WCHAR || LOG4CXX_LOGCHAR_IS_UNICHAR
750
    iter++;
751
#elif LOG4CXX_LOGCHAR_IS_UTF8
752
753
    //  advance past this character and all continuation characters
754
0
    do
755
0
    {
756
0
      ++iter;
757
0
    }
758
0
    while (iter != src.end() &&
759
0
         (*iter & 0xC0) == 0x80);
760
761
#else
762
#error logchar is unrecognized
763
#endif
764
#if 15 < LOG4CXX_ABI_VERSION
765
    enc->encode(Transcoder::LOSSCHAR, dst);
766
#else // LOG4CXX_ABI_VERSION <= 15
767
0
    if (auto p = dynamic_cast<TrivialCharsetEncoder*>(enc.get()))
768
0
      p->encode(Transcoder::LOSSCHAR, dst);
769
0
    else if (auto p = dynamic_cast<UTF8CharsetEncoder*>(enc.get()))
770
0
      p->encode(Transcoder::LOSSCHAR, dst);
771
0
    else if (auto p = dynamic_cast<LocaleCharsetEncoder*>(enc.get()))
772
0
      p->encode(Transcoder::LOSSCHAR, dst);
773
0
    else if (auto p = dynamic_cast<USASCIICharsetEncoder*>(enc.get()))
774
0
      p->encode(Transcoder::LOSSCHAR, dst);
775
0
    else if (auto p = dynamic_cast<ISOLatinCharsetEncoder*>(enc.get()))
776
0
      p->encode(Transcoder::LOSSCHAR, dst);
777
0
    else if (auto p = dynamic_cast<UTF16BECharsetEncoder*>(enc.get()))
778
0
      p->encode(Transcoder::LOSSCHAR, dst);
779
0
    else if (auto p = dynamic_cast<UTF16LECharsetEncoder*>(enc.get()))
780
0
      p->encode(Transcoder::LOSSCHAR, dst);
781
#if LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_WCSTOMBS
782
    else if (auto p = dynamic_cast<WcstombsCharsetEncoder*>(enc.get()))
783
      p->encode(Transcoder::LOSSCHAR, dst);
784
#endif //  LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_WCSTOMBS
785
0
#if APR_HAS_XLATE
786
0
    else if (auto p = dynamic_cast<APRCharsetEncoder*>(enc.get()))
787
0
      p->encode(Transcoder::LOSSCHAR, dst);
788
0
#endif //  APR_HAS_XLATE
789
0
#endif // LOG4CXX_ABI_VERSION <= 15
790
0
  }
791
0
}
792
793
bool CharsetEncoder::isTriviallyCopyable(const LogString& src, const CharsetEncoderPtr& enc)
794
0
{
795
0
  bool result;
796
0
#if !LOG4CXX_CHARSET_EBCDIC
797
0
  if (dynamic_cast<LocaleCharsetEncoder*>(enc.get()))
798
0
  {
799
0
    result = src.end() == std::find_if(src.begin(), src.end()
800
0
      , [](const logchar& ch) -> bool { return 0x80 <= (unsigned int)ch; });
801
0
  }
802
0
  else
803
0
#endif
804
0
    result = !!dynamic_cast<TrivialCharsetEncoder*>(enc.get());
805
0
  return result;
806
0
}
807
808
size_t CharsetEncoder::putUTF8CodePoint(unsigned int ch, char* dst)
809
17.0M
{
810
17.0M
  if (ch < 0x80)
811
12.3M
  {
812
12.3M
    dst[0] = (char) ch;
813
12.3M
    return 1;
814
12.3M
  }
815
4.64M
  else if (ch < 0x800)
816
681k
  {
817
681k
    dst[0] = (char) (0xC0 + (ch >> 6));
818
681k
    dst[1] = (char) (0x80 + (ch & 0x3F));
819
681k
    return 2;
820
681k
  }
821
3.96M
  else if (ch < 0x10000)
822
3.78M
  {
823
3.78M
    dst[0] = (char) (0xE0 + (ch >> 12));
824
3.78M
    dst[1] = (char) (0x80 + ((ch >> 6) & 0x3F));
825
3.78M
    dst[2] = (char) (0x80 + (ch & 0x3F));
826
3.78M
    return 3;
827
3.78M
  }
828
180k
  else if (ch <= 0x10FFFF)
829
180k
  {
830
180k
    dst[0] = (char) (0xF0 + (ch >> 18));
831
180k
    dst[1] = (char) (0x80 + ((ch >> 12) & 0x3F));
832
180k
    dst[2] = (char) (0x80 + ((ch >> 6) & 0x3F));
833
180k
    dst[3] = (char) (0x80 + (ch & 0x3F));
834
180k
    return 4;
835
180k
  }
836
0
  else
837
0
  {
838
    //
839
    //  output UTF-8 encoding of 0xFFFF
840
    //
841
0
    dst[0] = (char) 0xEF;
842
0
    dst[1] = (char) 0xBF;
843
0
    dst[2] = (char) 0xBF;
844
0
    return 3;
845
0
  }
846
17.0M
}
847
848
size_t CharsetEncoder::putUTF16BECodePoint(unsigned int ch, char* dst)
849
4.37M
{
850
4.37M
  if (ch <= 0xFFFF)
851
4.31M
  {
852
4.31M
    dst[0] = (char) (ch >> 8);
853
4.31M
    dst[1] = (char) (ch & 0xFF);
854
4.31M
    return 2;
855
4.31M
  }
856
857
65.6k
  if (ch <= 0x10FFFF)
858
65.6k
  {
859
65.6k
    unsigned char w = (unsigned char) ((ch >> 16) - 1);
860
65.6k
    dst[0] = (char) (0xD8 + (w >> 2));
861
65.6k
    dst[1] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
862
65.6k
    dst[2] = (char) (0xDC + ((ch >> 8) & 0x03));
863
65.6k
    dst[3] = (char) (ch & 0xFF);
864
65.6k
    return 4;
865
65.6k
  }
866
867
0
  dst[0] = dst[1] = (char) 0xFF;
868
0
  return 2;
869
65.6k
}
870
871
size_t CharsetEncoder::putUTF16LECodePoint(unsigned int ch, char* dst)
872
4.52M
{
873
4.52M
  if (ch <= 0xFFFF)
874
4.45M
  {
875
4.45M
    dst[1] = (char) (ch >> 8);
876
4.45M
    dst[0] = (char) (ch & 0xFF);
877
4.45M
    return 2;
878
4.45M
  }
879
880
68.4k
  if (ch <= 0x10FFFF)
881
68.4k
  {
882
68.4k
    unsigned char w = (unsigned char) ((ch >> 16) - 1);
883
68.4k
    dst[1] = (char) (0xD8 + (w >> 2));
884
68.4k
    dst[0] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
885
68.4k
    dst[3] = (char) (0xDC + ((ch >> 8) & 0x03));
886
68.4k
    dst[2] = (char) (ch & 0xFF);
887
68.4k
    return 4;
888
68.4k
  }
889
890
0
  dst[0] = dst[1] = (char) 0xFF;
891
0
  return 2;
892
68.4k
}