| /* | |
| * Licensed to the Apache Software Foundation (ASF) under one or more | |
| * contributor license agreements. See the NOTICE file distributed with | |
| * this work for additional information regarding copyright ownership. | |
| * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| * (the "License"); you may not use this file except in compliance with | |
| * the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <log4cxx/logstring.h> | |
| #include <log4cxx/helpers/charsetencoder.h> | |
| #include <log4cxx/private/bytebuffer_priv.h> | |
| #include <log4cxx/helpers/exception.h> | |
| #include <apr_xlate.h> | |
| #include <log4cxx/helpers/stringhelper.h> | |
| #include <log4cxx/helpers/transcoder.h> | |
| #include <algorithm> | |
| #if !defined(LOG4CXX) | |
| #define LOG4CXX 1 | |
| #endif | |
| #include <log4cxx/private/log4cxx_private.h> | |
| #include <apr_portable.h> | |
| #include <mutex> | |
| #ifdef LOG4CXX_HAS_WCSTOMBS | |
| #include <stdlib.h> | |
| #endif | |
| using namespace LOG4CXX_NS; | |
| using namespace LOG4CXX_NS::helpers; | |
| IMPLEMENT_LOG4CXX_OBJECT(CharsetEncoder) | |
| namespace LOG4CXX_NS | |
| { | |
| namespace helpers | |
| { | |
| #if APR_HAS_XLATE | |
| /** | |
| * A character encoder implemented using apr_xlate. | |
| */ | |
| class APRCharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| APRCharsetEncoder(const LogString& topage) : pool() | |
| { | |
| #if LOG4CXX_LOGCHAR_IS_WCHAR | |
| const char* frompage = "WCHAR_T"; | |
| #endif | |
| #if LOG4CXX_LOGCHAR_IS_UTF8 | |
| const char* frompage = "UTF-8"; | |
| #endif | |
| std::string tpage(Transcoder::encodeCharsetName(topage)); | |
| apr_status_t stat = apr_xlate_open(&convset, | |
| tpage.c_str(), | |
| frompage, | |
| pool.getAPRPool()); | |
| if (stat != APR_SUCCESS) | |
| { | |
| throw IllegalArgumentException(topage); | |
| } | |
| } | |
| virtual ~APRCharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| apr_status_t stat; | |
| size_t outbytes_left = out.remaining(); | |
| size_t initial_outbytes_left = outbytes_left; | |
| size_t position = out.position(); | |
| if (iter == in.end()) | |
| { | |
| std::lock_guard<std::mutex> lock(mutex); | |
| stat = apr_xlate_conv_buffer(convset, NULL, NULL, | |
| out.data() + position, &outbytes_left); | |
| } | |
| else | |
| { | |
| LogString::size_type inOffset = (iter - in.begin()); | |
| apr_size_t inbytes_left = | |
| (in.size() - inOffset) * sizeof(LogString::value_type); | |
| apr_size_t initial_inbytes_left = inbytes_left; | |
| { | |
| std::lock_guard<std::mutex> lock(mutex); | |
| stat = apr_xlate_conv_buffer(convset, | |
| (const char*) (in.data() + inOffset), | |
| &inbytes_left, | |
| out.data() + position, | |
| &outbytes_left); | |
| } | |
| iter += ((initial_inbytes_left - inbytes_left) / sizeof(LogString::value_type)); | |
| } | |
| out.increment_position((initial_outbytes_left - outbytes_left)); | |
| return stat; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (codePoint <= 0x10FFFF && 4 <= out.remaining()) | |
| out.increment_position(putUTF8CodePoint(codePoint, out.current())); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| APRCharsetEncoder(const APRCharsetEncoder&); | |
| APRCharsetEncoder& operator=(const APRCharsetEncoder&); | |
| Pool pool; | |
| std::mutex mutex; | |
| apr_xlate_t* convset; | |
| }; | |
| #endif | |
| #if LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_WCSTOMBS | |
| /** | |
| * A character encoder implemented using wcstombs. | |
| */ | |
| class WcstombsCharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| WcstombsCharsetEncoder() | |
| { | |
| } | |
| /** | |
| * Converts a wchar_t to the default external multibyte encoding. | |
| */ | |
| log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| log4cxx_status_t stat = APR_SUCCESS; | |
| if (iter != in.end()) | |
| { | |
| size_t outbytes_left = out.remaining(); | |
| size_t position = out.position(); | |
| std::wstring::size_type inOffset = (iter - in.begin()); | |
| enum { BUFSIZE = 256 }; | |
| wchar_t buf[BUFSIZE]; | |
| size_t chunkSize = BUFSIZE - 1; | |
| if (chunkSize * MB_LEN_MAX > outbytes_left) | |
| { | |
| chunkSize = outbytes_left / MB_LEN_MAX; | |
| } | |
| if (chunkSize > in.length() - inOffset) | |
| { | |
| chunkSize = in.length() - inOffset; | |
| } | |
| memset(buf, 0, BUFSIZE * sizeof(wchar_t)); | |
| memcpy(buf, | |
| in.data() + inOffset, | |
| chunkSize * sizeof(wchar_t)); | |
| size_t converted = wcstombs(out.data() + position, buf, outbytes_left); | |
| if (converted == (size_t) -1) | |
| { | |
| stat = APR_BADARG; | |
| // | |
| // if unconvertable character was encountered | |
| // repeatedly halve source to get fragment that | |
| // can be converted | |
| for (chunkSize /= 2; | |
| chunkSize > 0; | |
| chunkSize /= 2) | |
| { | |
| buf[chunkSize] = 0; | |
| converted = wcstombs(out.data() + position, buf, outbytes_left); | |
| if (converted != (size_t) -1) | |
| { | |
| iter += chunkSize; | |
| out.increment_position(converted); | |
| break; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| iter += chunkSize; | |
| out.increment_position(converted); | |
| } | |
| } | |
| return stat; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (codePoint <= 0x10FFFF && MB_LEN_MAX <= out.remaining()) | |
| { | |
| auto ch = static_cast<wchar_t>(codePoint); | |
| auto converted = wcstombs(out.current(), &ch, 1); | |
| if (static_cast<std::size_t>(-1) == converted) | |
| result = APR_BADARG; | |
| else | |
| out.increment_position(converted); | |
| } | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| WcstombsCharsetEncoder(const WcstombsCharsetEncoder&); | |
| WcstombsCharsetEncoder& operator=(const WcstombsCharsetEncoder&); | |
| }; | |
| #endif | |
| /** | |
| * Encodes a LogString to US-ASCII. | |
| */ | |
| class USASCIICharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| USASCIICharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| log4cxx_status_t stat = APR_SUCCESS; | |
| if (iter != in.end()) | |
| { | |
| while (out.remaining() > 0 && iter != in.end()) | |
| { | |
| LogString::const_iterator prev(iter); | |
| unsigned int sv = Transcoder::decode(in, iter); | |
| if (sv <= 0x7F) | |
| { | |
| out.put((char) sv); | |
| } | |
| else | |
| { | |
| iter = prev; | |
| stat = APR_BADARG; | |
| break; | |
| } | |
| } | |
| } | |
| return stat; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (out.remaining() < 1) | |
| result = APR_BADARG; | |
| else if (codePoint <= 0x7F) | |
| out.put(static_cast<char>(codePoint)); | |
| else if (Transcoder::LOSSCHAR == codePoint) | |
| out.put('?'); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| USASCIICharsetEncoder(const USASCIICharsetEncoder&); | |
| USASCIICharsetEncoder& operator=(const USASCIICharsetEncoder&); | |
| }; | |
| /** | |
| * Converts a LogString to ISO-8859-1. | |
| */ | |
| class ISOLatinCharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| ISOLatinCharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| log4cxx_status_t stat = APR_SUCCESS; | |
| while (out.remaining() > 0 && iter != in.end()) | |
| { | |
| LogString::const_iterator prev(iter); | |
| unsigned int sv = Transcoder::decode(in, iter); | |
| if (sv <= 0xFF) | |
| out.put(static_cast<char>(sv)); | |
| else | |
| { | |
| iter = prev; | |
| stat = APR_BADARG; | |
| break; | |
| } | |
| } | |
| return stat; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (out.remaining() < 1) | |
| result = APR_BADARG; | |
| else if (codePoint <= 0xFF) | |
| out.put(static_cast<char>(codePoint)); | |
| else if (Transcoder::LOSSCHAR == codePoint) | |
| out.put('?'); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| ISOLatinCharsetEncoder(const ISOLatinCharsetEncoder&); | |
| ISOLatinCharsetEncoder& operator=(const ISOLatinCharsetEncoder&); | |
| }; | |
| /** | |
| * Encodes a LogString to a byte array when the encodings are identical. | |
| */ | |
| class TrivialCharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| TrivialCharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| if (iter != in.end()) | |
| { | |
| size_t requested = in.length() - (iter - in.begin()); | |
| if (requested > out.remaining() / sizeof(logchar)) | |
| { | |
| requested = out.remaining() / sizeof(logchar); | |
| } | |
| memcpy(out.current(), | |
| (const char*) in.data() + (iter - in.begin()), | |
| requested * sizeof(logchar)); | |
| iter += requested; | |
| out.increment_position(requested * sizeof(logchar)); | |
| } | |
| return APR_SUCCESS; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (out.remaining() < 1) | |
| result = APR_BADARG; | |
| else if (codePoint <= 0xFF) | |
| out.put(static_cast<char>(codePoint)); | |
| else if (Transcoder::LOSSCHAR == codePoint) | |
| out.put('?'); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| TrivialCharsetEncoder(const TrivialCharsetEncoder&); | |
| TrivialCharsetEncoder& operator=(const TrivialCharsetEncoder&); | |
| }; | |
| /** | |
| * Converts a LogString to UTF-8. | |
| */ | |
| class UTF8CharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| UTF8CharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| while (iter != in.end() && 4 <= out.remaining()) | |
| { | |
| auto sv = Transcoder::getCodePoint(in, iter); | |
| out.increment_position(putUTF8CodePoint(sv, out.current())); | |
| } | |
| return APR_SUCCESS; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (codePoint <= 0x10FFFF && 4 <= out.remaining()) | |
| out.increment_position(putUTF8CodePoint(codePoint, out.current())); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| UTF8CharsetEncoder(const UTF8CharsetEncoder&); | |
| UTF8CharsetEncoder& operator=(const UTF8CharsetEncoder&); | |
| }; | |
| /** | |
| * Encodes a LogString to UTF16-BE. | |
| */ | |
| class UTF16BECharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| UTF16BECharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| while (iter != in.end() && 4 <= out.remaining()) | |
| { | |
| auto sv = Transcoder::getCodePoint(in, iter); | |
| out.increment_position(putUTF16BECodePoint(sv, out.current())); | |
| } | |
| return APR_SUCCESS; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (codePoint <= 0x10FFFF && 4 <= out.remaining()) | |
| Transcoder::encodeUTF16BE(codePoint, out); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| UTF16BECharsetEncoder(const UTF16BECharsetEncoder&); | |
| UTF16BECharsetEncoder& operator=(const UTF16BECharsetEncoder&); | |
| }; | |
| /** | |
| * Encodes a LogString to UTF16-LE. | |
| */ | |
| class UTF16LECharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| UTF16LECharsetEncoder() | |
| { | |
| } | |
| virtual log4cxx_status_t encode(const LogString& in, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& out_param) override | |
| { | |
| auto& out = out_param.impl(); | |
| while (iter != in.end() && 4 <= out.remaining()) | |
| { | |
| auto sv = Transcoder::getCodePoint(in, iter); | |
| out.increment_position(putUTF16LECodePoint(sv, out.current())); | |
| } | |
| return APR_SUCCESS; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (codePoint <= 0x10FFFF && 4 <= out.remaining()) | |
| out.increment_position(putUTF16LECodePoint(codePoint, out.current())); | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| UTF16LECharsetEncoder(const UTF16LECharsetEncoder&); | |
| UTF16LECharsetEncoder& operator=(const UTF16LECharsetEncoder&); | |
| }; | |
| /** | |
| * Charset encoder that uses current locale settings. | |
| */ | |
| class LocaleCharsetEncoder : public CharsetEncoder | |
| { | |
| public: | |
| LocaleCharsetEncoder() : state() | |
| { | |
| } | |
| log4cxx_status_t encode | |
| ( const LogString& in | |
| , LogString::const_iterator& nextCodePoint | |
| , ByteBuffer& out_param | |
| ) override | |
| { | |
| auto& out = out_param.impl(); | |
| log4cxx_status_t result = APR_SUCCESS; | |
| #if !LOG4CXX_CHARSET_EBCDIC | |
| char* current = out.current(); | |
| size_t availableByteCount = out.remaining(); | |
| size_t byteCount = 0; | |
| if (std::mbsinit(&this->state)) // ByteBuffer not partially encoded? | |
| { | |
| // Copy single byte characters | |
| for (; | |
| nextCodePoint != in.end() && byteCount < availableByteCount && static_cast<unsigned int>(*nextCodePoint) < 0x80; | |
| ++nextCodePoint, ++byteCount, ++current) | |
| { | |
| *current = static_cast<char>(*nextCodePoint); | |
| } | |
| } | |
| #endif | |
| // Encode characters that may require multiple bytes | |
| while (nextCodePoint != in.end() && byteCount < availableByteCount && MB_CUR_MAX <= (availableByteCount - byteCount)) | |
| { | |
| auto ch = Transcoder::getCodePoint(in, nextCodePoint); | |
| auto n = std::wcrtomb(current, ch, &this->state); | |
| if (static_cast<std::size_t>(-1) == n) // not a valid wide character? | |
| { | |
| result = APR_BADARG; | |
| break; | |
| } | |
| byteCount += n; | |
| current += n; | |
| } | |
| out.increment_position(byteCount); | |
| return result; | |
| } | |
| /** | |
| * Add onto \c out an encoded equivalent of \c codePoint. | |
| */ | |
| log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& out) override | |
| { | |
| apr_status_t result = APR_SUCCESS; | |
| if (MB_CUR_MAX <= out.remaining()) | |
| { | |
| auto n = std::wcrtomb(out.current(), codePoint, &this->state); | |
| if (static_cast<std::size_t>(-1) == n) // not a valid wide character? | |
| result = APR_BADARG; | |
| else | |
| out.increment_position(n); | |
| } | |
| else | |
| result = APR_BADARG; | |
| return result; | |
| } | |
| private: | |
| std::mbstate_t state; | |
| }; | |
| } // namespace helpers | |
| } //namespace log4cxx | |
| CharsetEncoder::CharsetEncoder() | |
| { | |
| } | |
| CharsetEncoder::~CharsetEncoder() | |
| { | |
| } | |
| CharsetEncoderPtr CharsetEncoder::getDefaultEncoder() | |
| { | |
| static WideLife<CharsetEncoderPtr> encoder(createDefaultEncoder()); | |
| // | |
| // if invoked after static variable destruction | |
| // (if logging is called in the destructor of a static object) | |
| // then create a new decoder. | |
| // | |
| if (encoder.value() == 0) | |
| { | |
| return CharsetEncoderPtr( createDefaultEncoder() ); | |
| } | |
| return encoder; | |
| } | |
| CharsetEncoder* CharsetEncoder::createDefaultEncoder() | |
| { | |
| #if LOG4CXX_CHARSET_UTF8 | |
| #if LOG4CXX_LOGCHAR_IS_UTF8 | |
| return new TrivialCharsetEncoder(); | |
| #else | |
| return new UTF8CharsetEncoder(); | |
| #endif | |
| #elif LOG4CXX_CHARSET_ISO88591 | |
| return new ISOLatinCharsetEncoder(); | |
| #elif LOG4CXX_CHARSET_USASCII | |
| return new USASCIICharsetEncoder(); | |
| #elif LOG4CXX_LOGCHAR_IS_WCHAR && LOG4CXX_HAS_WCSTOMBS | |
| return new WcstombsCharsetEncoder(); | |
| #else | |
| return new LocaleCharsetEncoder(); | |
| #endif | |
| } | |
| CharsetEncoderPtr CharsetEncoder::getUTF8Encoder() | |
| { | |
| return std::make_shared<UTF8CharsetEncoder>(); | |
| } | |
| CharsetEncoderPtr CharsetEncoder::getEncoder(const LogString& charset) | |
| { | |
| if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-8"), LOG4CXX_STR("utf-8")) | |
| || StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP65001"), LOG4CXX_STR("cp65001"))) | |
| { | |
| return std::make_shared<UTF8CharsetEncoder>(); | |
| } | |
| else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("C"), LOG4CXX_STR("c")) || | |
| charset == LOG4CXX_STR("646") || | |
| StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("US-ASCII"), LOG4CXX_STR("us-ascii")) || | |
| StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO646-US"), LOG4CXX_STR("iso646-US")) || | |
| StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ANSI_X3.4-1968"), LOG4CXX_STR("ansi_x3.4-1968")) || | |
| StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP20127"), LOG4CXX_STR("cp20127"))) | |
| { | |
| return std::make_shared<USASCIICharsetEncoder>(); | |
| } | |
| else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO-8859-1"), LOG4CXX_STR("iso-8859-1")) || | |
| StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("ISO-LATIN-1"), LOG4CXX_STR("iso-latin-1")) || | |
| StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP1252"), LOG4CXX_STR("cp1252"))) | |
| { | |
| return std::make_shared<ISOLatinCharsetEncoder>(); | |
| } | |
| else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-16BE"), LOG4CXX_STR("utf-16be")) | |
| || StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-16"), LOG4CXX_STR("utf-16")) | |
| || StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("CP1200"), LOG4CXX_STR("cp1200"))) | |
| { | |
| return std::make_shared<UTF16BECharsetEncoder>(); | |
| } | |
| else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("UTF-16LE"), LOG4CXX_STR("utf-16le"))) | |
| { | |
| return std::make_shared<UTF16LECharsetEncoder>(); | |
| } | |
| else if (StringHelper::equalsIgnoreCase(charset, LOG4CXX_STR("LOCALE"), LOG4CXX_STR("locale"))) | |
| { | |
| return std::make_shared<LocaleCharsetEncoder>(); | |
| } | |
| #if APR_HAS_XLATE | |
| return std::make_shared<APRCharsetEncoder>(charset); | |
| #else | |
| throw IllegalArgumentException(charset); | |
| #endif | |
| } | |
| void CharsetEncoder::reset() | |
| { | |
| } | |
| void CharsetEncoder::encode(CharsetEncoderPtr& enc, | |
| const LogString& src, | |
| LogString::const_iterator& iter, | |
| ByteBuffer& dst) | |
| { | |
| log4cxx_status_t stat = enc->encode(src, iter, dst); | |
| if (stat != APR_SUCCESS && iter != src.end()) | |
| { | |
| #if LOG4CXX_LOGCHAR_IS_WCHAR | |
| iter++; | |
| #elif LOG4CXX_LOGCHAR_IS_UTF8 | |
| // advance past this character and all continuation characters | |
| do | |
| { | |
| ++iter; | |
| } | |
| while (iter != src.end() && | |
| (*iter & 0xC0) == 0x80); | |
| #else | |
| #error logchar is unrecognized | |
| #endif | |
| enc->encode(Transcoder::LOSSCHAR, dst); | |
| } | |
| } | |
| bool CharsetEncoder::isTriviallyCopyable(const LogString& src, const CharsetEncoderPtr& enc) | |
| { | |
| bool result; | |
| #if !LOG4CXX_CHARSET_EBCDIC | |
| if (dynamic_cast<LocaleCharsetEncoder*>(enc.get())) | |
| { | |
| result = src.end() == std::find_if(src.begin(), src.end() | |
| , [](const logchar& ch) -> bool { return 0x80 <= (unsigned int)ch; }); | |
| } | |
| else | |
| #endif | |
| result = !!dynamic_cast<TrivialCharsetEncoder*>(enc.get()); | |
| return result; | |
| } | |
| size_t CharsetEncoder::putUTF8CodePoint(unsigned int ch, char* dst) | |
| { | |
| if (ch < 0x80) | |
| { | |
| dst[0] = (char) ch; | |
| return 1; | |
| } | |
| else if (ch < 0x800) | |
| { | |
| dst[0] = (char) (0xC0 + (ch >> 6)); | |
| dst[1] = (char) (0x80 + (ch & 0x3F)); | |
| return 2; | |
| } | |
| else if (ch < 0x10000) | |
| { | |
| dst[0] = (char) (0xE0 + (ch >> 12)); | |
| dst[1] = (char) (0x80 + ((ch >> 6) & 0x3F)); | |
| dst[2] = (char) (0x80 + (ch & 0x3F)); | |
| return 3; | |
| } | |
| else if (ch <= 0x10FFFF) | |
| { | |
| dst[0] = (char) (0xF0 + (ch >> 18)); | |
| dst[1] = (char) (0x80 + ((ch >> 12) & 0x3F)); | |
| dst[2] = (char) (0x80 + ((ch >> 6) & 0x3F)); | |
| dst[3] = (char) (0x80 + (ch & 0x3F)); | |
| return 4; | |
| } | |
| else | |
| { | |
| // | |
| // output UTF-8 encoding of 0xFFFF | |
| // | |
| dst[0] = (char) 0xEF; | |
| dst[1] = (char) 0xBF; | |
| dst[2] = (char) 0xBF; | |
| return 3; | |
| } | |
| } | |
| size_t CharsetEncoder::putUTF16BECodePoint(unsigned int ch, char* dst) | |
| { | |
| if (ch <= 0xFFFF) | |
| { | |
| dst[0] = (char) (ch >> 8); | |
| dst[1] = (char) (ch & 0xFF); | |
| return 2; | |
| } | |
| if (ch <= 0x10FFFF) | |
| { | |
| unsigned char w = (unsigned char) ((ch >> 16) - 1); | |
| dst[0] = (char) (0xD8 + (w >> 2)); | |
| dst[1] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F)); | |
| dst[2] = (char) (0xDC + ((ch >> 8) & 0x03)); | |
| dst[3] = (char) (ch & 0xFF); | |
| return 4; | |
| } | |
| dst[0] = dst[1] = (char) 0xFF; | |
| return 2; | |
| } | |
| size_t CharsetEncoder::putUTF16LECodePoint(unsigned int ch, char* dst) | |
| { | |
| if (ch <= 0xFFFF) | |
| { | |
| dst[1] = (char) (ch >> 8); | |
| dst[0] = (char) (ch & 0xFF); | |
| return 2; | |
| } | |
| if (ch <= 0x10FFFF) | |
| { | |
| unsigned char w = (unsigned char) ((ch >> 16) - 1); | |
| dst[1] = (char) (0xD8 + (w >> 2)); | |
| dst[0] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F)); | |
| dst[3] = (char) (0xDC + ((ch >> 8) & 0x03)); | |
| dst[2] = (char) (ch & 0xFF); | |
| return 4; | |
| } | |
| dst[0] = dst[1] = (char) 0xFF; | |
| return 2; | |
| } |