Back to index

lightning-sunbird  0.9+nobinonly
nsUnicodeToUTF7.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsUnicodeToUTF7.h"
00039 #include <string.h>
00040 
00041 //----------------------------------------------------------------------
00042 // Global functions and data [declaration]
00043 
00044 #define ENC_DIRECT      0
00045 #define ENC_BASE64      1
00046 
00047 //----------------------------------------------------------------------
00048 // Class nsBasicUTF7Encoder [implementation]
00049 
00050 nsBasicUTF7Encoder::nsBasicUTF7Encoder(char aLastChar, char aEscChar) 
00051 : nsEncoderSupport(5)
00052 {
00053   mLastChar = aLastChar;
00054   mEscChar = aEscChar;
00055   Reset();
00056 }
00057 
00058 NS_IMETHODIMP nsBasicUTF7Encoder::FillInfo(PRUint32 *aInfo)
00059 {
00060   memset(aInfo, 0xFF, (0x10000L >> 3));
00061   return NS_OK;
00062 }
00063 
00064 nsresult nsBasicUTF7Encoder::ShiftEncoding(PRInt32 aEncoding,
00065                                           char * aDest, 
00066                                           PRInt32 * aDestLength)
00067 {
00068   if (aEncoding == mEncoding) {
00069     *aDestLength = 0;
00070     return NS_OK;
00071   } 
00072 
00073   nsresult res = NS_OK;
00074   char * dest = aDest;
00075   char * destEnd = aDest + *aDestLength;
00076 
00077   if (mEncStep != 0) {
00078     if (dest >= destEnd) return NS_OK_UENC_MOREOUTPUT;
00079     *(dest++)=ValueToChar(mEncBits);
00080     mEncStep = 0;
00081     mEncBits = 0;
00082   }
00083 
00084   if (dest >= destEnd) {
00085     res = NS_OK_UENC_MOREOUTPUT;
00086   } else {
00087     switch (aEncoding) {
00088       case 0:
00089         *(dest++) = '-';
00090         mEncStep = 0;
00091         mEncBits = 0;
00092         break;
00093       case 1:
00094         *(dest++) = mEscChar;
00095         break;
00096     }
00097     mEncoding = aEncoding;
00098   }
00099 
00100   *aDestLength  = dest - aDest;
00101   return res;
00102 }
00103 
00104 nsresult nsBasicUTF7Encoder::EncodeDirect(
00105                             const PRUnichar * aSrc, 
00106                             PRInt32 * aSrcLength, 
00107                             char * aDest, 
00108                             PRInt32 * aDestLength)
00109 {
00110   nsresult res = NS_OK;
00111   const PRUnichar * src = aSrc;
00112   const PRUnichar * srcEnd = aSrc + *aSrcLength;
00113   char * dest = aDest;
00114   char * destEnd = aDest + *aDestLength;
00115   PRUnichar ch;
00116 
00117   while (src < srcEnd) {
00118     ch = *src;
00119 
00120     // stop when we reach Unicode chars
00121     if (!DirectEncodable(ch)) break;
00122 
00123     if (ch == mEscChar) {
00124       // special case for the escape char
00125       if (destEnd - dest < 1) {
00126         res = NS_OK_UENC_MOREOUTPUT;
00127         break;
00128       } else {
00129         *dest++ = (char)ch;
00130         *dest++ = (char)'-';
00131         src++;
00132       }
00133     } else {
00134       //classic direct encoding
00135       if (dest >= destEnd) {
00136         res = NS_OK_UENC_MOREOUTPUT;
00137         break;
00138       } else {
00139         *dest++ = (char)ch;
00140         src++;
00141       }
00142     }
00143   }
00144 
00145   *aSrcLength = src - aSrc;
00146   *aDestLength  = dest - aDest;
00147   return res;
00148 }
00149 
00150 nsresult nsBasicUTF7Encoder::EncodeBase64(
00151                              const PRUnichar * aSrc, 
00152                              PRInt32 * aSrcLength, 
00153                              char * aDest, 
00154                              PRInt32 * aDestLength)
00155 {
00156   nsresult res = NS_OK;
00157   const PRUnichar * src = aSrc;
00158   const PRUnichar * srcEnd = aSrc + *aSrcLength;
00159   char * dest = aDest;
00160   char * destEnd = aDest + *aDestLength;
00161   PRUnichar ch;
00162   PRUint32 value;
00163 
00164   while (src < srcEnd) {
00165     ch = *src;
00166 
00167     // stop when we reach printable US-ASCII chars
00168     if (DirectEncodable(ch)) break;
00169 
00170     switch (mEncStep) {
00171       case 0:
00172         if (destEnd - dest < 2) {
00173           res = NS_OK_UENC_MOREOUTPUT;
00174           break;
00175         }
00176         value=ch>>10;
00177         *(dest++)=ValueToChar(value);
00178         value=(ch>>4)&0x3f;
00179         *(dest++)=ValueToChar(value);
00180         mEncBits=(ch&0x0f)<<2;
00181         break;
00182       case 1:
00183         if (destEnd - dest < 3) {
00184           res = NS_OK_UENC_MOREOUTPUT;
00185           break;
00186         }
00187         value=mEncBits+(ch>>14);
00188         *(dest++)=ValueToChar(value);
00189         value=(ch>>8)&0x3f;
00190         *(dest++)=ValueToChar(value);
00191         value=(ch>>2)&0x3f;
00192         *(dest++)=ValueToChar(value);
00193         mEncBits=(ch&0x03)<<4;
00194         break;
00195       case 2:
00196         if (destEnd - dest < 3) {
00197           res = NS_OK_UENC_MOREOUTPUT;
00198           break;
00199         }
00200         value=mEncBits+(ch>>12);
00201         *(dest++)=ValueToChar(value);
00202         value=(ch>>6)&0x3f;
00203         *(dest++)=ValueToChar(value);
00204         value=ch&0x3f;
00205         *(dest++)=ValueToChar(value);
00206         mEncBits=0;
00207         break;
00208     }
00209 
00210     if (res != NS_OK) break;
00211 
00212     src++;
00213     (++mEncStep)%=3;
00214   }
00215 
00216   *aSrcLength = src - aSrc;
00217   *aDestLength  = dest - aDest;
00218   return res;
00219 }
00220 
00221 char nsBasicUTF7Encoder::ValueToChar(PRUint32 aValue) { 
00222   if (aValue < 26) 
00223     return (char)('A'+aValue);
00224   else if (aValue < 26 + 26) 
00225     return (char)('a' + aValue - 26);
00226   else if (aValue < 26 + 26 + 10)
00227     return (char)('0' + aValue - 26 - 26);
00228   else if (aValue == 26 + 26 + 10)
00229     return '+';
00230   else if (aValue == 26 + 26 + 10 + 1)
00231     return mLastChar;
00232   else
00233     return -1;
00234 }
00235 
00236 PRBool nsBasicUTF7Encoder::DirectEncodable(PRUnichar aChar) {
00237   // spec says: printable US-ASCII chars
00238   if ((aChar >= 0x20) && (aChar <= 0x7e)) return PR_TRUE;
00239   else return PR_FALSE;
00240 }
00241 
00242 //----------------------------------------------------------------------
00243 // Subclassing of nsEncoderSupport class [implementation]
00244 
00245 NS_IMETHODIMP nsBasicUTF7Encoder::ConvertNoBuffNoErr(
00246                                   const PRUnichar * aSrc, 
00247                                   PRInt32 * aSrcLength, 
00248                                   char * aDest, 
00249                                   PRInt32 * aDestLength)
00250 {
00251   nsresult res = NS_OK;
00252   const PRUnichar * src = aSrc;
00253   const PRUnichar * srcEnd = aSrc + *aSrcLength;
00254   char * dest = aDest;
00255   char * destEnd = aDest + *aDestLength;
00256   PRInt32 bcr,bcw;
00257   PRUnichar ch;
00258   PRInt32 enc;
00259 
00260   while (src < srcEnd) {
00261     // find the encoding for the next char
00262     ch = *src;
00263     if (DirectEncodable(ch)) 
00264       enc = ENC_DIRECT;
00265     else
00266       enc = ENC_BASE64;
00267 
00268     // if necessary, shift into the required encoding
00269     bcw = destEnd - dest;
00270     res = ShiftEncoding(enc, dest, &bcw);
00271     dest += bcw;
00272     if (res != NS_OK) break;
00273 
00274     // now encode (as much as you can)
00275     bcr = srcEnd - src;
00276     bcw = destEnd - dest;
00277     if (enc == ENC_DIRECT) 
00278       res = EncodeDirect(src, &bcr, dest, &bcw);
00279     else 
00280       res = EncodeBase64(src, &bcr, dest, &bcw);
00281     src += bcr;
00282     dest += bcw;
00283 
00284     if (res != NS_OK) break;
00285   }
00286 
00287   *aSrcLength = src - aSrc;
00288   *aDestLength  = dest - aDest;
00289   return res;
00290 }
00291 
00292 NS_IMETHODIMP nsBasicUTF7Encoder::FinishNoBuff(char * aDest, 
00293                                                PRInt32 * aDestLength)
00294 {
00295   return ShiftEncoding(ENC_DIRECT, aDest, aDestLength);
00296 }
00297 
00298 NS_IMETHODIMP nsBasicUTF7Encoder::Reset()
00299 {
00300   mEncoding = ENC_DIRECT;
00301   mEncBits = 0;
00302   mEncStep = 0;
00303   return nsEncoderSupport::Reset();
00304 }
00305 
00306 //----------------------------------------------------------------------
00307 // Class nsUnicodeToUTF7 [implementation]
00308 
00309 nsUnicodeToUTF7::nsUnicodeToUTF7() 
00310 : nsBasicUTF7Encoder('/', '+')
00311 {
00312 }
00313 
00314 
00315 PRBool nsUnicodeToUTF7::DirectEncodable(PRUnichar aChar) {
00316   if ((aChar >= 'A') && (aChar <= 'Z')) return PR_TRUE;
00317   else if ((aChar >= 'a') && (aChar <= 'z')) return PR_TRUE;
00318   else if ((aChar >= '0') && (aChar <= '9')) return PR_TRUE;
00319   else if ((aChar >= 39) && (aChar <= 41)) return PR_TRUE;
00320   else if ((aChar >= 44) && (aChar <= 47)) return PR_TRUE;
00321   else if (aChar == 58) return PR_TRUE;
00322   else if (aChar == 63) return PR_TRUE;
00323   else if (aChar == ' ') return PR_TRUE;
00324   else if (aChar == 9) return PR_TRUE;
00325   else if (aChar == 13) return PR_TRUE;
00326   else if (aChar == 10) return PR_TRUE;
00327   else if (aChar == 60) return PR_TRUE;  // '<'
00328   else if (aChar == 33) return PR_TRUE;  // '!'
00329   else if (aChar == 34) return PR_TRUE;  // '"'
00330   else if (aChar == 62) return PR_TRUE;  // '>'
00331   else if (aChar == 61) return PR_TRUE;  // '='
00332   else if (aChar == 59) return PR_TRUE;  // ';'
00333   else if (aChar == 91) return PR_TRUE;  // '['
00334   else if (aChar == 93) return PR_TRUE;  // ']'
00335   else return PR_FALSE;
00336 }