diff --git a/mailnews/base/util/nsMsgI18N.cpp b/mailnews/base/util/nsMsgI18N.cpp --- a/mailnews/base/util/nsMsgI18N.cpp +++ b/mailnews/base/util/nsMsgI18N.cpp @@ -131,6 +131,10 @@ nsresult nsMsgI18NConvertToUnicode(const nsAString& outString, PRBool aIsCharsetCanonical) { +#ifdef DEBUG + printf("nsMsgI18NConvertToUnicode, aCharset = %s, inString = %s\n", + aCharset, inString.get()); +#endif if (inString.IsEmpty()) { outString.Truncate(); return NS_OK; @@ -165,6 +169,9 @@ nsresult nsMsgI18NConvertToUnicode(const rv = ccm->GetUnicodeDecoderRaw(aCharset, getter_AddRefs(decoder)); else rv = ccm->GetUnicodeDecoder(aCharset, getter_AddRefs(decoder)); +#ifdef DEBUG + printf(" GetUnicodeDecoder returned %x\n", rv); +#endif NS_ENSURE_SUCCESS(rv, rv); const char *originalSrcPtr = inString.get(); @@ -182,6 +189,10 @@ nsresult nsMsgI18NConvertToUnicode(const srcLength = originalLength - consumedLen; dstLength = 512; rv = decoder->Convert(currentSrcPtr, &srcLength, localbuf, &dstLength); +#ifdef DEBUG + printf(" decode->Convert returned %x, localbuf = %s\n", + rv, NS_ConvertUTF16toUTF8(localbuf).get()); +#endif if (NS_FAILED(rv) || dstLength == 0) break; outString.Append(localbuf, dstLength); diff --git a/mailnews/build/nsMailModule.cpp b/mailnews/build/nsMailModule.cpp --- a/mailnews/build/nsMailModule.cpp +++ b/mailnews/build/nsMailModule.cpp @@ -274,6 +274,10 @@ #include "nsMimeConverter.h" #include "nsMsgHeaderParser.h" #include "nsMimeHeaders.h" +#include "nsUTF7ToUnicode.h" +#include "nsMUTF7ToUnicode.h" +#include "nsUnicodeToUTF7.h" +#include "nsUnicodeToMUTF7.h" /////////////////////////////////////////////////////////////////////////////// // mime emitter includes @@ -674,12 +678,20 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMimeCon NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamConverter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgHeaderParser) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMimeHeaders) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUTF7ToUnicode) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsMUTF7ToUnicode) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToUTF7) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToMUTF7) NS_DEFINE_NAMED_CID(NS_MIME_OBJECT_CLASS_ACCESS_CID); NS_DEFINE_NAMED_CID(NS_MIME_CONVERTER_CID); NS_DEFINE_NAMED_CID(NS_MSGHEADERPARSER_CID); NS_DEFINE_NAMED_CID(NS_MAILNEWS_MIME_STREAM_CONVERTER_CID); NS_DEFINE_NAMED_CID(NS_IMIMEHEADERS_CID); +NS_DEFINE_NAMED_CID(NS_UTF7TOUNICODE_CID); +NS_DEFINE_NAMED_CID(NS_MUTF7TOUNICODE_CID); +NS_DEFINE_NAMED_CID(NS_UNICODETOUTF7_CID); +NS_DEFINE_NAMED_CID(NS_UNICODETOMUTF7_CID); //////////////////////////////////////////////////////////////////////////////// // mime emitter factories @@ -943,6 +955,10 @@ const mozilla::Module::CIDEntry kMailNew { &kNS_MSGHEADERPARSER_CID, false, NULL, nsMsgHeaderParserConstructor }, { &kNS_MAILNEWS_MIME_STREAM_CONVERTER_CID, false, NULL, nsStreamConverterConstructor }, { &kNS_IMIMEHEADERS_CID, false, NULL, nsMimeHeadersConstructor }, + { &kNS_UTF7TOUNICODE_CID, false, NULL, nsUTF7ToUnicodeConstructor }, + { &kNS_MUTF7TOUNICODE_CID, false, NULL, nsMUTF7ToUnicodeConstructor }, + { &kNS_UNICODETOUTF7_CID, false, NULL, nsUnicodeToUTF7Constructor }, + { &kNS_UNICODETOMUTF7_CID, false, NULL, nsUnicodeToMUTF7Constructor }, { &kNS_HTML_MIME_EMITTER_CID, false, NULL, nsMimeHtmlDisplayEmitterConstructor}, { &kNS_XML_MIME_EMITTER_CID, false, NULL, nsMimeXmlEmitterConstructor}, { &kNS_PLAIN_MIME_EMITTER_CID, false, NULL, nsMimePlainEmitterConstructor}, @@ -1153,6 +1169,10 @@ const mozilla::Module::ContractIDEntry k { NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID1, &kNS_MAILNEWS_MIME_STREAM_CONVERTER_CID }, { NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID2, &kNS_MAILNEWS_MIME_STREAM_CONVERTER_CID }, { NS_IMIMEHEADERS_CONTRACTID, &kNS_IMIMEHEADERS_CID }, + { NS_UNICODEDECODER_CONTRACTID_BASE "UTF-7", &kNS_UTF7TOUNICODE_CID }, + { NS_UNICODEDECODER_CONTRACTID_BASE "x-imap4-modified-utf7", &kNS_MUTF7TOUNICODE_CID }, + { NS_UNICODEENCODER_CONTRACTID_BASE "UTF-7", &kNS_UNICODETOUTF7_CID }, + { NS_UNICODEENCODER_CONTRACTID_BASE "x-imap4-modified-utf7", &kNS_UNICODETOMUTF7_CID }, { NS_HTML_MIME_EMITTER_CONTRACTID, &kNS_HTML_MIME_EMITTER_CID }, { NS_XML_MIME_EMITTER_CONTRACTID, &kNS_XML_MIME_EMITTER_CID }, { NS_PLAIN_MIME_EMITTER_CONTRACTID, &kNS_PLAIN_MIME_EMITTER_CID }, @@ -1204,6 +1224,10 @@ static const mozilla::Module::CategoryEn // Local Entries // msgdb Entries // Mime Entries + { "Charset Decoders", "UTF-7", "" }, + { "Charset Encoders", "UTF-7", "" }, + { "Charset Decoders", "x-imap4-modified-utf7", "" }, + { "Charset Encoders", "x-imap4-modified-utf7", "" }, { "mime-emitter", NS_HTML_MIME_EMITTER_CONTRACTID, NS_HTML_MIME_EMITTER_CONTRACTID }, { "mime-emitter", NS_XML_MIME_EMITTER_CONTRACTID, NS_XML_MIME_EMITTER_CONTRACTID }, { "mime-emitter", NS_PLAIN_MIME_EMITTER_CONTRACTID, NS_PLAIN_MIME_EMITTER_CONTRACTID }, diff --git a/mailnews/mime/build/nsMimeModule.cpp b/mailnews/mime/build/nsMimeModule.cpp --- a/mailnews/mime/build/nsMimeModule.cpp +++ b/mailnews/mime/build/nsMimeModule.cpp @@ -39,6 +39,8 @@ #include "mozilla/ModuleUtils.h" #include "nsMsgMimeCID.h" #include "nsCOMPtr.h" +#include "nsIUnicodeDecoder.h" +#include "nsIUnicodeEncoder.h" // include files for components this factory creates... #include "nsStreamConverter.h" @@ -46,6 +48,10 @@ #include "nsMimeConverter.h" #include "nsMsgHeaderParser.h" #include "nsMimeHeaders.h" +#include "nsUTF7ToUnicode.h" +#include "nsMUTF7ToUnicode.h" +#include "nsUnicodeToUTF7.h" +#include "nsUnicodeToMUTF7.h" // private factory declarations for each component we know how to produce @@ -54,12 +60,20 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMimeCon NS_GENERIC_FACTORY_CONSTRUCTOR(nsStreamConverter) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMsgHeaderParser) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMimeHeaders) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUTF7ToUnicode) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsMUTF7ToUnicode) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToUTF7) +NS_GENERIC_FACTORY_CONSTRUCTOR(nsUnicodeToMUTF7) NS_DEFINE_NAMED_CID(NS_MIME_OBJECT_CLASS_ACCESS_CID); NS_DEFINE_NAMED_CID(NS_MIME_CONVERTER_CID); NS_DEFINE_NAMED_CID(NS_MSGHEADERPARSER_CID); NS_DEFINE_NAMED_CID(NS_MAILNEWS_MIME_STREAM_CONVERTER_CID); NS_DEFINE_NAMED_CID(NS_IMIMEHEADERS_CID); +NS_DEFINE_NAMED_CID(NS_UTF7TOUNICODE_CID); +NS_DEFINE_NAMED_CID(NS_MUTF7TOUNICODE_CID); +NS_DEFINE_NAMED_CID(NS_UNICODETOUTF7_CID); +NS_DEFINE_NAMED_CID(NS_UNICODETOMUTF7_CID); const mozilla::Module::CIDEntry kMimeCIDs[] = { { &kNS_MIME_OBJECT_CLASS_ACCESS_CID, false, NULL, nsMimeObjectClassAccessConstructor }, @@ -67,6 +81,10 @@ const mozilla::Module::CIDEntry kMimeCID { &kNS_MSGHEADERPARSER_CID, false, NULL, nsMsgHeaderParserConstructor }, { &kNS_MAILNEWS_MIME_STREAM_CONVERTER_CID, false, NULL, nsStreamConverterConstructor }, { &kNS_IMIMEHEADERS_CID, false, NULL, nsMimeHeadersConstructor }, + { &kNS_UTF7TOUNICODE_CID, false, NULL, nsUTF7ToUnicodeConstructor }, + { &kNS_MUTF7TOUNICODE_CID, false, NULL, nsMUTF7ToUnicodeConstructor }, + { &kNS_UNICODETOUTF7_CID, false, NULL, nsUnicodeToUTF7Constructor }, + { &kNS_UNICODETOMUTF7_CID, false, NULL, nsUnicodeToMUTF7Constructor }, { NULL } }; @@ -78,13 +96,26 @@ const mozilla::Module::ContractIDEntry k { NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID1, &kNS_MAILNEWS_MIME_STREAM_CONVERTER_CID }, { NS_MAILNEWS_MIME_STREAM_CONVERTER_CONTRACTID2, &kNS_MAILNEWS_MIME_STREAM_CONVERTER_CID }, { NS_IMIMEHEADERS_CONTRACTID, &kNS_IMIMEHEADERS_CID }, + { NS_UNICODEDECODER_CONTRACTID_BASE "UTF-7", &kNS_UTF7TOUNICODE_CID }, + { NS_UNICODEDECODER_CONTRACTID_BASE "x-imap4-modified-utf7", &kNS_MUTF7TOUNICODE_CID }, + { NS_UNICODEENCODER_CONTRACTID_BASE "UTF-7", &kNS_UNICODETOUTF7_CID }, + { NS_UNICODEENCODER_CONTRACTID_BASE "x-imap4-modified-utf7", &kNS_UNICODETOMUTF7_CID }, + { NULL } +}; + +static const mozilla::Module::CategoryEntry kMimeUConvCategories[] = { + { "Charset Decoders", "UTF-7", "" }, + { "Charset Encoders", "UTF-7", "" }, + { "Charset Decoders", "x-imap4-modified-utf7", "" }, + { "Charset Encoders", "x-imap4-modified-utf7", "" }, { NULL } }; static const mozilla::Module kMimeModule = { mozilla::Module::kVersion, kMimeCIDs, - kMimeContracts + kMimeContracts, + kMimeUConvCategories }; NSMODULE_DEFN(mime) = &kMimeModule; diff --git a/mailnews/mime/public/nsMsgMimeCID.h b/mailnews/mime/public/nsMsgMimeCID.h --- a/mailnews/mime/public/nsMsgMimeCID.h +++ b/mailnews/mime/public/nsMsgMimeCID.h @@ -72,4 +72,24 @@ { 0x932c53a5, 0xf398, 0x11d2, \ { 0x82, 0xb7, 0x44, 0x45, 0x53, 0x54, 0x0, 0x2 } } +// Class ID for our UTF7ToUnicode charset converter +// {77CFAAF1-1CF4-11d3-8AAF-00600811A836} +#define NS_UTF7TOUNICODE_CID \ + { 0x77cfaaf1, 0x1cf4, 0x11d3, {0x8a, 0xaf, 0x0, 0x60, 0x8, 0x11, 0xa8, 0x36}} + +// Class ID for our MUTF7ToUnicode charset converter +// {B57F97C1-0D70-11d3-8AAE-00600811A836} +#define NS_MUTF7TOUNICODE_CID \ + { 0xb57f97c1, 0xd70, 0x11d3, {0x8a, 0xae, 0x0, 0x60, 0x8, 0x11, 0xa8, 0x36}} + +// Class ID for our UnicodeToUTF7 charset converter +// {77CFAAF2-1CF4-11d3-8AAF-00600811A836} +#define NS_UNICODETOUTF7_CID \ + { 0x77cfaaf2, 0x1cf4, 0x11d3, {0x8a, 0xaf, 0x0, 0x60, 0x8, 0x11, 0xa8, 0x36}} + +// Class ID for our UnicodeToMUTF7 charset converter +// {B57F97C2-0D70-11d3-8AAE-00600811A836} +#define NS_UNICODETOMUTF7_CID \ + { 0xb57f97c2, 0xd70, 0x11d3, {0x8a, 0xae, 0x0, 0x60, 0x8, 0x11, 0xa8, 0x36}} + #endif // nsMessageMimeCID_h__ diff --git a/mailnews/mime/src/Makefile.in b/mailnews/mime/src/Makefile.in --- a/mailnews/mime/src/Makefile.in +++ b/mailnews/mime/src/Makefile.in @@ -95,6 +95,11 @@ CPPSRCS = \ mimecom.cpp \ mimemoz2.cpp \ comi18n.cpp \ + nsUCvMimeSupport.cpp \ + nsUTF7ToUnicode.cpp \ + nsMUTF7ToUnicode.cpp \ + nsUnicodeToUTF7.cpp \ + nsUnicodeToMUTF7.cpp \ nsMsgHeaderParser.cpp \ nsStreamConverter.cpp \ mimedrft.cpp \ diff --git a/mailnews/mime/src/nsMUTF7ToUnicode.cpp b/mailnews/mime/src/nsMUTF7ToUnicode.cpp new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsMUTF7ToUnicode.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsMUTF7ToUnicode.h" + +//---------------------------------------------------------------------- +// Class nsMUTF7ToUnicode [implementation] + +nsMUTF7ToUnicode::nsMUTF7ToUnicode() +: nsBasicUTF7Decoder(',', '&') +{ +} diff --git a/mailnews/mime/src/nsMUTF7ToUnicode.h b/mailnews/mime/src/nsMUTF7ToUnicode.h new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsMUTF7ToUnicode.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsMUTF7ToUnicode_h___ +#define nsMUTF7ToUnicode_h___ + +#include "nsUTF7ToUnicode.h" + +//---------------------------------------------------------------------- +// Class nsMUTF7ToUnicode [declaration] + +/** + * A character set converter from Modified UTF7 to Unicode. + * + * @created 18/May/1999 + * @author Catalin Rotaru [CATA] + */ +class nsMUTF7ToUnicode : public nsBasicUTF7Decoder +{ +public: + + /** + * Class constructor. + */ + nsMUTF7ToUnicode(); + +}; + +#endif /* nsMUTF7ToUnicode_h___ */ diff --git a/mailnews/mime/src/nsUCvMimeSupport.cpp b/mailnews/mime/src/nsUCvMimeSupport.cpp new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUCvMimeSupport.cpp @@ -0,0 +1,451 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Simon Montagu + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "pratom.h" +#include "nsIComponentManager.h" +#include "nsUCvMimeSupport.h" + +#define DEFAULT_BUFFER_CAPACITY 16 + +// XXX review the buffer growth limitation code + +//---------------------------------------------------------------------- +// Class nsBasicDecoderSupport [implementation] + +nsBasicDecoderSupport::nsBasicDecoderSupport() + : mErrBehavior(kOnError_Recover) +{ +} + +nsBasicDecoderSupport::~nsBasicDecoderSupport() +{ +} + +//---------------------------------------------------------------------- +// Interface nsISupports [implementation] + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsBasicDecoderSupport, nsIUnicodeDecoder) + +//---------------------------------------------------------------------- +// Interface nsIUnicodeDecoder [implementation] + +void +nsBasicDecoderSupport::SetInputErrorBehavior(PRInt32 aBehavior) +{ + NS_ABORT_IF_FALSE(aBehavior == kOnError_Recover || aBehavior == kOnError_Signal, + "Unknown behavior for SetInputErrorBehavior"); + mErrBehavior = aBehavior; +} + +PRUnichar +nsBasicDecoderSupport::GetCharacterForUnMapped() +{ + return PRUnichar(0xfffd); // Unicode REPLACEMENT CHARACTER +} + +//---------------------------------------------------------------------- +// Class nsBufferDecoderSupport [implementation] + +nsBufferDecoderSupport::nsBufferDecoderSupport(PRUint32 aMaxLengthFactor) + : nsBasicDecoderSupport(), + mMaxLengthFactor(aMaxLengthFactor) +{ + mBufferCapacity = DEFAULT_BUFFER_CAPACITY; + mBuffer = new char[mBufferCapacity]; + + Reset(); +} + +nsBufferDecoderSupport::~nsBufferDecoderSupport() +{ + delete [] mBuffer; +} + +void nsBufferDecoderSupport::FillBuffer(const char ** aSrc, PRInt32 aSrcLength) +{ + PRInt32 bcr = PR_MIN(mBufferCapacity - mBufferLength, aSrcLength); + memcpy(mBuffer + mBufferLength, *aSrc, bcr); + mBufferLength += bcr; + (*aSrc) += bcr; +} + +//---------------------------------------------------------------------- +// Subclassing of nsBasicDecoderSupport class [implementation] + +NS_IMETHODIMP nsBufferDecoderSupport::Convert(const char * aSrc, + PRInt32 * aSrcLength, + PRUnichar * aDest, + PRInt32 * aDestLength) +{ + // we do all operations using pointers internally + const char * src = aSrc; + const char * srcEnd = aSrc + *aSrcLength; + PRUnichar * dest = aDest; + PRUnichar * destEnd = aDest + *aDestLength; + + PRInt32 bcr, bcw; // byte counts for read & write; + nsresult res = NS_OK; + + // do we have some residual data from the last conversion? + if (mBufferLength > 0) { + if (dest == destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + } else { + for (;;) { + // we need new data to add to the buffer + if (src == srcEnd) { + res = NS_OK_UDEC_MOREINPUT; + break; + } + + // fill that buffer + PRInt32 buffLen = mBufferLength; // initial buffer length + FillBuffer(&src, srcEnd - src); + + // convert that buffer + bcr = mBufferLength; + bcw = destEnd - dest; + res = ConvertNoBuff(mBuffer, &bcr, dest, &bcw); + dest += bcw; + + // Detect invalid input character + if (res == NS_ERROR_ILLEGAL_INPUT && mErrBehavior == kOnError_Signal) { + break; + } + + if ((res == NS_OK_UDEC_MOREINPUT) && (bcw == 0)) { + res = NS_ERROR_UNEXPECTED; +#if defined(DEBUG_yokoyama) || defined(DEBUG_ftang) + NS_ERROR("This should not happen. Internal buffer may be corrupted."); +#endif + break; + } else { + if (bcr < buffLen) { + // we didn't convert that residual data - unfill the buffer + src -= mBufferLength - buffLen; + mBufferLength = buffLen; +#if defined(DEBUG_yokoyama) || defined(DEBUG_ftang) + NS_ERROR("This should not happen. Internal buffer may be corrupted."); +#endif + } else { + // the buffer and some extra data was converted - unget the rest + src -= mBufferLength - bcr; + mBufferLength = 0; + res = NS_OK; + } + break; + } + } + } + } + + if (res == NS_OK) { + bcr = srcEnd - src; + bcw = destEnd - dest; + res = ConvertNoBuff(src, &bcr, dest, &bcw); + src += bcr; + dest += bcw; + + // if we have partial input, store it in our internal buffer. + if (res == NS_OK_UDEC_MOREINPUT) { + bcr = srcEnd - src; + // make sure buffer is large enough + if (bcr > mBufferCapacity) { + // somehow we got into an error state and the buffer is growing out + // of control + res = NS_ERROR_UNEXPECTED; + } else { + FillBuffer(&src, bcr); + } + } + } + + *aSrcLength -= srcEnd - src; + *aDestLength -= destEnd - dest; + return res; +} + +NS_IMETHODIMP nsBufferDecoderSupport::Reset() +{ + mBufferLength = 0; + return NS_OK; +} + +NS_IMETHODIMP nsBufferDecoderSupport::GetMaxLength(const char* aSrc, + PRInt32 aSrcLength, + PRInt32* aDestLength) +{ + NS_ASSERTION(mMaxLengthFactor != 0, "Must override GetMaxLength!"); + *aDestLength = aSrcLength * mMaxLengthFactor; + return NS_OK; +} + +//---------------------------------------------------------------------- +// Class nsBasicEncoder [implementation] +nsBasicEncoder::nsBasicEncoder() +{ +} + +nsBasicEncoder::~nsBasicEncoder() +{ +} + +//---------------------------------------------------------------------- +// Interface nsISupports [implementation] + +NS_IMPL_ADDREF(nsBasicEncoder) +NS_IMPL_RELEASE(nsBasicEncoder) +NS_IMPL_QUERY_INTERFACE1(nsBasicEncoder, + nsIUnicodeEncoder) +//---------------------------------------------------------------------- +// Class nsEncoderSupport [implementation] + +nsEncoderSupport::nsEncoderSupport(PRUint32 aMaxLengthFactor) : + mMaxLengthFactor(aMaxLengthFactor) +{ + mBufferCapacity = DEFAULT_BUFFER_CAPACITY; + mBuffer = new char[mBufferCapacity]; + + mErrBehavior = kOnError_Signal; + mErrChar = 0; + + Reset(); +} + +nsEncoderSupport::~nsEncoderSupport() +{ + delete [] mBuffer; +} + +NS_IMETHODIMP nsEncoderSupport::ConvertNoBuff(const PRUnichar * aSrc, + PRInt32 * aSrcLength, + char * aDest, + PRInt32 * aDestLength) +{ + // we do all operations using pointers internally + const PRUnichar * src = aSrc; + const PRUnichar * srcEnd = aSrc + *aSrcLength; + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + + PRInt32 bcr, bcw; // byte counts for read & write; + nsresult res; + + for (;;) { + bcr = srcEnd - src; + bcw = destEnd - dest; + res = ConvertNoBuffNoErr(src, &bcr, dest, &bcw); + src += bcr; + dest += bcw; + + if (res == NS_ERROR_UENC_NOMAPPING) { + if (mErrBehavior == kOnError_Replace) { + const PRUnichar buff[] = {mErrChar}; + bcr = 1; + bcw = destEnd - dest; + src--; // back the input: maybe the guy won't consume consume anything. + res = ConvertNoBuffNoErr(buff, &bcr, dest, &bcw); + src += bcr; + dest += bcw; + if (res != NS_OK) break; + } else if (mErrBehavior == kOnError_CallBack) { + bcw = destEnd - dest; + src--; + res = mErrEncoder->Convert(*src, dest, &bcw); + dest += bcw; + // if enought output space then the last char was used + if (res != NS_OK_UENC_MOREOUTPUT) src++; + if (res != NS_OK) break; + } else break; + } + else break; + } + + *aSrcLength -= srcEnd - src; + *aDestLength -= destEnd - dest; + return res; +} + +NS_IMETHODIMP nsEncoderSupport::FinishNoBuff(char * aDest, + PRInt32 * aDestLength) +{ + *aDestLength = 0; + return NS_OK; +} + +nsresult nsEncoderSupport::FlushBuffer(char ** aDest, const char * aDestEnd) +{ + PRInt32 bcr, bcw; // byte counts for read & write; + nsresult res = NS_OK; + char * dest = *aDest; + + if (mBufferStart < mBufferEnd) { + bcr = mBufferEnd - mBufferStart; + bcw = aDestEnd - dest; + if (bcw < bcr) bcr = bcw; + memcpy(dest, mBufferStart, bcr); + dest += bcr; + mBufferStart += bcr; + + if (mBufferStart < mBufferEnd) res = NS_OK_UENC_MOREOUTPUT; + } + + *aDest = dest; + return res; +} + + +//---------------------------------------------------------------------- +// Interface nsIUnicodeEncoder [implementation] + +NS_IMETHODIMP nsEncoderSupport::Convert(const PRUnichar * aSrc, + PRInt32 * aSrcLength, + char * aDest, + PRInt32 * aDestLength) +{ + // we do all operations using pointers internally + const PRUnichar * src = aSrc; + const PRUnichar * srcEnd = aSrc + *aSrcLength; + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + + PRInt32 bcr, bcw; // byte counts for read & write; + nsresult res; + + res = FlushBuffer(&dest, destEnd); + if (res == NS_OK_UENC_MOREOUTPUT) goto final; + + bcr = srcEnd - src; + bcw = destEnd - dest; + res = ConvertNoBuff(src, &bcr, dest, &bcw); + src += bcr; + dest += bcw; + if ((res == NS_OK_UENC_MOREOUTPUT) && (dest < destEnd)) { + // convert exactly one character into the internal buffer + // at this point, there should be at least a char in the input + for (;;) { + bcr = 1; + bcw = mBufferCapacity; + res = ConvertNoBuff(src, &bcr, mBuffer, &bcw); + + if (res == NS_OK_UENC_MOREOUTPUT) { + delete [] mBuffer; + mBufferCapacity *= 2; + mBuffer = new char [mBufferCapacity]; + } else { + src += bcr; + mBufferStart = mBufferEnd = mBuffer; + mBufferEnd += bcw; + break; + } + } + + res = FlushBuffer(&dest, destEnd); + } + +final: + *aSrcLength -= srcEnd - src; + *aDestLength -= destEnd - dest; + return res; +} + +NS_IMETHODIMP nsEncoderSupport::Finish(char * aDest, PRInt32 * aDestLength) +{ + // we do all operations using pointers internally + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + + PRInt32 bcw; // byte count for write; + nsresult res; + + res = FlushBuffer(&dest, destEnd); + if (res == NS_OK_UENC_MOREOUTPUT) goto final; + + // do the finish into the internal buffer. + for (;;) { + bcw = mBufferCapacity; + res = FinishNoBuff(mBuffer, &bcw); + + if (res == NS_OK_UENC_MOREOUTPUT) { + delete [] mBuffer; + mBufferCapacity *= 2; + mBuffer = new char [mBufferCapacity]; + } else { + mBufferStart = mBufferEnd = mBuffer; + mBufferEnd += bcw; + break; + } + } + + res = FlushBuffer(&dest, destEnd); + +final: + *aDestLength -= destEnd - dest; + return res; +} + +NS_IMETHODIMP nsEncoderSupport::Reset() +{ + mBufferStart = mBufferEnd = mBuffer; + return NS_OK; +} + +NS_IMETHODIMP nsEncoderSupport::SetOutputErrorBehavior( + PRInt32 aBehavior, + nsIUnicharEncoder * aEncoder, + PRUnichar aChar) +{ + if (aBehavior == kOnError_CallBack && aEncoder == nsnull) + return NS_ERROR_NULL_POINTER; + + mErrEncoder = aEncoder; + mErrBehavior = aBehavior; + mErrChar = aChar; + return NS_OK; +} + +NS_IMETHODIMP +nsEncoderSupport::GetMaxLength(const PRUnichar * aSrc, + PRInt32 aSrcLength, + PRInt32 * aDestLength) +{ + *aDestLength = aSrcLength * mMaxLengthFactor; + return NS_OK; +} diff --git a/mailnews/mime/src/nsUCvMimeSupport.h b/mailnews/mime/src/nsUCvMimeSupport.h new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUCvMimeSupport.h @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUCvMimeSupport_h___ +#define nsUCvMimeSupport_h___ + +#include "nsCOMPtr.h" +#include "nsIUnicodeEncoder.h" +#include "nsIUnicodeDecoder.h" +#include "uconvutil.h" +#include "mozilla/Mutex.h" + +//---------------------------------------------------------------------- +// Class nsBasicDecoderSupport [declaration] + +/** + * Support class for the Unicode decoders. + * + * This class implements: + * - nsISupports + * - nsIUnicodeDecoder + * + * @created 19/Apr/1999 + * @author Catalin Rotaru [CATA] + */ +class nsBasicDecoderSupport : public nsIUnicodeDecoder +{ + NS_DECL_ISUPPORTS + +public: + + /** + * Class constructor. + */ + nsBasicDecoderSupport(); + + /** + * Class destructor. + */ + virtual ~nsBasicDecoderSupport(); + + //-------------------------------------------------------------------- + // Interface nsIUnicodeDecoder [declaration] + + virtual void SetInputErrorBehavior(PRInt32 aBehavior); + virtual PRUnichar GetCharacterForUnMapped(); + +protected: + PRInt32 mErrBehavior; +}; + +//---------------------------------------------------------------------- +// Class nsBufferDecoderSupport [declaration] + +/** + * Support class for the Unicode decoders. + * + * This class implements: + * - the buffer management + * + * @created 15/Mar/1999 + * @author Catalin Rotaru [CATA] + */ +class nsBufferDecoderSupport : public nsBasicDecoderSupport +{ +protected: + + /** + * Internal buffer for partial conversions. + */ + char * mBuffer; + PRInt32 mBufferCapacity; + PRInt32 mBufferLength; + + PRUint32 mMaxLengthFactor; + + /** + * Convert method but *without* the buffer management stuff. + */ + NS_IMETHOD ConvertNoBuff(const char * aSrc, PRInt32 * aSrcLength, + PRUnichar * aDest, PRInt32 * aDestLength) = 0; + + void FillBuffer(const char ** aSrc, PRInt32 aSrcLength); + +public: + + /** + * Class constructor. + */ + nsBufferDecoderSupport(PRUint32 aMaxLengthFactor); + + /** + * Class destructor. + */ + virtual ~nsBufferDecoderSupport(); + + //-------------------------------------------------------------------- + // Interface nsIUnicodeDecoder [declaration] + + NS_IMETHOD Convert(const char * aSrc, PRInt32 * aSrcLength, + PRUnichar * aDest, PRInt32 * aDestLength); + NS_IMETHOD Reset(); + NS_IMETHOD GetMaxLength(const char *aSrc, + PRInt32 aSrcLength, + PRInt32* aDestLength); +}; + +//---------------------------------------------------------------------- +// Class nsBasicEncoder [declaration] + +class nsBasicEncoder : public nsIUnicodeEncoder +{ + NS_DECL_ISUPPORTS + +public: + /** + * Class constructor. + */ + nsBasicEncoder(); + + /** + * Class destructor. + */ + virtual ~nsBasicEncoder(); + +}; +//---------------------------------------------------------------------- +// Class nsEncoderSupport [declaration] + +/** + * Support class for the Unicode encoders. + * + * This class implements: + * - nsISupports + * - the buffer management + * - error handling procedure(s) + * + * @created 17/Feb/1999 + * @author Catalin Rotaru [CATA] + */ +class nsEncoderSupport : public nsBasicEncoder +{ + +protected: + + /** + * Internal buffer for partial conversions. + */ + char * mBuffer; + PRInt32 mBufferCapacity; + char * mBufferStart; + char * mBufferEnd; + + /** + * Error handling stuff + */ + PRInt32 mErrBehavior; + nsCOMPtr mErrEncoder; + PRUnichar mErrChar; + PRUint32 mMaxLengthFactor; + + /** + * Convert method but *without* the buffer management stuff and *with* + * error handling stuff. + */ + NS_IMETHOD ConvertNoBuff(const PRUnichar * aSrc, PRInt32 * aSrcLength, + char * aDest, PRInt32 * aDestLength); + + /** + * Convert method but *without* the buffer management stuff and *without* + * error handling stuff. + */ + NS_IMETHOD ConvertNoBuffNoErr(const PRUnichar * aSrc, PRInt32 * aSrcLength, + char * aDest, PRInt32 * aDestLength) = 0; + + /** + * Finish method but *without* the buffer management stuff. + */ + NS_IMETHOD FinishNoBuff(char * aDest, PRInt32 * aDestLength); + + /** + * Copy as much as possible from the internal buffer to the destination. + */ + nsresult FlushBuffer(char ** aDest, const char * aDestEnd); + +public: + + /** + * Class constructor. + */ + nsEncoderSupport(PRUint32 aMaxLengthFactor); + + /** + * Class destructor. + */ + virtual ~nsEncoderSupport(); + + //-------------------------------------------------------------------- + // Interface nsIUnicodeEncoder [declaration] + + NS_IMETHOD Convert(const PRUnichar * aSrc, PRInt32 * aSrcLength, + char * aDest, PRInt32 * aDestLength); + NS_IMETHOD Finish(char * aDest, PRInt32 * aDestLength); + NS_IMETHOD Reset(); + NS_IMETHOD SetOutputErrorBehavior(PRInt32 aBehavior, + nsIUnicharEncoder * aEncoder, PRUnichar aChar); + NS_IMETHOD GetMaxLength(const PRUnichar * aSrc, + PRInt32 aSrcLength, + PRInt32 * aDestLength); +}; + +#endif /* nsUCvMimeSupport_h___ */ diff --git a/mailnews/mime/src/nsUTF7ToUnicode.cpp b/mailnews/mime/src/nsUTF7ToUnicode.cpp new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUTF7ToUnicode.cpp @@ -0,0 +1,262 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsUTF7ToUnicode.h" + +#define ENC_DIRECT 0 +#define ENC_BASE64 1 + +//---------------------------------------------------------------------- +// Class nsBasicUTF7Decoder [implementation] + +nsBasicUTF7Decoder::nsBasicUTF7Decoder(char aLastChar, char aEscChar) +: nsBufferDecoderSupport(1) +{ + mLastChar = aLastChar; + mEscChar = aEscChar; + Reset(); +} + +nsresult nsBasicUTF7Decoder::DecodeDirect( + const char * aSrc, + PRInt32 * aSrcLength, + PRUnichar * aDest, + PRInt32 * aDestLength) +{ + const char * srcEnd = aSrc + *aSrcLength; + const char * src = aSrc; + PRUnichar * destEnd = aDest + *aDestLength; + PRUnichar * dest = aDest; + nsresult res = NS_OK; + char ch; + + while (src < srcEnd) { + ch = *src; + + // stop when we meet other chars or end of direct encoded seq. + // if (!(DirectEncodable(ch)) || (ch == mEscChar)) { + // but we are decoding; so we should be lax; pass everything until escchar + if (ch == mEscChar) { + res = NS_ERROR_UDEC_ILLEGALINPUT; + break; + } + + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } else { + *dest++ = ch; + src++; + } + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +nsresult nsBasicUTF7Decoder::DecodeBase64( + const char * aSrc, + PRInt32 * aSrcLength, + PRUnichar * aDest, + PRInt32 * aDestLength) +{ + const char * srcEnd = aSrc + *aSrcLength; + const char * src = aSrc; + PRUnichar * destEnd = aDest + *aDestLength; + PRUnichar * dest = aDest; + nsresult res = NS_OK; + char ch; + PRUint32 value; + + while (src < srcEnd) { + ch = *src; + + // stop when we meet other chars or end of direct encoded seq. + value = CharToValue(ch); + if (value > 0xff) { + res = NS_ERROR_UDEC_ILLEGALINPUT; + break; + } + + switch (mEncStep) { + case 0: + mEncBits = value << 10; + break; + case 1: + mEncBits += value << 4; + break; + case 2: + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + mEncBits += value >> 2; + *(dest++) = (PRUnichar) mEncBits; + mEncBits = (value & 0x03) << 14; + break; + case 3: + mEncBits += value << 8; + break; + case 4: + mEncBits += value << 2; + break; + case 5: + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + mEncBits += value >> 4; + *(dest++) = (PRUnichar) mEncBits; + mEncBits = (value & 0x0f) << 12; + break; + case 6: + mEncBits += value << 6; + break; + case 7: + if (dest >= destEnd) { + res = NS_OK_UDEC_MOREOUTPUT; + break; + } + mEncBits += value; + *(dest++) = (PRUnichar) mEncBits; + mEncBits = 0; + break; + } + + if (res != NS_OK) break; + + src++; + (++mEncStep)%=8; + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +PRUint32 nsBasicUTF7Decoder::CharToValue(char aChar) { + if ((aChar>='A')&&(aChar<='Z')) + return (PRUint8)(aChar-'A'); + else if ((aChar>='a')&&(aChar<='z')) + return (PRUint8)(26+aChar-'a'); + else if ((aChar>='0')&&(aChar<='9')) + return (PRUint8)(26+26+aChar-'0'); + else if (aChar=='+') + return (PRUint8)(26+26+10); + else if (aChar==mLastChar) + return (PRUint8)(26+26+10+1); + else + return 0xffff; +} + +//---------------------------------------------------------------------- +// Subclassing of nsBufferDecoderSupport class [implementation] + +NS_IMETHODIMP nsBasicUTF7Decoder::ConvertNoBuff(const char * aSrc, + PRInt32 * aSrcLength, + PRUnichar * aDest, + PRInt32 * aDestLength) +{ + const char * srcEnd = aSrc + *aSrcLength; + const char * src = aSrc; + PRUnichar * destEnd = aDest + *aDestLength; + PRUnichar * dest = aDest; + PRInt32 bcr,bcw; + nsresult res = NS_OK; + char ch; + + while (src < srcEnd) { + ch = *src; + + // fist, attept to decode in the current mode + bcr = srcEnd - src; + bcw = destEnd - dest; + if (mEncoding == ENC_DIRECT) + res = DecodeDirect(src, &bcr, dest, &bcw); + else if ((mFreshBase64) && (*src == '-')) { + *dest = mEscChar; + bcr = 0; + bcw = 1; + res = NS_ERROR_UDEC_ILLEGALINPUT; + } else { + mFreshBase64 = PR_FALSE; + res = DecodeBase64(src, &bcr, dest, &bcw); + } + src += bcr; + dest += bcw; + + // if an illegal char was encountered, test if it is an escape seq. + if (res == NS_ERROR_UDEC_ILLEGALINPUT) { + if (mEncoding == ENC_DIRECT) { + if (*src == mEscChar) { + mEncoding = ENC_BASE64; + mFreshBase64 = PR_TRUE; + mEncBits = 0; + mEncStep = 0; + src++; + res = NS_OK; + } else break; + } else { + mEncoding = ENC_DIRECT; + res = NS_OK; + // absorbe end of escape sequence + if (*src == '-') src++; + } + } else if (res != NS_OK) break; + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +NS_IMETHODIMP nsBasicUTF7Decoder::Reset() +{ + mEncoding = ENC_DIRECT; + mEncBits = 0; + mEncStep = 0; + return nsBufferDecoderSupport::Reset(); +} + +//---------------------------------------------------------------------- +// Class nsUTF7ToUnicode [implementation] + +nsUTF7ToUnicode::nsUTF7ToUnicode() +: nsBasicUTF7Decoder('/', '+') +{ +} diff --git a/mailnews/mime/src/nsUTF7ToUnicode.h b/mailnews/mime/src/nsUTF7ToUnicode.h new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUTF7ToUnicode.h @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUTF7ToUnicode_h___ +#define nsUTF7ToUnicode_h___ + +#include "nsUCvMimeSupport.h" + +//---------------------------------------------------------------------- +// Class nsBasicUTF7Decoder [declaration] + +/** + * Basic class for a character set converter from UTF-7 to Unicode. + * + * @created 03/Jun/1999 + * @author Catalin Rotaru [CATA] + */ +class nsBasicUTF7Decoder : public nsBufferDecoderSupport +{ +public: + + /** + * Class constructor. + */ + nsBasicUTF7Decoder(char aLastChar, char aEscChar); + +protected: + + PRInt32 mEncoding; // current encoding + PRUint32 mEncBits; + PRInt32 mEncStep; + char mLastChar; + char mEscChar; + PRBool mFreshBase64; + + nsresult DecodeDirect(const char * aSrc, PRInt32 * aSrcLength, + PRUnichar * aDest, PRInt32 * aDestLength); + nsresult DecodeBase64(const char * aSrc, PRInt32 * aSrcLength, + PRUnichar * aDest, PRInt32 * aDestLength); + PRUint32 CharToValue(char aChar); + + //-------------------------------------------------------------------- + // Subclassing of nsBufferDecoderSupport class [declaration] + + NS_IMETHOD ConvertNoBuff(const char * aSrc, PRInt32 * aSrcLength, + PRUnichar * aDest, PRInt32 * aDestLength); + NS_IMETHOD Reset(); +}; + +//---------------------------------------------------------------------- +// Class nsUTF7ToUnicode [declaration] + +/** + * A character set converter from Modified UTF7 to Unicode. + * + * @created 18/May/1999 + * @author Catalin Rotaru [CATA] + */ +class nsUTF7ToUnicode : public nsBasicUTF7Decoder +{ +public: + + /** + * Class constructor. + */ + nsUTF7ToUnicode(); + +}; + +#endif /* nsUTF7ToUnicode_h___ */ diff --git a/mailnews/mime/src/nsUnicodeToMUTF7.cpp b/mailnews/mime/src/nsUnicodeToMUTF7.cpp new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUnicodeToMUTF7.cpp @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsUnicodeToMUTF7.h" + +//---------------------------------------------------------------------- +// Class nsUnicodeToMUTF7 [implementation] + +nsUnicodeToMUTF7::nsUnicodeToMUTF7() +: nsBasicUTF7Encoder(',', '&') +{ +} diff --git a/mailnews/mime/src/nsUnicodeToMUTF7.h b/mailnews/mime/src/nsUnicodeToMUTF7.h new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUnicodeToMUTF7.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUnicodeToMUTF7_h___ +#define nsUnicodeToMUTF7_h___ + +#include "nsUnicodeToUTF7.h" + +//---------------------------------------------------------------------- +// Class nsUnicodeToMUTF7 [declaration] + +/** + * A character set converter from Unicode to Modified UTF-7. + * + * @created 18/May/1999 + * @author Catalin Rotaru [CATA] + */ +class nsUnicodeToMUTF7 : public nsBasicUTF7Encoder +{ +public: + + /** + * Class constructor. + */ + nsUnicodeToMUTF7(); + +}; + +#endif /* nsUnicodeToMUTF7_h___ */ diff --git a/mailnews/mime/src/nsUnicodeToUTF7.cpp b/mailnews/mime/src/nsUnicodeToUTF7.cpp new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUnicodeToUTF7.cpp @@ -0,0 +1,330 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsUnicodeToUTF7.h" +#include + +//---------------------------------------------------------------------- +// Global functions and data [declaration] + +#define ENC_DIRECT 0 +#define ENC_BASE64 1 + +//---------------------------------------------------------------------- +// Class nsBasicUTF7Encoder [implementation] + +nsBasicUTF7Encoder::nsBasicUTF7Encoder(char aLastChar, char aEscChar) +: nsEncoderSupport(5) +{ + mLastChar = aLastChar; + mEscChar = aEscChar; + Reset(); +} + +nsresult nsBasicUTF7Encoder::ShiftEncoding(PRInt32 aEncoding, + char * aDest, + PRInt32 * aDestLength) +{ + if (aEncoding == mEncoding) { + *aDestLength = 0; + return NS_OK; + } + + nsresult res = NS_OK; + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + + if (mEncStep != 0) { + if (dest >= destEnd) return NS_OK_UENC_MOREOUTPUT; + *(dest++)=ValueToChar(mEncBits); + mEncStep = 0; + mEncBits = 0; + } + + if (dest >= destEnd) { + res = NS_OK_UENC_MOREOUTPUT; + } else { + switch (aEncoding) { + case 0: + *(dest++) = '-'; + mEncStep = 0; + mEncBits = 0; + break; + case 1: + *(dest++) = mEscChar; + break; + } + mEncoding = aEncoding; + } + + *aDestLength = dest - aDest; + return res; +} + +nsresult nsBasicUTF7Encoder::EncodeDirect( + const PRUnichar * aSrc, + PRInt32 * aSrcLength, + char * aDest, + PRInt32 * aDestLength) +{ + nsresult res = NS_OK; + const PRUnichar * src = aSrc; + const PRUnichar * srcEnd = aSrc + *aSrcLength; + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + PRUnichar ch; + + while (src < srcEnd) { + ch = *src; + + // stop when we reach Unicode chars + if (!DirectEncodable(ch)) break; + + if (ch == mEscChar) { + // special case for the escape char + if (destEnd - dest < 1) { + res = NS_OK_UENC_MOREOUTPUT; + break; + } else { + *dest++ = (char)ch; + *dest++ = (char)'-'; + src++; + } + } else { + //classic direct encoding + if (dest >= destEnd) { + res = NS_OK_UENC_MOREOUTPUT; + break; + } else { + *dest++ = (char)ch; + src++; + } + } + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +nsresult nsBasicUTF7Encoder::EncodeBase64( + const PRUnichar * aSrc, + PRInt32 * aSrcLength, + char * aDest, + PRInt32 * aDestLength) +{ + nsresult res = NS_OK; + const PRUnichar * src = aSrc; + const PRUnichar * srcEnd = aSrc + *aSrcLength; + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + PRUnichar ch; + PRUint32 value; + + while (src < srcEnd) { + ch = *src; + + // stop when we reach printable US-ASCII chars + if (DirectEncodable(ch)) break; + + switch (mEncStep) { + case 0: + if (destEnd - dest < 2) { + res = NS_OK_UENC_MOREOUTPUT; + break; + } + value=ch>>10; + *(dest++)=ValueToChar(value); + value=(ch>>4)&0x3f; + *(dest++)=ValueToChar(value); + mEncBits=(ch&0x0f)<<2; + break; + case 1: + if (destEnd - dest < 3) { + res = NS_OK_UENC_MOREOUTPUT; + break; + } + value=mEncBits+(ch>>14); + *(dest++)=ValueToChar(value); + value=(ch>>8)&0x3f; + *(dest++)=ValueToChar(value); + value=(ch>>2)&0x3f; + *(dest++)=ValueToChar(value); + mEncBits=(ch&0x03)<<4; + break; + case 2: + if (destEnd - dest < 3) { + res = NS_OK_UENC_MOREOUTPUT; + break; + } + value=mEncBits+(ch>>12); + *(dest++)=ValueToChar(value); + value=(ch>>6)&0x3f; + *(dest++)=ValueToChar(value); + value=ch&0x3f; + *(dest++)=ValueToChar(value); + mEncBits=0; + break; + } + + if (res != NS_OK) break; + + src++; + (++mEncStep)%=3; + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +char nsBasicUTF7Encoder::ValueToChar(PRUint32 aValue) { + if (aValue < 26) + return (char)('A'+aValue); + else if (aValue < 26 + 26) + return (char)('a' + aValue - 26); + else if (aValue < 26 + 26 + 10) + return (char)('0' + aValue - 26 - 26); + else if (aValue == 26 + 26 + 10) + return '+'; + else if (aValue == 26 + 26 + 10 + 1) + return mLastChar; + else + return -1; +} + +PRBool nsBasicUTF7Encoder::DirectEncodable(PRUnichar aChar) { + // spec says: printable US-ASCII chars + if ((aChar >= 0x20) && (aChar <= 0x7e)) return PR_TRUE; + else return PR_FALSE; +} + +//---------------------------------------------------------------------- +// Subclassing of nsEncoderSupport class [implementation] + +NS_IMETHODIMP nsBasicUTF7Encoder::ConvertNoBuffNoErr( + const PRUnichar * aSrc, + PRInt32 * aSrcLength, + char * aDest, + PRInt32 * aDestLength) +{ + nsresult res = NS_OK; + const PRUnichar * src = aSrc; + const PRUnichar * srcEnd = aSrc + *aSrcLength; + char * dest = aDest; + char * destEnd = aDest + *aDestLength; + PRInt32 bcr,bcw; + PRUnichar ch; + PRInt32 enc; + + while (src < srcEnd) { + // find the encoding for the next char + ch = *src; + if (DirectEncodable(ch)) + enc = ENC_DIRECT; + else + enc = ENC_BASE64; + + // if necessary, shift into the required encoding + bcw = destEnd - dest; + res = ShiftEncoding(enc, dest, &bcw); + dest += bcw; + if (res != NS_OK) break; + + // now encode (as much as you can) + bcr = srcEnd - src; + bcw = destEnd - dest; + if (enc == ENC_DIRECT) + res = EncodeDirect(src, &bcr, dest, &bcw); + else + res = EncodeBase64(src, &bcr, dest, &bcw); + src += bcr; + dest += bcw; + + if (res != NS_OK) break; + } + + *aSrcLength = src - aSrc; + *aDestLength = dest - aDest; + return res; +} + +NS_IMETHODIMP nsBasicUTF7Encoder::FinishNoBuff(char * aDest, + PRInt32 * aDestLength) +{ + return ShiftEncoding(ENC_DIRECT, aDest, aDestLength); +} + +NS_IMETHODIMP nsBasicUTF7Encoder::Reset() +{ + mEncoding = ENC_DIRECT; + mEncBits = 0; + mEncStep = 0; + return nsEncoderSupport::Reset(); +} + +//---------------------------------------------------------------------- +// Class nsUnicodeToUTF7 [implementation] + +nsUnicodeToUTF7::nsUnicodeToUTF7() +: nsBasicUTF7Encoder('/', '+') +{ +} + + +PRBool nsUnicodeToUTF7::DirectEncodable(PRUnichar aChar) { + if ((aChar >= 'A') && (aChar <= 'Z')) return PR_TRUE; + else if ((aChar >= 'a') && (aChar <= 'z')) return PR_TRUE; + else if ((aChar >= '0') && (aChar <= '9')) return PR_TRUE; + else if ((aChar >= 39) && (aChar <= 41)) return PR_TRUE; + else if ((aChar >= 44) && (aChar <= 47)) return PR_TRUE; + else if (aChar == 58) return PR_TRUE; + else if (aChar == 63) return PR_TRUE; + else if (aChar == ' ') return PR_TRUE; + else if (aChar == 9) return PR_TRUE; + else if (aChar == 13) return PR_TRUE; + else if (aChar == 10) return PR_TRUE; + else if (aChar == 60) return PR_TRUE; // '<' + else if (aChar == 33) return PR_TRUE; // '!' + else if (aChar == 34) return PR_TRUE; // '"' + else if (aChar == 62) return PR_TRUE; // '>' + else if (aChar == 61) return PR_TRUE; // '=' + else if (aChar == 59) return PR_TRUE; // ';' + else if (aChar == 91) return PR_TRUE; // '[' + else if (aChar == 93) return PR_TRUE; // ']' + else return PR_FALSE; +} diff --git a/mailnews/mime/src/nsUnicodeToUTF7.h b/mailnews/mime/src/nsUnicodeToUTF7.h new file mode 100644 --- /dev/null +++ b/mailnews/mime/src/nsUnicodeToUTF7.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Communicator client code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef nsUnicodeToUTF7_h___ +#define nsUnicodeToUTF7_h___ + +#include "nsUCvMimeSupport.h" + +//---------------------------------------------------------------------- +// Class nsBasicUTF7Encoder [declaration] + +/** + * Basic class for a character set converter from Unicode to UTF-7. + * + * @created 03/Jun/1999 + * @author Catalin Rotaru [CATA] + */ +class nsBasicUTF7Encoder : public nsEncoderSupport +{ +public: + + /** + * Class constructor. + */ + nsBasicUTF7Encoder(char aLastChar, char aEscChar); + +protected: + + PRInt32 mEncoding; // current encoding + PRUint32 mEncBits; + PRInt32 mEncStep; + char mLastChar; + char mEscChar; + + nsresult ShiftEncoding(PRInt32 aEncoding, char * aDest, + PRInt32 * aDestLength); + nsresult EncodeDirect(const PRUnichar * aSrc, PRInt32 * aSrcLength, + char * aDest, PRInt32 * aDestLength); + nsresult EncodeBase64(const PRUnichar * aSrc, PRInt32 * aSrcLength, + char * aDest, PRInt32 * aDestLength); + char ValueToChar(PRUint32 aValue); + virtual PRBool DirectEncodable(PRUnichar aChar); + + //-------------------------------------------------------------------- + // Subclassing of nsEncoderSupport class [declaration] + + NS_IMETHOD ConvertNoBuffNoErr(const PRUnichar * aSrc, PRInt32 * aSrcLength, + char * aDest, PRInt32 * aDestLength); + NS_IMETHOD FinishNoBuff(char * aDest, PRInt32 * aDestLength); + NS_IMETHOD Reset(); +}; + +//---------------------------------------------------------------------- +// Class nsUnicodeToUTF7 [declaration] + +/** + * A character set converter from Unicode to UTF-7. + * + * @created 03/Jun/1999 + * @author Catalin Rotaru [CATA] + */ +class nsUnicodeToUTF7 : public nsBasicUTF7Encoder +{ +public: + + /** + * Class constructor. + */ + nsUnicodeToUTF7(); + +protected: + + virtual PRBool DirectEncodable(PRUnichar aChar); +}; + +#endif /* nsUnicodeToUTF7_h___ */