Back to index

lightning-sunbird  0.9+nobinonly
base64.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; 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 the Netscape Portable Runtime (NSPR).
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-2000
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 the GNU General Public License Version 2 or later (the "GPL"), or
00026  * 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 "plbase64.h"
00039 #include "prlog.h" /* For PR_NOT_REACHED */
00040 #include "prmem.h" /* for malloc / PR_MALLOC */
00041 #include "plstr.h" /* for PL_strlen */
00042 
00043 static unsigned char *base = (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00044 
00045 static void
00046 encode3to4
00047 (
00048     const unsigned char    *src,
00049     unsigned char          *dest
00050 )
00051 {
00052     PRUint32 b32 = (PRUint32)0;
00053     PRIntn i, j = 18;
00054 
00055     for( i = 0; i < 3; i++ )
00056     {
00057         b32 <<= 8;
00058         b32 |= (PRUint32)src[i];
00059     }
00060 
00061     for( i = 0; i < 4; i++ )
00062     {
00063         dest[i] = base[ (PRUint32)((b32>>j) & 0x3F) ];
00064         j -= 6;
00065     }
00066 
00067     return;
00068 }
00069 
00070 static void
00071 encode2to4
00072 (
00073     const unsigned char    *src,
00074     unsigned char          *dest
00075 )
00076 {
00077     dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
00078     dest[1] = base[ (PRUint32)(((src[0] & 0x03) << 4) | ((src[1] >> 4) & 0x0F)) ];
00079     dest[2] = base[ (PRUint32)((src[1] & 0x0F) << 2) ];
00080     dest[3] = (unsigned char)'=';
00081     return;
00082 }
00083 
00084 static void
00085 encode1to4
00086 (
00087     const unsigned char    *src,
00088     unsigned char          *dest
00089 )
00090 {
00091     dest[0] = base[ (PRUint32)((src[0]>>2) & 0x3F) ];
00092     dest[1] = base[ (PRUint32)((src[0] & 0x03) << 4) ];
00093     dest[2] = (unsigned char)'=';
00094     dest[3] = (unsigned char)'=';
00095     return;
00096 }
00097 
00098 static void
00099 encode
00100 (
00101     const unsigned char    *src,
00102     PRUint32                srclen,
00103     unsigned char          *dest
00104 )
00105 {
00106     while( srclen >= 3 )
00107     {
00108         encode3to4(src, dest);
00109         src += 3;
00110         dest += 4;
00111         srclen -= 3;
00112     }
00113 
00114     switch( srclen )
00115     {
00116         case 2:
00117             encode2to4(src, dest);
00118             break;
00119         case 1:
00120             encode1to4(src, dest);
00121             break;
00122         case 0:
00123             break;
00124         default:
00125             PR_NOT_REACHED("coding error");
00126     }
00127 
00128     return;
00129 }
00130 
00131 /*
00132  * PL_Base64Encode
00133  *
00134  * If the destination argument is NULL, a return buffer is 
00135  * allocated, and the data therein will be null-terminated.  
00136  * If the destination argument is not NULL, it is assumed to
00137  * be of sufficient size, and the contents will not be null-
00138  * terminated by this routine.
00139  *
00140  * Returns null if the allocation fails.
00141  */
00142 
00143 PR_IMPLEMENT(char *)
00144 PL_Base64Encode
00145 (
00146     const char *src,
00147     PRUint32    srclen,
00148     char       *dest
00149 )
00150 {
00151     if( 0 == srclen )
00152     {
00153         srclen = PL_strlen(src);
00154     }
00155 
00156     if( (char *)0 == dest )
00157     {
00158         PRUint32 destlen = ((srclen + 2)/3) * 4;
00159         dest = (char *)PR_MALLOC(destlen + 1);
00160         if( (char *)0 == dest )
00161         {
00162             return (char *)0;
00163         }
00164         dest[ destlen ] = (char)0; /* null terminate */
00165     }
00166 
00167     encode((const unsigned char *)src, srclen, (unsigned char *)dest);
00168     return dest;
00169 }
00170 
00171 static PRInt32
00172 codetovalue
00173 (
00174     unsigned char c
00175 )
00176 {
00177     if( (c >= (unsigned char)'A') && (c <= (unsigned char)'Z') )
00178     {
00179         return (PRInt32)(c - (unsigned char)'A');
00180     }
00181     else if( (c >= (unsigned char)'a') && (c <= (unsigned char)'z') )
00182     {
00183         return ((PRInt32)(c - (unsigned char)'a') +26);
00184     }
00185     else if( (c >= (unsigned char)'0') && (c <= (unsigned char)'9') )
00186     {
00187         return ((PRInt32)(c - (unsigned char)'0') +52);
00188     }
00189     else if( (unsigned char)'+' == c )
00190     {
00191         return (PRInt32)62;
00192     }
00193     else if( (unsigned char)'/' == c )
00194     {
00195         return (PRInt32)63;
00196     }
00197     else
00198     {
00199         return -1;
00200     }
00201 }
00202 
00203 static PRStatus
00204 decode4to3
00205 (
00206     const unsigned char    *src,
00207     unsigned char          *dest
00208 )
00209 {
00210     PRUint32 b32 = (PRUint32)0;
00211     PRInt32 bits;
00212     PRIntn i;
00213 
00214     for( i = 0; i < 4; i++ )
00215     {
00216         bits = codetovalue(src[i]);
00217         if( bits < 0 )
00218         {
00219             return PR_FAILURE;
00220         }
00221 
00222         b32 <<= 6;
00223         b32 |= bits;
00224     }
00225 
00226     dest[0] = (unsigned char)((b32 >> 16) & 0xFF);
00227     dest[1] = (unsigned char)((b32 >>  8) & 0xFF);
00228     dest[2] = (unsigned char)((b32      ) & 0xFF);
00229 
00230     return PR_SUCCESS;
00231 }
00232 
00233 static PRStatus
00234 decode3to2
00235 (
00236     const unsigned char    *src,
00237     unsigned char          *dest
00238 )
00239 {
00240     PRUint32 b32 = (PRUint32)0;
00241     PRInt32 bits;
00242     PRUint32 ubits;
00243 
00244     bits = codetovalue(src[0]);
00245     if( bits < 0 )
00246     {
00247         return PR_FAILURE;
00248     }
00249 
00250     b32 = (PRUint32)bits;
00251     b32 <<= 6;
00252 
00253     bits = codetovalue(src[1]);
00254     if( bits < 0 )
00255     {
00256         return PR_FAILURE;
00257     }
00258 
00259     b32 |= (PRUint32)bits;
00260     b32 <<= 4;
00261 
00262     bits = codetovalue(src[2]);
00263     if( bits < 0 )
00264     {
00265         return PR_FAILURE;
00266     }
00267 
00268     ubits = (PRUint32)bits;
00269     b32 |= (ubits >> 2);
00270 
00271     dest[0] = (unsigned char)((b32 >> 8) & 0xFF);
00272     dest[1] = (unsigned char)((b32     ) & 0xFF);
00273 
00274     return PR_SUCCESS;
00275 }
00276 
00277 static PRStatus
00278 decode2to1
00279 (
00280     const unsigned char    *src,
00281     unsigned char          *dest
00282 )
00283 {
00284     PRUint32 b32;
00285     PRUint32 ubits;
00286     PRInt32 bits;
00287 
00288     bits = codetovalue(src[0]);
00289     if( bits < 0 )
00290     {
00291         return PR_FAILURE;
00292     }
00293 
00294     ubits = (PRUint32)bits;
00295     b32 = (ubits << 2);
00296 
00297     bits = codetovalue(src[1]);
00298     if( bits < 0 )
00299     {
00300         return PR_FAILURE;
00301     }
00302 
00303     ubits = (PRUint32)bits;
00304     b32 |= (ubits >> 4);
00305 
00306     dest[0] = (unsigned char)b32;
00307 
00308     return PR_SUCCESS;
00309 }
00310 
00311 static PRStatus
00312 decode
00313 (
00314     const unsigned char    *src,
00315     PRUint32                srclen,
00316     unsigned char          *dest
00317 )
00318 {
00319     PRStatus rv;
00320 
00321     while( srclen >= 4 )
00322     {
00323         rv = decode4to3(src, dest);
00324         if( PR_SUCCESS != rv )
00325         {
00326             return PR_FAILURE;
00327         }
00328 
00329         src += 4;
00330         dest += 3;
00331         srclen -= 4;
00332     }
00333 
00334     switch( srclen )
00335     {
00336         case 3:
00337             rv = decode3to2(src, dest);
00338             break;
00339         case 2:
00340             rv = decode2to1(src, dest);
00341             break;
00342         case 1:
00343             rv = PR_FAILURE;
00344             break;
00345         case 0:
00346             rv = PR_SUCCESS;
00347             break;
00348         default:
00349             PR_NOT_REACHED("coding error");
00350     }
00351 
00352     return rv;
00353 }
00354 
00355 /*
00356  * PL_Base64Decode
00357  *
00358  * If the destination argument is NULL, a return buffer is
00359  * allocated and the data therein will be null-terminated.
00360  * If the destination argument is not null, it is assumed
00361  * to be of sufficient size, and the data will not be null-
00362  * terminated by this routine.
00363  * 
00364  * Returns null if the allocation fails, or if the source string is 
00365  * not well-formed.
00366  */
00367 
00368 PR_IMPLEMENT(char *)
00369 PL_Base64Decode
00370 (
00371     const char *src,
00372     PRUint32    srclen,
00373     char       *dest
00374 )
00375 {
00376     PRStatus status;
00377     PRBool allocated = PR_FALSE;
00378 
00379     if( (char *)0 == src )
00380     {
00381         return (char *)0;
00382     }
00383 
00384     if( 0 == srclen )
00385     {
00386         srclen = PL_strlen(src);
00387     }
00388 
00389     if( srclen && (0 == (srclen & 3)) )
00390     {
00391         if( (char)'=' == src[ srclen-1 ] )
00392         {
00393             if( (char)'=' == src[ srclen-2 ] )
00394             {
00395                 srclen -= 2;
00396             }
00397             else
00398             {
00399                 srclen -= 1;
00400             }
00401         }
00402     }
00403 
00404     if( (char *)0 == dest )
00405     {
00406         PRUint32 destlen = ((srclen * 3) / 4);
00407         dest = (char *)PR_MALLOC(destlen + 1);
00408         if( (char *)0 == dest )
00409         {
00410             return (char *)0;
00411         }
00412         dest[ destlen ] = (char)0; /* null terminate */
00413         allocated = PR_TRUE;
00414     }
00415 
00416     status = decode((const unsigned char *)src, srclen, (unsigned char *)dest);
00417     if( PR_SUCCESS != status )
00418     {
00419         if( PR_TRUE == allocated )
00420         {
00421             PR_DELETE(dest);
00422         }
00423 
00424         return (char *)0;
00425     }
00426 
00427     return dest;
00428 }