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 =  (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) &&
    192               ( ((cbDataProcessed >= 3) && (bLast == 0)) ||
    193                 ((cbDataProcessed >  0) && (bLast == 1)) ))
    194           {
    195           /**************************************/
    196           /* Check if it is time to send a CRLF */
    197           /**************************************/
    198           if ((*pcbOffset) > 0 && ((*pcbOffset) % MAX_COLUMNS == 0))
    199              {
    200              if (cbTargetSize < 6)        // there is not enough space in the target buffer:
    201                 break;                    // return to the caller.
    202              *pbTarget = '\r';
    203              *(pbTarget+1) = '\n';
    204              cbCopySize += 2;
    205              cbTargetSize -= 2;
    206              pbTarget += 2;
    207              }
    208 
    209           if (pbSaveBytes && pbSaveBytes [0])
    210              { byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --; }
    211           else
    212              { byt = (unsigned int) *pbSourceData; pbSourceData ++; cbDataProcessed --;}
    213 
    214           i0 =  byt >> 2;
    215           i1 =  (byt & 0x0003) << 4;
    216 
    217           (*pcbOffset) ++;
    218 
    219           if (cbDataProcessed > 0)
    220              {
    221              if (pbSaveBytes && pbSaveBytes [0])
    222                 { byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --; }
    223              else
    224                 { byt = (unsigned int) *pbSourceData; pbSourceData ++; cbDataProcessed --;}
    225 
    226              i1 += (byt >> 4);
    227              i2 =  (byt & 0x000F) << 2;
    228 
    229              (*pcbOffset) ++;
    230 
    231              if (cbDataProcessed > 0)
    232                 {
    233                 if (pbSaveBytes && pbSaveBytes [0])
    234                    { byt = (unsigned int) pbSaveBytes [iSave]; iSave ++; pbSaveBytes [0] --; }
    235                 else
    236                    { byt = (unsigned int) *pbSourceData; pbSourceData ++; cbDataProcessed --;}
    237 
    238                 i2 += (byt & 0x00C0) >> 6;
    239                 i3 =  byt & 0x003F;
    240                 (*pcbOffset) ++;
    241                 }
    242              else
    243                 i3 = 64;  // index to the padding char '=';
    244              }
    245           else
    246              i2 = i3 = 64;  // index to the padding char '=';
    247           pbTarget [0] = t[i0];
    248           pbTarget [1] = t[i1];
    249           pbTarget [2] = t[i2];
    250           pbTarget [3] = t[i3];
    251 
    252           cbCopySize += 4;
    253           cbTargetSize -= 4;
    254           pbTarget += 4;
    255        }
    256    }
    257 
    258 
    259 
    260    /*************************************************************/
    261    /* Save the bytes that must be processed in the following    */
    262    /* call (max. 2 Bytes).                                      */
    263    /*************************************************************/
    264    if ((bLast == 0) && (cbDataProcessed <= 2) && (pbSaveBytes != NULL))
    265       {
    266       pbSaveBytes[0] = cbDataProcessed;
    267       while (cbDataProcessed)
    268          {
    269          *(++pbSaveBytes) = pbSourceData[0];
    270          cbDataProcessed --; pbSourceData ++;
    271          }
    272       }
    273 
    274    /*****************************************************************/
    275    /* Shift all non-processed data to the start of the input buffer */
    276    /*****************************************************************/
    277 
    278    if (cbDataProcessed > 0)
    279       {
    280       xppMemmove (pbData, pbSourceData, cbDataProcessed);
    281       }
    282    *pcbDataLength = cbDataProcessed;
    283 
    284    return cbCopySize;
    285    }
    286 
    287 
    288 /***************************************************************/
    289 /* Function: decode a base64- encoded block of data.           */
    290 /* The function returns the count of data that are decoded, or */
    291 /* 0 in case of a data error, or if cbTargetSize < 4           */
    292 /***************************************************************/
    293 
    294 BufferSize_t base64Decode (DataBuffer_t pbTarget,       // o: target buffer
    295                      BufferSize_t cbTargetSize,   // i: target buffer size
    296                      DataBuffer_t pbData,         // i: data buffer
    297                      BufferSize_t *pcbDataLength) // i/o: Data buffer size
    298    {
    299    DataBuffer_t pbSource = pbData;
    300    BufferSize_t cbDataCopied = 0L;
    301    BufferSize_t cbRemaining = *pcbDataLength; // remaining source data
    302    int i0 = 0, i1 = 0, i2 = 0, i3 = 0;
    303 
    304    while (cbTargetSize > 0)
    305       {
    306       BufferSize_t cbNext = cbRemaining;
    307       DataBuffer_t pbNext = pbSource;
    308 
    309       i0 = nextBase64Char (&pbNext, &cbNext);
    310       i1 = nextBase64Char (&pbNext, &cbNext);
    311       i2 = nextBase64Char (&pbNext, &cbNext);
    312       i3 = nextBase64Char (&pbNext, &cbNext);
    313       if ((i0 < 0) || (i1 < 0) || (i2 < 0) || (i3 < 0))
    314          break; // end-of-block, or data error.
    315 
    316       else if ( ((cbTargetSize <= 2) && (i3 != 64)) ||
    317                 ((cbTargetSize <= 1) && (i2 != 64)) )
    318          break; // end of transmission.
    319 
    320       else
    321          {
    322          pbSource = pbNext;
    323          cbRemaining = cbNext;
    324          /************************/
    325          /* decode the quadruple */
    326          /************************/
    327          *pbTarget = (i0 << 2) + (i1 >> 4);
    328          pbTarget ++; cbDataCopied ++; cbTargetSize --;
    329          if (i2 != 64)
    330             {
    331             *pbTarget = ((i1 & 0x000f) << 4) + (i2 >> 2);
    332             pbTarget ++; cbDataCopied ++; cbTargetSize --;
    333             if (i3 != 64)
    334                {
    335                *pbTarget = ((i2 & 0x0003) << 6) + i3;
    336                pbTarget ++; cbDataCopied ++; cbTargetSize --;
    337                }
    338             }
    339          }
    340       }
    341 
    342    /*******************************/
    343    /* Handle invalid data errors! */
    344    /*******************************/
    345 
    346    if ((i0 == -2) || (i1 == -2) || (i2 == -2) || (i3 == -2))
    347       cbDataCopied = 0;
    348 
    349    /*****************************************************************/
    350    /* Shift all non-processed data to the start of the input buffer */
    351    /*****************************************************************/
    352    if (cbRemaining > 0)
    353       xppMemmove (pbData, pbSource, cbRemaining);
    354    *pcbDataLength = cbRemaining;
    355    return cbDataCopied;
    356    }
    357 
    358 
    359