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