diff --git a/mailnews/mime/src/comi18n.cpp b/mailnews/mime/src/comi18n.cpp index 8bdd18e14b42..cda0eb176da9 100644 --- a/mailnews/mime/src/comi18n.cpp +++ b/mailnews/mime/src/comi18n.cpp @@ -768,7 +768,7 @@ char * utf8_mime_encode_mail_address(char *charset, const char *src, int maxLine } // utf-8 to mail charset conversion (or iso-8859-1 in case of us-ascii). if (MIME_ConvertCharset(PR_FALSE, "utf-8", !PL_strcasecmp(charset, "us-ascii") ? "iso-8859-1" : charset, - (const char*) begin, (const PRInt32) len, &buf1, (PRInt32 *) &iBufLen)) { + (const char*) begin, (const PRInt32) len, &buf1, (PRInt32 *) &iBufLen, NULL)) { PR_FREEIF(srcbuf); PR_FREEIF(retbuf); return NULL; //error @@ -1281,7 +1281,9 @@ public: // Converts input buffer or duplicates input if converters not available (and returns 0). // Also duplicates input if convertion not needed. // C string is generated for converted string. - PRInt32 Convert(const char* inBuffer, const PRInt32 inLength, char** outBuffer, PRInt32* outLength); + PRInt32 Convert(const char* inBuffer, const PRInt32 inLength, + char** outBuffer, PRInt32* outLength, + PRInt32* numUnConverted); protected: nsIUnicodeDecoder * GetUnicodeDecoder() {return (mAutoDetect && NULL != mDecoderDetected) ? mDecoderDetected : mDecoder;} @@ -1390,10 +1392,16 @@ PRInt32 MimeCharsetConverterClass::Initialize(const char* from_charset, const ch return NS_SUCCEEDED(res) ? 0 : -1; } -PRInt32 MimeCharsetConverterClass::Convert(const char* inBuffer, const PRInt32 inLength, char** outBuffer, PRInt32* outLength) +PRInt32 MimeCharsetConverterClass::Convert(const char* inBuffer, const PRInt32 inLength, + char** outBuffer, PRInt32* outLength, + PRInt32* numUnConverted) { nsresult res; + if (NULL != numUnConverted) { + *numUnConverted = 0; + } + // Encoder is not available, duplicate the input. if (NULL == mEncoder) { *outBuffer = (char *) PR_Malloc(inLength+1); @@ -1483,12 +1491,40 @@ PRInt32 MimeCharsetConverterClass::Convert(const char* inBuffer, const PRInt32 i } else { // convert from unicode - res = encoder->Convert(unichars, &unicharLength, dstPtr, &dstLength); - if (NS_SUCCEEDED(res)) { - dstPtr[dstLength] = '\0'; - *outBuffer = dstPtr; // set the result string - *outLength = dstLength; + PRUnichar *currentUStringPtr = unichars; + PRInt32 oldUnicharLength = unicharLength; + PRInt32 currentUnicharLength = unicharLength; + char *currentCStringPtr = dstPtr; + PRInt32 totalCLength = 0; + while (1) { + res = encoder->Convert(currentUStringPtr, ¤tUnicharLength, currentCStringPtr, &dstLength); + + // increment for destination + currentCStringPtr += dstLength; + totalCLength += dstLength; + + // break: this is usually the case + // source length <= zero and no error or unrecoverable error + if (0 >= currentUnicharLength || NS_ERROR_UENC_NOMAPPING != res) { + break; + } + // could not map unicode to the destination charset, skip one unichar and continue + // increment for source unicode, skip one unichar + if (NULL != numUnConverted) { + (*numUnConverted)++; + } + currentUStringPtr += currentUnicharLength + 1; + oldUnicharLength -= (currentUnicharLength + 1); + currentUnicharLength = oldUnicharLength; + // estimate target length again + (void) encoder->GetMaxLength(currentUStringPtr, currentUnicharLength, &dstLength); + if (dstLength > unicharLength) { + dstLength = unicharLength; // not to exceed allocated buffer length + } } + dstPtr[totalCLength] = '\0'; + *outBuffer = dstPtr; // set the result string + *outLength = totalCLength; } } delete [] unichars; @@ -1539,11 +1575,13 @@ PRInt32 MIME_ConvertString(const char* from_charset, const char* to_charset, const char* inCstring, char** outCstring) { PRInt32 outLength; - return MIME_ConvertCharset(PR_FALSE, from_charset, to_charset, inCstring, PL_strlen(inCstring), outCstring, &outLength); + return MIME_ConvertCharset(PR_FALSE, from_charset, to_charset, + inCstring, PL_strlen(inCstring), outCstring, &outLength, NULL); } PRInt32 MIME_ConvertCharset(const PRBool autoDetection, const char* from_charset, const char* to_charset, - const char* inBuffer, const PRInt32 inLength, char** outBuffer, PRInt32* outLength) + const char* inBuffer, const PRInt32 inLength, char** outBuffer, PRInt32* outLength, + PRInt32* numUnConverted) { char srcCharset[kMAX_CSNAME+1], dstCharset[kMAX_CSNAME+1]; MimeCharsetConverterClass aMimeCharsetConverterClass; @@ -1557,7 +1595,7 @@ PRInt32 MIME_ConvertCharset(const PRBool autoDetection, const char* from_charset res = aMimeCharsetConverterClass.Initialize(srcCharset, dstCharset, autoDetection, -1); if (res != -1) { - res = aMimeCharsetConverterClass.Convert(inBuffer, inLength, outBuffer, outLength); + res = aMimeCharsetConverterClass.Convert(inBuffer, inLength, outBuffer, outLength, NULL); } return res; diff --git a/mailnews/mime/src/comi18n.h b/mailnews/mime/src/comi18n.h index b3ae197fc655..78bb05ef235d 100644 --- a/mailnews/mime/src/comi18n.h +++ b/mailnews/mime/src/comi18n.h @@ -89,10 +89,12 @@ PRInt32 MIME_ConvertString(const char* from_charset, const char* to_charset, * @param inLength [IN] Input buffer length. * @param outBuffer [OUT] Converted buffer is set. Allocated buffer should be freed by PR_FREE. * @param outLength [OUT] Converted buffer length is set. + * @param numUnConverted [OUT] Number of unconverted characters (can be NULL). * @return 0 is success, otherwise error. */ PRInt32 MIME_ConvertCharset(const PRBool autoDetection, const char* from_charset, const char* to_charset, - const char* inBuffer, const PRInt32 inLength, char** outBuffer, PRInt32* outLength); + const char* inBuffer, const PRInt32 inLength, char** outBuffer, PRInt32* outLength, + PRInt32* numUnConverted); /** * Convert an input string with a charset into unicode. diff --git a/mailnews/mime/src/mimedrft.cpp b/mailnews/mime/src/mimedrft.cpp index db0dcceed629..bb61690170fa 100644 --- a/mailnews/mime/src/mimedrft.cpp +++ b/mailnews/mime/src/mimedrft.cpp @@ -536,7 +536,7 @@ mime_intl_mimepart_2_str(char **str, char *mcharset) char *newStr = NULL; PRInt32 newStrLen; PRInt32 res = MIME_ConvertCharset(PR_TRUE, mcharset, "UTF-8", *str, PL_strlen(*str), - &newStr, &newStrLen); + &newStr, &newStrLen, NULL); if ( (NS_SUCCEEDED(res)) && (newStr && newStr != *str)) { PR_FREEIF(*str); @@ -1301,7 +1301,7 @@ mime_parse_stream_complete (nsMIMESession *stream) char *newBody = NULL; PRInt32 newBodyLen; PRInt32 res = MIME_ConvertCharset(PR_TRUE, mdd->mailcharset, "UTF-8", body, - PL_strlen(body), &newBody, &newBodyLen); + PL_strlen(body), &newBody, &newBodyLen, NULL); if ( (NS_SUCCEEDED(res)) && (newBody && newBody != body)) { PR_FREEIF(body); diff --git a/mailnews/mime/src/mimemoz2.cpp b/mailnews/mime/src/mimemoz2.cpp index b926a9c3ea95..2106bf189af7 100644 --- a/mailnews/mime/src/mimemoz2.cpp +++ b/mailnews/mime/src/mimemoz2.cpp @@ -369,7 +369,7 @@ mime_convert_charset (const PRBool input_autodetect, const char *input_line, PRI char *convertedString = NULL; PRInt32 convertedStringLen; PRInt32 res = MIME_ConvertCharset(input_autodetect, input_charset, "UTF-8", input_line, input_length, - &convertedString, &convertedStringLen); + &convertedString, &convertedStringLen, NULL); if (res != 0) { *output_ret = 0; diff --git a/mailnews/mime/src/nsMsgHeaderParser.cpp b/mailnews/mime/src/nsMsgHeaderParser.cpp index b6e52d64f4b5..b5ea4f0a4ed5 100644 --- a/mailnews/mime/src/nsMsgHeaderParser.cpp +++ b/mailnews/mime/src/nsMsgHeaderParser.cpp @@ -102,7 +102,8 @@ nsresult nsMsgHeaderParser::ParseHeaderAddresses (const char *charset, const cha s += len; } // convert array of strings - if (MIME_ConvertCharset(PR_FALSE, "UTF-8", CHARSET(charset), *names, len_all, &outStrings, &outStrLen) == 0) { + if (MIME_ConvertCharset(PR_FALSE, "UTF-8", CHARSET(charset), *names, + len_all, &outStrings, &outStrLen, NULL) == 0) { PR_Free(*names); *names = outStrings; } @@ -116,7 +117,8 @@ nsresult nsMsgHeaderParser::ParseHeaderAddresses (const char *charset, const cha s += len; } // convert array of strings - if (MIME_ConvertCharset(PR_FALSE, "UTF-8", CHARSET(charset), *addresses, len_all, &outStrings, &outStrLen) == 0) { + if (MIME_ConvertCharset(PR_FALSE, "UTF-8", CHARSET(charset), *addresses, + len_all, &outStrings, &outStrLen, NULL) == 0) { PR_Free(*addresses); *addresses = outStrings; }