00001
00068
00069
00070
00071
00072
00073
00074 #include "cardparser.h"
00075 #include <stdlib.h>
00076 #include <ctype.h>
00077 #include <string.h>
00078 #include <stdio.h>
00079
00080 #ifndef TRUE
00081 #define TRUE -1
00082 #endif
00083
00084 #ifndef FALSE
00085 #define FALSE 0
00086 #endif
00087
00088
00089
00090
00091
00092
00093 const char *CARD_ParserVersion()
00094 {
00095 return CARD_PARSER_VER;
00096 };
00097
00098 typedef enum {cp_PropName, cp_ParamBN,cp_ParamIN, cp_ValueBV, cp_ValueIV, cp_PropData} TCARDParserState;
00099 typedef enum {cp_EncodingNone, cp_EncodingQP, cp_EncodingBase64, cp_Encoding8Bit} TCARDParserEncoding;
00100
00101 typedef struct
00102 {
00103
00104 int startOfLine;
00105 int folding;
00106
00107
00108 char *lineBuf;
00109 int lbSize;
00110 int lbLen;
00111
00112
00113 TCARDParserState state;
00114 int startOfData;
00115 CARD_Char **params;
00116 int nParams;
00117 int valueEscape;
00118 TCARDParserEncoding encoding;
00119 int decoding;
00120 char decodeBuf[4];
00121 int dbLen;
00122
00123
00124
00125 void *userData;
00126
00127
00128 CARD_PropHandler cardProp;
00129 CARD_DataHandler cardData;
00130 } VP;
00131
00132 void vcard_clear_line(VP *vp)
00133 {
00134 vp->state = cp_PropName;
00135 vp->lbLen = 0;
00136 if (vp->lbSize > 1024)
00137 {
00138 free(vp->lineBuf);
00139 vp->lineBuf = NULL;
00140 vp->lbSize = 0;
00141 };
00142 vp->startOfData = TRUE;
00143 vp->nParams = 0;
00144 vp->valueEscape = FALSE;
00145 vp->encoding = cp_EncodingNone;
00146 vp->decoding = FALSE;
00147 memset(vp->decodeBuf, 0, sizeof(vp->decodeBuf));
00148 vp->dbLen = 0;
00149 };
00150
00151
00152
00160 CARD_Parser CARD_ParserCreate(CARD_Char *encoding)
00161 {
00162 VP *vp = (VP *) malloc(sizeof(VP));
00163 if (! vp)
00164 return NULL;
00165
00166 memset(vp, 0, sizeof(VP));
00167
00168
00169 vp->startOfLine = TRUE;
00170 vp->folding = FALSE;
00171
00172
00173 vcard_clear_line(vp);
00174
00175
00176 return vp;
00177 };
00178
00185 void CARD_ParserFree(CARD_Parser p)
00186 {
00187 VP *vp = (VP *) p;
00188 free(vp->lineBuf);
00189 free(vp->params);
00190 free(p);
00191 };
00192
00193 int vcard_add_char_to_line(VP *vp, char c)
00194 {
00195
00196 if (vp->lbLen >= vp->lbSize)
00197 {
00198 vp->lbSize = vp->lbLen + 128;
00199 vp->lineBuf = (char *) realloc(vp->lineBuf, vp->lbSize);
00200 if (vp->lineBuf == NULL)
00201 {
00202
00203 vp->lbSize = 0;
00204 vp->lbLen = 0;
00205 return FALSE;
00206 };
00207
00208 };
00209
00210
00211 vp->lineBuf[vp->lbLen] = c;
00212 vp->lbLen++;
00213
00214 return TRUE;
00215 };
00216
00217 int card_add_param(VP *vp, int paramOff)
00218 {
00219 vp->params = (CARD_Char **) realloc(vp->params, sizeof(CARD_Char *) * (vp->nParams + 1) * 2);
00220
00221 if (! vp->params)
00222 return FALSE;
00223
00224 vp->params[vp->nParams * 2] = (CARD_Char *) paramOff;
00225 vp->params[vp->nParams * 2 + 1] = NULL;
00226 vp->nParams++;
00227
00228 return TRUE;
00229 };
00230
00231 int card_set_paramvalue(VP *vp, int valueOff)
00232 {
00233 if (! vp->params)
00234 return FALSE;
00235
00236 vp->params[(vp->nParams - 1) * 2 + 1] = (CARD_Char *) valueOff;
00237
00238 return TRUE;
00239 };
00240
00241 int vcard_end_prop(VP *vp)
00242 {
00243 char *b;
00244 const CARD_Char *propName;
00245 int i;
00246 CARD_Char *encoding;
00247
00248 if (vp->cardProp)
00249 {
00250
00251 if (! vcard_add_char_to_line(vp, 0))
00252 return FALSE;
00253
00254
00255 b = vp->lineBuf;
00256 propName = b;
00257
00258
00259 for (i = 0; i < vp->nParams; i++)
00260 {
00261 vp->params[i * 2] = vp->lineBuf + (int) vp->params[i * 2];
00262 if (vp->params[i * 2 + 1])
00263 vp->params[i * 2 + 1] = vp->lineBuf + (int) vp->params[i * 2 + 1];
00264
00265
00266
00267 encoding = vp->params[i * 2];
00268 if (strcmpi(encoding, "ENCODING") == 0)
00269 encoding = vp->params[i * 2 + 1];
00270
00271 if (encoding)
00272 {
00273 if (strcmpi(encoding, "QUOTED-PRINTABLE") == 0)
00274 vp->encoding = cp_EncodingQP;
00275 else if (strcmpi(encoding, "BASE64") == 0)
00276 vp->encoding = cp_EncodingBase64;
00277 else if (strcmpi(encoding, "8BIT") == 0)
00278 vp->encoding = cp_Encoding8Bit;
00279 };
00280 };
00281
00282
00283
00284 card_add_param(vp, 0);
00285
00286
00287 vp->cardProp(vp->userData, propName, (const CARD_Char **) vp->params);
00288 };
00289
00290 vp->lbLen = 0;
00291 vp->state = cp_PropData;
00292
00293 return TRUE;
00294 };
00295
00296
00297
00298
00299
00300
00301 unsigned char Base64ToOrd(char ch)
00302 {
00303 if (ch >= 'A'&& ch <= 'Z')
00304 return ch - 'A';
00305
00306 else if (ch >= 'a'&& ch <= 'z')
00307 return 26 + ch - 'a';
00308
00309 else if (ch >= '0' && ch <= '9')
00310 return 52 + ch - '0';
00311
00312 else if (ch == '+')
00313 return 62;
00314
00315 else if (ch == '/')
00316 return 63;
00317
00318 return 0xFF;
00319 };
00320
00321 int vcard_process_char(VP *vp, char c)
00322 {
00323
00324 int x;
00325
00326 unsigned char ch;
00327 unsigned char u0;
00328 unsigned char u1;
00329 unsigned char u2;
00330 unsigned char u3;
00331
00332 switch (vp->state)
00333 {
00334
00335
00336 case cp_PropName:
00337
00338 switch(c)
00339 {
00340 case ':':
00341 vcard_end_prop(vp);
00342 return TRUE;
00343
00344 case ';':
00345
00346 vp->state = cp_ParamBN;
00347 return vcard_add_char_to_line(vp, 0);
00348
00349 case '\r':
00350 return TRUE;
00351
00352 case '\n':
00353
00354 vcard_clear_line(vp);
00355 return TRUE;
00356
00357 default:
00358
00359 if (! isspace(c))
00360 return vcard_add_char_to_line(vp, c);
00361 else
00362 return TRUE;
00363 };
00364 break;
00365
00366
00367
00368 case cp_ParamBN:
00369 switch(c)
00370 {
00371 case ':':
00372
00373 vcard_clear_line(vp);
00374 return FALSE;
00375
00376 default:
00377 if (isspace(c))
00378 return TRUE;
00379
00380
00381 card_add_param(vp, vp->lbLen);
00382
00383
00384 vp->state = cp_ParamIN;
00385 return vcard_add_char_to_line(vp, c);
00386 };
00387 break;
00388
00389 case cp_ParamIN:
00390 switch(c)
00391 {
00392 case '=':
00393
00394 vp->state = cp_ValueBV;
00395 return vcard_add_char_to_line(vp, 0);
00396
00397 case ';':
00398
00399 vp->state = cp_ParamBN;
00400 return vcard_add_char_to_line(vp, 0);
00401
00402 case ':':
00403
00404 vcard_end_prop(vp);
00405 return TRUE;
00406
00407 default:
00408 if (! isspace(c))
00409 return vcard_add_char_to_line(vp, c);
00410 else
00411 return TRUE;
00412 }
00413 break;
00414
00415
00416
00417 case cp_ValueBV:
00418 switch(c)
00419 {
00420 case ';':
00421 case ':':
00422
00423 vcard_clear_line(vp);
00424 return FALSE;
00425
00426 default:
00427 if (isspace(c))
00428 return TRUE;
00429
00430
00431 card_set_paramvalue(vp, vp->lbLen);
00432
00433
00434 vp->state = cp_ValueIV;
00435 return vcard_add_char_to_line(vp, c);
00436 };
00437 break;
00438
00439 case cp_ValueIV:
00440 switch(c)
00441 {
00442 case ';':
00443 if (vp->valueEscape)
00444 {
00445
00446 vp->valueEscape = FALSE;
00447 return vcard_add_char_to_line(vp, c);
00448 };
00449
00450
00451 vp->state = cp_ParamBN;
00452 return vcard_add_char_to_line(vp, 0);
00453
00454 case ':':
00455
00456 vcard_end_prop(vp);
00457 return TRUE;
00458
00459 default:
00460 if (! isspace(c))
00461 {
00462 if (c == '\\')
00463 {
00464 if (vp->valueEscape)
00465 vp->valueEscape = FALSE;
00466 else
00467 {
00468 vp->valueEscape = TRUE;
00469 return TRUE;
00470 };
00471 };
00472 return vcard_add_char_to_line(vp, c);
00473 }
00474 else
00475 return TRUE;
00476 }
00477 break;
00478
00479
00480
00481 case cp_PropData:
00482 switch(c)
00483 {
00484 case '\r':
00485 return TRUE;
00486
00487 case '\n':
00488
00489 if (vp->cardData)
00490 {
00491
00492 if (vp->encoding == cp_EncodingBase64)
00493 {
00494 if (vp->dbLen > 0)
00495 {
00496 while (vp->dbLen != 0)
00497 vcard_process_char(vp, '=');
00498 };
00499 };
00500
00501
00502 if (vp->lbLen > 0)
00503 vp->cardData(vp->userData, vp->lineBuf, vp->lbLen);
00504
00505
00506 vp->cardData(vp->userData, NULL, 0);
00507 };
00508
00509 vcard_clear_line(vp);
00510 return TRUE;
00511
00512 default:
00513 if (vp->startOfData && isspace(c))
00514 return TRUE;
00515 else
00516 vp->startOfData = FALSE;
00517
00518
00519 if (vp->cardData)
00520 {
00521 switch (vp->encoding)
00522 {
00523 case cp_EncodingBase64:
00524 if (vp->dbLen < 4)
00525 {
00526
00527
00528 if (! isspace(c))
00529 {
00530 vp->decodeBuf[vp->dbLen] = c;
00531 vp->dbLen++;
00532 };
00533 };
00534 if (vp->dbLen < 4)
00535 return TRUE;
00536
00537
00538 u0 = Base64ToOrd(vp->decodeBuf[0]);
00539 u1 = Base64ToOrd(vp->decodeBuf[1]);
00540 u2 = Base64ToOrd(vp->decodeBuf[2]);
00541 u3 = Base64ToOrd(vp->decodeBuf[3]);
00542
00543 if (u0 == 0xFF || u1 == 0xFF)
00544 return FALSE;
00545 ch = ((u0 << 2) | (u1 >> 4));
00546 vcard_add_char_to_line(vp, ch);
00547
00548 if (vp->decodeBuf[2] != '=')
00549 {
00550 if (u1 == 0xFF || u2 == 0xFF)
00551 return FALSE;
00552 ch = (((u1 & 0xF) << 4) | (u2 >> 2));
00553 vcard_add_char_to_line(vp, ch);
00554
00555 if (vp->decodeBuf[3] != '=')
00556 {
00557 if (u2 == 0xFF || u3 == 0xFF)
00558 return FALSE;
00559 ch = (((u2 & 0x3) << 6) | u3);
00560 vcard_add_char_to_line(vp, ch);
00561 }
00562 }
00563
00564 memset(vp->decodeBuf, 0, sizeof(vp->decodeBuf));
00565 vp->dbLen = 0;
00566 return TRUE;
00567
00568 case cp_EncodingQP:
00569 if (vp->decoding)
00570 {
00571 if (vp->decodeBuf[0] == 0)
00572 {
00573 vp->decodeBuf[0] = c;
00574 return TRUE;
00575 }
00576 else
00577 {
00578
00579
00580 x = 0;
00581 vp->decodeBuf[1] = c;
00582 vp->decodeBuf[2] = 0;
00583 sscanf(vp->decodeBuf, "%X", &x);
00584 c = x;
00585 vp->decoding = FALSE;
00586 break;
00587 }
00588 }
00589 else if (c == '=')
00590 {
00591 vp->decoding = TRUE;
00592 memset(vp->decodeBuf, 0, sizeof(vp->decodeBuf));
00593 vp->dbLen = 0;
00594 return TRUE;
00595 };
00596 break;
00597 };
00598
00599 vcard_add_char_to_line(vp, c);
00600 };
00601 return TRUE;
00602 };
00603 };
00604
00605 return TRUE;
00606 };
00607
00621 int CARD_Parse(CARD_Parser p, const char *s, int len, int isFinal)
00622 {
00623 int i;
00624 char c;
00625 VP *vp = (VP *) p;
00626
00627
00628 for (i = 0; i < len; i++)
00629 {
00630 c = s[i];
00631
00632
00633 if (vp->startOfLine)
00634 {
00635 if (! vp->folding && isspace(c))
00636 {
00637
00638 vp->folding = TRUE;
00639 continue;
00640 }
00641
00642
00643 vp->startOfLine = FALSE;
00644
00645
00646 if (vp->folding)
00647 {
00648
00649 if (vp->encoding == cp_EncodingQP)
00650 vp->decoding = FALSE;
00651 vcard_process_char(vp, ' ');
00652 }
00653 else
00654 vcard_process_char(vp, '\n');
00655 };
00656
00657
00658 if (c == '\n')
00659 {
00660 vp->startOfLine = TRUE;
00661 vp->folding = FALSE;
00662 }
00663 else
00664 {
00665
00666 if (! vcard_process_char(vp, c))
00667 return 0;
00668 };
00669 };
00670
00671 if (isFinal)
00672 {
00673
00674 vcard_process_char(vp, '\n');
00675 };
00676
00677 return TRUE;
00678 };
00679
00680
00688 void CARD_SetUserData(CARD_Parser p, void *userData)
00689 {
00690 VP *vp = (VP *) p;
00691
00692 vp->userData = userData;
00693 };
00694
00700 void *CARD_GetUserData(CARD_Parser p)
00701 {
00702 VP *vp = (VP *) p;
00703
00704 return vp->userData;
00705 };
00706
00713 void CARD_SetPropHandler(CARD_Parser p, CARD_PropHandler cardProp)
00714 {
00715 VP *vp = (VP *) p;
00716
00717 vp->cardProp = cardProp;
00718 };
00719
00726 void CARD_SetDataHandler(CARD_Parser p, CARD_DataHandler cardData)
00727 {
00728 VP *vp = (VP *) p;
00729
00730 vp->cardData = cardData;
00731 };
00732