Main Page   File List   Globals   Related Pages  

cardparser.c

Go to the documentation of this file.
00001 
00068 /*
00069 Licensing : All code is under the Mozilla Public License 1.1 (MPL 1.1) as specified in 
00070 license.txt
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 implementation
00090 */
00091 
00092 /* version */
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         /* folding stuff */
00104         int startOfLine;
00105         int folding;
00106 
00107         /* inital buffer */
00108         char *lineBuf;
00109         int lbSize;
00110         int lbLen;
00111 
00112         /* line parsing state */
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         /* user data (duh!) */
00125         void *userData;
00126 
00127         /* handlers */
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         /* folding stuff */
00169         vp->startOfLine = TRUE;
00170         vp->folding = FALSE;
00171 
00172         /* init line stuff */
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         /* expand buf if neccessary */
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                         /* memory failure, crash & burn */
00203                         vp->lbSize = 0;
00204                         vp->lbLen = 0;
00205                         return FALSE;
00206                 };
00207 
00208         };
00209 
00210         /* place in linebuf */
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                 /* null terminate the line buf */
00251                 if (! vcard_add_char_to_line(vp, 0))
00252                         return FALSE;
00253 
00254                 /* propname */
00255                 b = vp->lineBuf;
00256                 propName = b;
00257                 
00258                 /* fix up params & values */
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                         /* check for encodings, needlessly complicated by solo value string
00266                            dumb spec choice */
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                 /* null terminate */
00284                 card_add_param(vp, 0);
00285 
00286                 /* do callback */
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 /*  Base64 Chars 
00297     ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ 
00298     Folling func translates a base64 char to its ordinal val
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     // for qp decoding
00324         int x;
00325     // for base64 decoding
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         /* Property Names */
00336         case cp_PropName:
00337                 /* looking for eof propName delim */
00338                 switch(c)
00339                 {
00340                 case ':':
00341                         vcard_end_prop(vp);
00342                         return TRUE;
00343 
00344                 case ';':
00345                         /* we have parameters - null terminate name */
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                         /* throw it all away */
00354                         vcard_clear_line(vp);
00355                         return TRUE;
00356 
00357                 default:
00358                         /* just add */
00359                         if (! isspace(c))
00360                                 return vcard_add_char_to_line(vp, c);
00361                         else
00362                                 return TRUE;
00363                 };
00364                 break;
00365 
00366         /* --------------------------------------- */
00367         /* Param Names */
00368         case cp_ParamBN: /* before name */
00369                 switch(c)
00370                 {
00371                 case ':':
00372                         /* error */
00373                         vcard_clear_line(vp); 
00374                         return FALSE;
00375 
00376                 default:
00377                         if (isspace(c))
00378                                 return TRUE; /* ignore */
00379 
00380                         /* start name - store as offset into lineBuf, as lineBuf may move when reallocated */
00381                         card_add_param(vp, vp->lbLen);
00382 
00383                         /* now in name */
00384                         vp->state = cp_ParamIN;
00385                         return vcard_add_char_to_line(vp, c);
00386                 };
00387                 break;
00388 
00389         case cp_ParamIN: /* in name */
00390                 switch(c)
00391                 {
00392                 case '=':
00393                         /* eof param name, value follows */
00394                         vp->state = cp_ValueBV;
00395                         return vcard_add_char_to_line(vp, 0); /* terminate param name */
00396 
00397                 case ';':
00398                         /* eof param, start new param */
00399                         vp->state = cp_ParamBN;
00400                         return vcard_add_char_to_line(vp, 0); /* terminate param name */
00401 
00402                 case ':':
00403                         /* eof param, into data */
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         /* Param Values */
00417         case cp_ValueBV: /* before value */
00418                 switch(c)
00419                 {
00420                 case ';':
00421                 case ':':
00422                         /* error ? can we have empty values (ie. "name=;" or "name=:") */
00423                         vcard_clear_line(vp); 
00424                         return FALSE;
00425 
00426                 default:
00427                         if (isspace(c))
00428                                 return TRUE; /* ignore */
00429 
00430                         /* start value - store as offset into lineBuf, as lineBuf may move */
00431                         card_set_paramvalue(vp, vp->lbLen);
00432 
00433                         /* now in Value */
00434                         vp->state = cp_ValueIV;
00435                         return vcard_add_char_to_line(vp, c);
00436                 };
00437                 break;
00438 
00439         case cp_ValueIV: /* in value */
00440                 switch(c)
00441                 {
00442                 case ';':
00443                         if (vp->valueEscape)
00444                         {
00445                                 /* just add to value */
00446                                 vp->valueEscape = FALSE;
00447                                 return vcard_add_char_to_line(vp, c);
00448                         };
00449 
00450                         /* eof value, start new param */
00451                         vp->state = cp_ParamBN;
00452                         return vcard_add_char_to_line(vp, 0); /* terminate value */
00453 
00454                 case ':':
00455                         /* eof value, into data */
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; /* unescaping now */
00466                                         else
00467                                         {
00468                                                 vp->valueEscape = TRUE; /* escaping now */
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         /* Property Data */
00481         case cp_PropData:
00482                 switch(c)
00483                 {
00484                 case '\r':
00485                         return TRUE;
00486 
00487                 case '\n':
00488                         /* terminate data */
00489                         if (vp->cardData)
00490                         {
00491                 /* check for improperly terminated base64 encoding */
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                                 /* report any data */
00502                                 if (vp->lbLen > 0)
00503                                         vp->cardData(vp->userData, vp->lineBuf, vp->lbLen);
00504 
00505                                 /* terminate data */
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                         /* only store data if we bother reporting it */
00519                         if (vp->cardData)
00520                         {
00521                                 switch (vp->encoding)
00522                                 {
00523                 case cp_EncodingBase64:
00524                     if (vp->dbLen < 4)
00525                     {
00526                         // add to decode buf
00527                         // may have trailing ws on lines, so ignore
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                     // we have a quartet
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                                                         /* decoding
00579                                                            finished */
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; /* drops down to add char */
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         /* add to lineBuf */
00628         for (i = 0; i < len; i++)
00629         {
00630                 c = s[i];
00631 
00632                 /* check start of line whitespace/folding */
00633                 if (vp->startOfLine)
00634                 {
00635                         if (! vp->folding && isspace(c))
00636                         {
00637                                 /* we are folding, carry on */
00638                                 vp->folding = TRUE;
00639                                 continue;
00640                         }
00641 
00642                         /* no longer start of line */
00643                         vp->startOfLine = FALSE;
00644 
00645                         /* either are folding or can terminate last line */
00646                         if (vp->folding)
00647                         {
00648                                 /* cancel any qp encoding as it does not continue across folding breaks */
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                         /* add to lineBuf */
00666                         if (! vcard_process_char(vp, c))
00667                                 return 0;
00668                 };
00669         };
00670 
00671         if (isFinal)
00672         {
00673                 /* terminate  */
00674                 vcard_process_char(vp, '\n');
00675         };
00676 
00677         return TRUE;
00678 };
00679 
00680 /* user data */
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 

Generated on Fri Apr 25 15:56:55 2003 for ccard by doxygen1.3-rc3