From 86e5ca3fd3df88b264880e854045c46811eb855d Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Sun, 21 Dec 2014 17:07:29 +0000 Subject: [PATCH] Update Csocket to 7c9c6ef676818457a952c2bda478ce7e27a928bf * Add encoding mode which reads UTF-8 and something else, but sends UTF-8 * Expose encoding conversion error callbacks to subclasses --- include/znc/Csocket.h | 15 +++++++++ src/Csocket.cpp | 76 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/include/znc/Csocket.h b/include/znc/Csocket.h index 8a9704b5..5d8794fe 100644 --- a/include/znc/Csocket.h +++ b/include/znc/Csocket.h @@ -1134,6 +1134,19 @@ public: #ifdef HAVE_ICU void SetEncoding( const CString& sEncoding ); + virtual void IcuExtToUCallback( + UConverterToUnicodeArgs* toArgs, + const char* codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode* err ); + virtual void IcuExtFromUCallback( + UConverterFromUnicodeArgs* fromArgs, + const UChar* codeUnits, + int32_t length, + UChar32 codePoint, + UConverterCallbackReason reason, + UErrorCode* err ); #endif /* HAVE_ICU */ private: @@ -1200,6 +1213,8 @@ private: #ifdef HAVE_ICU icu::LocalUConverterPointer m_cnvInt, m_cnvIntStrict, m_cnvExt; bool m_cnvTryUTF8; + bool m_cnvSendUTF8; + CS_STRING m_sEncoding; #endif }; diff --git a/src/Csocket.cpp b/src/Csocket.cpp index 8594bf4c..0f4c30db 100644 --- a/src/Csocket.cpp +++ b/src/Csocket.cpp @@ -51,6 +51,7 @@ #ifdef HAVE_ICU #include +#include #endif /* HAVE_ICU */ #include @@ -1058,6 +1059,10 @@ void Csock::Copy( const Csock & cCopy ) #endif /* HAVE_LIBSSL */ +#ifdef HAVE_ICU + SetEncoding(cCopy.m_sEncoding); +#endif + CleanupCrons(); CleanupFDMonitors(); m_vcCrons = cCopy.m_vcCrons; @@ -2056,7 +2061,7 @@ bool Csock::Write( const char *data, size_t len ) bool Csock::Write( const CS_STRING & sData ) { #ifdef HAVE_ICU - if( m_cnvExt.isValid() ) + if( m_cnvExt.isValid() && !m_cnvSendUTF8 ) { CS_STRING sBinary; if( icuConv( sData, sBinary, m_cnvInt.getAlias(), m_cnvExt.getAlias() ) ) @@ -2314,21 +2319,85 @@ void Csock::PushBuff( const char *data, size_t len, bool bStartAtZero ) } #ifdef HAVE_ICU +void Csock::IcuExtToUCallback( + UConverterToUnicodeArgs* toArgs, + const char* codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode* err) +{ + if( reason <= UCNV_IRREGULAR ) + { + *err = U_ZERO_ERROR; + ucnv_cbToUWriteSub( toArgs, 0, err ); + } +} + +void Csock::IcuExtFromUCallback( + UConverterFromUnicodeArgs* fromArgs, + const UChar* codeUnits, + int32_t length, + UChar32 codePoint, + UConverterCallbackReason reason, + UErrorCode * err) +{ + if( reason <= UCNV_IRREGULAR ) + { + *err = U_ZERO_ERROR; + ucnv_cbFromUWriteSub( fromArgs, 0, err ); + } +} + +static void icuExtToUCallback( + const void* context, + UConverterToUnicodeArgs* toArgs, + const char* codeUnits, + int32_t length, + UConverterCallbackReason reason, + UErrorCode* err) +{ + Csock* pcSock = (Csock*)context; + pcSock->IcuExtToUCallback(toArgs, codeUnits, length, reason, err); +} + +static void icuExtFromUCallback( + const void* context, + UConverterFromUnicodeArgs* fromArgs, + const UChar* codeUnits, + int32_t length, + UChar32 codePoint, + UConverterCallbackReason reason, + UErrorCode* err) +{ + Csock* pcSock = (Csock*)context; + pcSock->IcuExtFromUCallback(fromArgs, codeUnits, length, codePoint, reason, err); +} + void Csock::SetEncoding( const CS_STRING& sEncoding ) { + m_sEncoding = sEncoding; if( sEncoding.empty() ) { m_cnvExt.adoptInstead( NULL ); } else { - m_cnvTryUTF8 = sEncoding[0] == '*'; + m_cnvTryUTF8 = sEncoding[0] == '*' || sEncoding[0] == '^'; + m_cnvSendUTF8 = sEncoding[0] == '^'; + const char* sEncodingName = sEncoding.c_str(); + if( m_cnvTryUTF8 ) + sEncodingName++; icu::ErrorCode e; - m_cnvExt.adoptInstead( ucnv_open( sEncoding.c_str(), e ) ); + m_cnvExt.adoptInstead( ucnv_open( sEncodingName, e ) ); if( e.isFailure() ) { CS_DEBUG( "Can't set encoding to " << sEncoding << ": " << e.errorName() ); } + if( m_cnvExt.isValid() ) + { + ucnv_setToUCallBack( m_cnvExt.getAlias(), icuExtToUCallback, this, NULL, NULL, e ); + ucnv_setFromUCallBack( m_cnvExt.getAlias(), icuExtFromUCallback, this, NULL, NULL, e ); + } } } #endif /* HAVE_ICU */ @@ -2973,6 +3042,7 @@ void Csock::Init( const CS_STRING & sHostname, uint16_t uPort, int iTimeout ) #endif /* HAVE_C_ARES */ #ifdef HAVE_ICU m_cnvTryUTF8 = false; + m_cnvSendUTF8 = false; icu::ErrorCode e; m_cnvInt.adoptInstead( ucnv_open( "UTF-8", e ) ); m_cnvIntStrict.adoptInstead( ucnv_open( "UTF-8", e ) );