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