Home | History | Annotate | Download | only in src
      1 
      2 /*************************************************************************/
      3 /* module:          Communication Services, base64 encoding/decoding fns.*/
      4 /* file:            src/xpt/all/xpt-b64.c                                */
      5 /* target system:   all                                                  */
      6 /* target OS:       all                                                  */
      7 /*************************************************************************/
      8 
      9 
     10 /*
     11  * Copyright Notice
     12  * Copyright (c) Ericsson, IBM, Lotus, Matsushita Communication
     13  * Industrial Co., Ltd., Motorola, Nokia, Openwave Systems, Inc.,
     14  * Palm, Inc., Psion, Starfish Software, Symbian, Ltd. (2001).
     15  * All Rights Reserved.
     16  * Implementation of all or part of any Specification may require
     17  * licenses under third party intellectual property rights,
     18  * including without limitation, patent rights (such a third party
     19  * may or may not be a Supporter). The Sponsors of the Specification
     20  * are not responsible and shall not be held responsible in any
     21  * manner for identifying or failing to identify any or all such
     22  * third party intellectual property rights.
     23  *
     24  * THIS DOCUMENT AND THE INFORMATION CONTAINED HEREIN ARE PROVIDED
     25  * ON AN "AS IS" BASIS WITHOUT WARRANTY OF ANY KIND AND ERICSSON, IBM,
     26  * LOTUS, MATSUSHITA COMMUNICATION INDUSTRIAL CO. LTD, MOTOROLA,
     27  * NOKIA, PALM INC., PSION, STARFISH SOFTWARE AND ALL OTHER SYNCML
     28  * SPONSORS DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
     29  * BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
     30  * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
     31  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
     32  * SHALL ERICSSON, IBM, LOTUS, MATSUSHITA COMMUNICATION INDUSTRIAL CO.,
     33  * LTD, MOTOROLA, NOKIA, PALM INC., PSION, STARFISH SOFTWARE OR ANY
     34  * OTHER SYNCML SPONSOR BE LIABLE TO ANY PARTY FOR ANY LOSS OF
     35  * PROFITS, LOSS OF BUSINESS, LOSS OF USE OF DATA, INTERRUPTION OF
     36  * BUSINESS, OR FOR DIRECT, INDIRECT, SPECIAL OR EXEMPLARY, INCIDENTAL,
     37  * PUNITIVE OR CONSEQUENTIAL DAMAGES OF ANY KIND IN CONNECTION WITH
     38  * THIS DOCUMENT OR THE INFORMATION CONTAINED HEREIN, EVEN IF ADVISED
     39  * OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE.
     40  *
     41  * The above notice and this paragraph must be included on all copies
     42  * of this document that are made.
     43  *
     44  */
     45 
     46 
     47 #include "xptport.h"
     48 #include "xpttypes.h"
     49 #include "xpt-b64.h"
     50 
     51 
     52 #define MAX_COLUMNS 45
     53 
     54 
     55 /***************************************************************************/
     56 /* The function decodes the next character of the input buffer and updates */
     57 /* the pointers to the input buffer. The function skips CRLF characters    */
     58 /* and whitespace characters.                                              */
     59 /* Returns: 0..63, the logical value of the next valid character in the    */
     60 /*                 input buffer                                            */
     61 /*          64,    padding character                                       */
     62 /*          -1,    No more characters to read                              */
     63 /*          -2,    an error occurred: invalid characters in the data stream*/
     64 /***************************************************************************/
     65 
     66 int nextBase64Char (DataBuffer_t *ppbData, BufferSize_t *pcbDataLength)
     67    {
     68    int r = -1;
     69    DataBuffer_t pbData = *ppbData;
     70    BufferSize_t cbDataLength = *pcbDataLength;
     71 #ifndef __EPOC_OS__
     72    static char *pszSkipChars = "\t\r\n ";
     73 #endif
     74 #ifdef __EPOC_OS__
     75    char *pszSkipChars = "\t\r\n ";
     76 #endif
     77    char ch;
     78 
     79    if (cbDataLength == 0) return r;
     80 
     81    do {
     82       ch = *pbData;
     83       if ((ch>='0')&&(ch<='9'))      r = (int)ch+4;  //  |
     84       else if ((ch>='A')&&(ch<='Z')) r = (int)ch-65; //  |
     85       else if ((ch>='a')&&(ch<='z')) r = (int)ch-71; //  | Valid characters
     86       else if (ch == '/')            r = 63;         //  |
     87       else if (ch == '+')            r = 62;         //  |
     88       else if (ch == '=')            r = 64;         // padding character
     89       else if (!xppStrchr (pszSkipChars, ch))  r = -2; // invalid character
     90       cbDataLength --;
     91       pbData ++;
     92       } while ((r == -1) && (cbDataLength > 0));
     93 
     94    /***************************************************/
     95    /* Pass the updated parameter values to the caller */
     96    /***************************************************/
     97    if (r != -1)
     98       {
     99       *ppbData = pbData;
    100       *pcbDataLength = cbDataLength;
    101       }
    102    return r;
    103    }
    104 
    105 BufferSize_t base64GetSize (BufferSize_t cbRealDataSize)
    106    {
    107    int iMod = cbRealDataSize % 3;
    108    /* The encoded data size ... */
    109    BufferSize_t cbEncodedSize = ((cbRealDataSize - iMod) / 3 ) * 4;
    110    if (iMod != 0) cbEncodedSize += 4;
    111    /* ... and the # of CRLF characters */
    112    cbEncodedSize += ((cbEncodedSize-1) / ((MAX_COLUMNS*4)/3)) * 2;
    113    return cbEncodedSize;
    114    }
    115 
    116 
    117 /*****************************************************************/
    118 /* Function: pre-compute the size of the base64 encoded document */
    119 /****************************************************************/
    120 
    121 BufferSize_t base64Encode (DataBuffer_t pbTarget,       // o: target buffer
    122                      BufferSize_t cbTargetSize,   // i: target buffer size
    123                      DataBuffer_t pbData,         // i: Data buffer
    124                      BufferSize_t *pcbDataLength, // i/o: Data buffer size
    125                      BufferSize_t *pcbOffset,     // i/o: absolute # of bytes encoded so far
    126                      unsigned int bLast,          // i: 0=first block, 1= next block, 2=last block
    127                      unsigned char *pbSaveBytes)  // i/o: last incomplete data block
    128    {
    129    DataBuffer_t pbSourceData = pbData;
    130    BufferSize_t cbCopySize = 0;
    131    BufferSize_t cbDataProcessed = *pcbDataLength;
    132    unsigned int i0, i1, i2, i3;
    133    unsigned int byt;
    134    int iSave = 1;
    135 #ifndef __EPOC_OS__
    136    static char t [] =   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"    // 26
    137                         "abcdefghijklmnopqrstuvwxyz"    // 26
    138                         "0123456789+/"                  // 12
    139                         "=";                            // 1
    140 #endif
    141 #ifdef __EPOC_OS__
    142 char t [] =   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"    // 26
    143               "abcdefghijklmnopqrstuvwxyz"    // 26
    144               "0123456789+/"                  // 12
    145               "=";                            // 1
    146 #endif
    147    // Check for NULL data buffer,
    148    if (pbData == NULL ) {
    149        // See if last block and there is any "saved" data that needs to go now.
    150        if ( bLast && ( pbSaveBytes && pbSaveBytes [0] )) {
    151           /**************************************/
    152           /* Check if it is time to send a CRLF */
    153           /**************************************/
    154           if ((*pcbOffset) > 0 && ((*pcbOffset) % MAX_COLUMNS == 0))
    155              {
    156              //if (cbTargetSize < 6)        // there is not enough space in the target buffer:
    157              //   break;                    // return to the caller.
    158              *pbTarget = '\r';
    159              *(pbTarget+1) = '\n';
    160              cbCopySize += 2;
    161              cbTargetSize -= 2;
    162              pbTarget += 2;
    163              }
    164 
    165           byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --;
    166 
    167           i0 =  byt >> 2;
    168           i1 =  (byt & 0x0003) << 4;
    169 
    170           (*pcbOffset) ++;
    171 
    172           if (pbSaveBytes && pbSaveBytes [0]) {
    173               byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --;
    174               i1 += (byt >> 4);
    175               i2 = i3 = (byt & 0x000F) << 2;
    176           } else {
    177               i2 = i3 = 64;  // index to the padding char '=';
    178           }
    179 
    180           pbTarget [0] = t[i0];
    181           pbTarget [1] = t[i1];
    182           pbTarget [2] = t[i2];
    183           pbTarget [3] = t[i3];
    184 
    185           cbCopySize += 4;
    186           cbTargetSize -= 4;
    187           pbTarget += 4;
    188        }
    189 
    190    } else {
    191        while ((cbTargetSize >= 4) && (cbDataProcessed >  0))
    192 	/*
    193          *   AZ: We do not need to divide the data into multiple blocks, nor do we enforce
    194          *          MAX_COLUMNS. So commenting out the code block below for now.
    195          *
    196 	  * 	&&
    197          *    ( ((cbDataProcessed >= 3) && (bLast == 0)) ||
    198          *       ((cbDataProcessed >  0) && (bLast == 1)) ))
    199          */
    200           {
    201           /**************************************/
    202           /* Check if it is time to send a CRLF */
    203           /**************************************/
    204           /*
    205           if ((*pcbOffset) > 0 && ((*pcbOffset) % MAX_COLUMNS == 0))
    206              {
    207              if (cbTargetSize < 6)        // there is not enough space in the target buffer:
    208                 break;                    // return to the caller.
    209              *pbTarget = '\r';
    210              *(pbTarget+1) = '\n';
    211              cbCopySize += 2;
    212              cbTargetSize -= 2;
    213              pbTarget += 2;
    214              }
    215           */
    216           if (pbSaveBytes && pbSaveBytes [0])
    217              { byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --; }
    218           else
    219              { byt = (unsigned int) *pbSourceData; pbSourceData ++; cbDataProcessed --;}
    220 
    221           i0 =  byt >> 2;
    222           i1 =  (byt & 0x0003) << 4;
    223 
    224           (*pcbOffset) ++;
    225 
    226           if (cbDataProcessed > 0)
    227              {
    228              if (pbSaveBytes && pbSaveBytes [0])
    229                 { byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --; }
    230              else
    231                 { byt = (unsigned int) *pbSourceData; pbSourceData ++; cbDataProcessed --;}
    232 
    233              i1 += (byt >> 4);
    234              i2 =  (byt & 0x000F) << 2;
    235 
    236              (*pcbOffset) ++;
    237 
    238              if (cbDataProcessed > 0)
    239                 {
    240                 if (pbSaveBytes && pbSaveBytes [0])
    241                    { byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --; }
    242                 else
    243                    { byt = (unsigned int) *pbSourceData; pbSourceData ++; cbDataProcessed --;}
    244 
    245                 i2 += (byt & 0x00C0) >> 6;
    246                 i3 =  byt & 0x003F;
    247                 (*pcbOffset) ++;
    248                 }
    249              else
    250                 i3 = 64;  // index to the padding char '=';
    251              }
    252           else
    253              i2 = i3 = 64;  // index to the padding char '=';
    254           pbTarget [0] = t[i0];
    255           pbTarget [1] = t[i1];
    256           pbTarget [2] = t[i2];
    257           pbTarget [3] = t[i3];
    258 
    259           cbCopySize += 4;
    260           cbTargetSize -= 4;
    261           pbTarget += 4;
    262        }
    263    }
    264 
    265 
    266 
    267    /*************************************************************/
    268    /* Save the bytes that must be processed in the following    */
    269    /* call (max. 2 Bytes).                                      */
    270    /*************************************************************/
    271    if(pbSourceData!=NULL){
    272     if ((bLast == 0) && (cbDataProcessed <= 2) && (pbSaveBytes != NULL))
    273       {
    274       pbSaveBytes[0] = cbDataProcessed;
    275       while (cbDataProcessed)
    276          {
    277          *(++pbSaveBytes) = pbSourceData[0];
    278          cbDataProcessed --; pbSourceData ++;
    279          }
    280       }
    281 
    282    /*****************************************************************/
    283    /* Shift all non-processed data to the start of the input buffer */
    284    /*****************************************************************/
    285 
    286    if (cbDataProcessed > 0)
    287       {
    288       xppMemmove (pbData, pbSourceData, cbDataProcessed);
    289       }
    290    *pcbDataLength = cbDataProcessed;
    291    }
    292    return cbCopySize;
    293    }
    294 
    295 /***************************************************************/
    296 /* Function: decode a base64- encoded block of data.           */
    297 /* The function returns the count of data that are decoded, or */
    298 /* 0 in case of a data error, or if cbTargetSize < 4           */
    299 /***************************************************************/
    300 
    301 BufferSize_t base64Decode (DataBuffer_t pbTarget,       // o: target buffer
    302                      BufferSize_t cbTargetSize,   // i: target buffer size
    303                      DataBuffer_t pbData,         // i: data buffer
    304                      BufferSize_t *pcbDataLength) // i/o: Data buffer size
    305    {
    306    DataBuffer_t pbSource = pbData;
    307    BufferSize_t cbDataCopied = 0L;
    308    BufferSize_t cbRemaining = *pcbDataLength; // remaining source data
    309    int i0 = 0, i1 = 0, i2 = 0, i3 = 0;
    310 
    311    while (cbTargetSize > 0)
    312       {
    313       BufferSize_t cbNext = cbRemaining;
    314       DataBuffer_t pbNext = pbSource;
    315 
    316       i0 = nextBase64Char (&pbNext, &cbNext);
    317       i1 = nextBase64Char (&pbNext, &cbNext);
    318       i2 = nextBase64Char (&pbNext, &cbNext);
    319       i3 = nextBase64Char (&pbNext, &cbNext);
    320       if ((i0 < 0) || (i1 < 0) || (i2 < 0) || (i3 < 0))
    321          break; // end-of-block, or data error.
    322 
    323       else if ( ((cbTargetSize <= 2) && (i3 != 64)) ||
    324                 ((cbTargetSize <= 1) && (i2 != 64)) )
    325          break; // end of transmission.
    326 
    327       else
    328          {
    329          pbSource = pbNext;
    330          cbRemaining = cbNext;
    331          /************************/
    332          /* decode the quadruple */
    333          /************************/
    334          *pbTarget = (i0 << 2) + (i1 >> 4);
    335          pbTarget ++; cbDataCopied ++; cbTargetSize --;
    336          if (i2 != 64)
    337             {
    338             *pbTarget = ((i1 & 0x000f) << 4) + (i2 >> 2);
    339             pbTarget ++; cbDataCopied ++; cbTargetSize --;
    340             if (i3 != 64)
    341                {
    342                *pbTarget = ((i2 & 0x0003) << 6) + i3;
    343                pbTarget ++; cbDataCopied ++; cbTargetSize --;
    344                }
    345             }
    346          }
    347       }
    348 
    349    /*******************************/
    350    /* Handle invalid data errors! */
    351    /*******************************/
    352 
    353    if ((i0 == -2) || (i1 == -2) || (i2 == -2) || (i3 == -2))
    354       cbDataCopied = 0;
    355 
    356    /*****************************************************************/
    357    /* Shift all non-processed data to the start of the input buffer */
    358    /*****************************************************************/
    359    if (cbRemaining > 0)
    360       xppMemmove (pbData, pbSource, cbRemaining);
    361    *pcbDataLength = cbRemaining;
    362    return cbDataCopied;
    363    }
    364 
    365 
    366