diff options
Diffstat (limited to 'src/libicalvcal/vcc.c')
-rw-r--r-- | src/libicalvcal/vcc.c | 1636 |
1 files changed, 1636 insertions, 0 deletions
diff --git a/src/libicalvcal/vcc.c b/src/libicalvcal/vcc.c new file mode 100644 index 00000000..7fcf6624 --- /dev/null +++ b/src/libicalvcal/vcc.c @@ -0,0 +1,1636 @@ +#ifndef lint +static const char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; +#endif + +#include <stdlib.h> +#include <string.h> +#include <stddef.h> /* for ptrdiff_h */ + +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYPATCH 20070509 + +#define YYEMPTY (-1) +#define yyclearin (yychar = YYEMPTY) +#define yyerrok (yyerrflag = 0) +#define YYRECOVERING (yyerrflag != 0) + +extern int yyparse(void); + +static int yygrowstack(void); + +/*************************************************************************** +(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. + +For purposes of this license notice, the term Licensors shall mean, +collectively, Apple Computer, Inc., AT&T Corp., International +Business Machines Corporation and Siemens Rolm Communications Inc. +The term Licensor shall mean any of the Licensors. + +Subject to acceptance of the following conditions, permission is hereby +granted by Licensors without the need for written agreement and without +license or royalty fees, to use, copy, modify and distribute this +software for any purpose. + +The above copyright notice and the following four paragraphs must be +reproduced in all copies of this software and any software including +this software. + +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE +ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR +MODIFICATIONS. + +IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, +INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT +OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. + +The software is provided with RESTRICTED RIGHTS. Use, duplication, or +disclosure by the government are subject to restrictions set forth in +DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable. + +***************************************************************************/ + +/* + * src: vcc.c + * doc: Parser for vCard and vCalendar. Note that this code is + * generated by a yacc parser generator. Generally it should not + * be edited by hand. The real source is vcc.y. The #line directives + * can be commented out here to make it easier to trace through + * in a debugger. However, if a bug is found it should + * be fixed in vcc.y and this file regenerated. + */ + + +/* debugging utilities */ +#if __DEBUG +#define DBG_(x) printf x +#else +#define DBG_(x) +#endif + +#if defined(_MSC_VER) +#define snprintf _snprintf +#define strcasecmp stricmp +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#define yyparse mime_parse +#define yylex mime_lex +#define yyerror mime_error +#define yychar mime_char +/* #define p_yyval p_mime_val */ +#undef yyval +#define yyval mime_yyval +/* #define p_yylval p_mime_lval */ +#undef yylval +#define yylval mime_yylval +#define yydebug mime_debug +#define yynerrs mime_nerrs +#define yyerrflag mime_errflag +#define yyss mime_ss +#define yyssp mime_ssp +#define yyvs mime_vs +#define yyvsp mime_vsp +#define yylhs mime_lhs +#define yylen mime_len +#define yydefred mime_defred +#define yydgoto mime_dgoto +#define yysindex mime_sindex +#define yyrindex mime_rindex +#define yygindex mime_gindex +#define yytable mime_table +#define yycheck mime_check +#define yyname mime_name +#define yyrule mime_rule +#define YYPREFIX "mime_" + + +#ifndef _NO_LINE_FOLDING +#define _SUPPORT_LINE_FOLDING 1 +#endif + +/* undef below if compile with MFC */ +/* #define INCLUDEMFC 1 */ + +#if defined(WIN32) || defined(_WIN32) +#ifdef INCLUDEMFC +#include <afx.h> +#endif +#endif + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include "vcc.h" + +/**** Types, Constants ****/ + +#define YYDEBUG 1 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 50 /* ~unref ? */ +#define MAXLEVEL 10 /* max # of nested objects parseable */ + /* (includes outermost) */ + + +/**** Global Variables ****/ +int mime_lineNum, mime_numErrors; /* yyerror() can use these */ +static VObject* vObjList; +static VObject *curProp; +static VObject *curObj; +static VObject* ObjStack[MAXLEVEL]; +static int ObjStackTop; + + +/* A helpful utility for the rest of the app. */ +#if __CPLUSPLUS__ +extern "C" { +#endif + + extern void Parse_Debug(const char *s); + static void yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yylex(void); +int yyparse(void); + +enum LexMode { + L_NORMAL, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static void lexClearToken(void); +static char* lexGet1Value(void); +static int lexGeta(void); +static int lexGetc(void); +static char lexGetc_(void); +static char* lexGetDataFromBase64(void); +static char* lexGetQuotedPrintable(void); +static char* lexGetWord(void); +static int lexLookahead(void); +static char* lexLookaheadWord(void); +static void lexPopMode(int top); +static void lexPushMode(enum LexMode mode); +static void lexSkipLookahead(void); +static void lexSkipLookaheadWord(void); +static void lexSkipWhite(void); +static char* lexStr(void); +static int lexWithinMode(enum LexMode mode); +static void enterAttr(const char *s1, const char *s2); +static void enterProps(const char *s); +static void enterValues(const char *value); +static void finiLex(void); +static void mime_error_(char *s); +static VObject* Parse_MIMEHelper(void); +static VObject* popVObject(void); +static int pushVObject(const char *prop); + +typedef union { + char *str; + VObject *vobj; + } YYSTYPE; +#define EQ 257 +#define COLON 258 +#define DOT 259 +#define SEMICOLON 260 +#define SPACE 261 +#define HTAB 262 +#define LINESEP 263 +#define NEWLINE 264 +#define BEGIN_VCARD 265 +#define END_VCARD 266 +#define BEGIN_VCAL 267 +#define END_VCAL 268 +#define BEGIN_VEVENT 269 +#define END_VEVENT 270 +#define BEGIN_VTODO 271 +#define END_VTODO 272 +#define ID 273 +#define STRING 274 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 7, 6, 6, 5, 5, 9, 3, 10, 3, + 8, 8, 14, 11, 11, 16, 12, 12, 15, 15, + 17, 18, 18, 1, 19, 13, 13, 2, 2, 21, + 4, 22, 4, 20, 20, 23, 23, 23, 26, 24, + 27, 24, 28, 25, 29, 25, +}; +short yylen[] = { 2, + 1, 0, 3, 1, 1, 1, 0, 4, 0, 3, + 2, 1, 0, 5, 1, 0, 3, 1, 2, 1, + 2, 1, 3, 1, 0, 4, 1, 1, 0, 0, + 4, 0, 3, 2, 1, 1, 1, 1, 0, 4, + 0, 3, 0, 4, 0, 3, +}; +short yydefred[] = { 0, + 0, 0, 0, 5, 6, 0, 1, 0, 0, 0, + 0, 0, 15, 24, 0, 0, 0, 0, 10, 0, + 0, 38, 0, 0, 36, 37, 33, 3, 0, 8, + 11, 13, 0, 0, 0, 0, 31, 34, 0, 17, + 0, 0, 0, 42, 0, 46, 0, 21, 19, 28, + 0, 0, 40, 44, 0, 25, 14, 23, 0, 26, +}; +short yydgoto[] = { 3, + 15, 51, 4, 5, 6, 7, 12, 22, 8, 9, + 17, 18, 52, 42, 40, 29, 41, 48, 59, 23, + 10, 11, 24, 25, 26, 33, 34, 35, 36, +}; +short yysindex[] = { -227, + 0, 0, 0, 0, 0, 0, 0, -249, -262, -253, + -258, -227, 0, 0, 0, -234, -249, -215, 0, 0, + 0, 0, -223, -253, 0, 0, 0, 0, -247, 0, + 0, 0, -249, -222, -249, -225, 0, 0, -224, 0, + -247, -221, -220, 0, -218, 0, -206, 0, 0, 0, + -208, -207, 0, 0, -224, 0, 0, 0, -221, 0, +}; +short yyrindex[] = { 0, + -245, -254, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, -219, 0, -235, 0, 0, -244, + -250, 0, 0, -213, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -201, -255, 0, 0, 0, 0, -216, 0, 0, 0, + -205, 0, 0, 0, 0, 0, 0, 0, -255, 0, +}; +short yygindex[] = { 0, + -9, 0, 0, 0, 0, 47, 0, -8, 0, 0, + 0, 0, 2, 0, 19, 0, 0, 0, 0, 38, + 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define YYTABLESIZE 268 +short yytable[] = { 16, + 4, 30, 13, 19, 29, 43, 13, 29, 31, 27, + 7, 39, 39, 32, 30, 20, 30, 21, 30, 14, + 9, 45, 43, 14, 43, 41, 45, 7, 39, 47, + 12, 30, 12, 12, 12, 12, 12, 1, 18, 2, + 16, 22, 32, 22, 37, 58, 46, 44, 14, 53, + 55, 56, 50, 54, 35, 57, 20, 27, 28, 49, + 60, 38, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 0, 2, +}; +short yycheck[] = { 8, + 0, 256, 256, 266, 260, 256, 256, 263, 17, 268, + 256, 256, 260, 268, 269, 269, 271, 271, 273, 273, + 266, 272, 273, 273, 33, 270, 35, 273, 273, 39, + 266, 266, 268, 269, 270, 271, 272, 265, 258, 267, + 260, 258, 258, 260, 268, 55, 272, 270, 273, 270, + 257, 260, 274, 272, 268, 263, 258, 263, 12, 41, + 59, 24, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 265, -1, 267, +}; +#define YYFINAL 3 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 274 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"EQ","COLON","DOT","SEMICOLON", +"SPACE","HTAB","LINESEP","NEWLINE","BEGIN_VCARD","END_VCARD","BEGIN_VCAL", +"END_VCAL","BEGIN_VEVENT","END_VEVENT","BEGIN_VTODO","END_VTODO","ID","STRING", +}; +char *yyrule[] = { +"$accept : mime", +"mime : vobjects", +"$$1 :", +"vobjects : vobject $$1 vobjects", +"vobjects : vobject", +"vobject : vcard", +"vobject : vcal", +"$$2 :", +"vcard : BEGIN_VCARD $$2 items END_VCARD", +"$$3 :", +"vcard : BEGIN_VCARD $$3 END_VCARD", +"items : item items", +"items : item", +"$$4 :", +"item : prop COLON $$4 values LINESEP", +"item : error", +"$$5 :", +"prop : name $$5 attr_params", +"prop : name", +"attr_params : attr_param attr_params", +"attr_params : attr_param", +"attr_param : SEMICOLON attr", +"attr : name", +"attr : name EQ name", +"name : ID", +"$$6 :", +"values : value SEMICOLON $$6 values", +"values : value", +"value : STRING", +"value :", +"$$7 :", +"vcal : BEGIN_VCAL $$7 calitems END_VCAL", +"$$8 :", +"vcal : BEGIN_VCAL $$8 END_VCAL", +"calitems : calitem calitems", +"calitems : calitem", +"calitem : eventitem", +"calitem : todoitem", +"calitem : items", +"$$9 :", +"eventitem : BEGIN_VEVENT $$9 items END_VEVENT", +"$$10 :", +"eventitem : BEGIN_VEVENT $$10 END_VEVENT", +"$$11 :", +"todoitem : BEGIN_VTODO $$11 items END_VTODO", +"$$12 :", +"todoitem : BEGIN_VTODO $$12 END_VTODO", +}; +#endif +#if YYDEBUG +#include <stdio.h> +#endif + +/* define the initial stack-sizes */ +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif + +#define YYINITSTACKSIZE 500 + +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; + +/* variables for the parser stack */ +static short *yyss; +static short *yysslim; +static YYSTYPE *yyvs; +static int yystacksize; +static int pushVObject(const char *prop) + { + VObject *newObj; + if (ObjStackTop == MAXLEVEL) + return FALSE; + + ObjStack[++ObjStackTop] = curObj; + + if (curObj) { + newObj = addProp(curObj,prop); + curObj = newObj; + } + else + curObj = newVObject(prop); + + return TRUE; + } + + +/* This pops the recently built vCard off the stack and returns it. */ +static VObject* popVObject() + { + VObject *oldObj; + if (ObjStackTop < 0) { + yyerror("pop on empty Object Stack\n"); + return 0; + } + oldObj = curObj; + curObj = ObjStack[ObjStackTop--]; + + return oldObj; + } + + +static void enterValues(const char *value) + { + if (fieldedProp && *fieldedProp) { + if (value) { + addPropValue(curProp,*fieldedProp,value); + } + /* else this field is empty, advance to next field */ + fieldedProp++; + } + else { + if (value) { + char *p1, *p2; + wchar_t *p3; + size_t i; + + /* If the property already has a string value, we append this one, + using ';' to separate the values. */ + if (vObjectUStringZValue(curProp)) { + p1 = fakeCString(vObjectUStringZValue(curProp)); + i = strlen(p1)+strlen(value)+2; + p2 = malloc(i); + snprintf(p2,i,"%s;%s",p1,value); + deleteStr(p1); + p3 = (wchar_t *) vObjectUStringZValue(curProp); + free(p3); + setVObjectUStringZValue_(curProp,fakeUnicode(p2,0)); + deleteStr(p2); + } else { + setVObjectUStringZValue_(curProp,fakeUnicode(value,0)); + } + } + } + deleteStr(value); + } + +static void enterProps(const char *s) + { + curProp = addGroup(curObj,s); + deleteStr(s); + } + +static void enterAttr(const char *s1, const char *s2) + { + const char *p1, *p2 = NULL; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + if (stricmp(p1,VCBase64Prop) == 0 || (s2 && stricmp(p2,VCBase64Prop)==0)) + lexPushMode(L_BASE64); + else if (stricmp(p1,VCQuotedPrintableProp) == 0 + || (s2 && stricmp(p2,VCQuotedPrintableProp)==0)) + lexPushMode(L_QUOTED_PRINTABLE); + deleteStr(s1); deleteStr(s2); + } + + +#define MAX_LEX_LOOKAHEAD_0 32 +#define MAX_LEX_LOOKAHEAD 64 +#define MAX_LEX_MODE_STACK_SIZE 10 +#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop]) + +struct LexBuf { + /* input */ +#ifdef INCLUDEMFC + CFile *inputFile; +#else + FILE *inputFile; +#endif + char *inputString; + unsigned long curPos; + unsigned long inputLen; + /* lookahead buffer */ + /* -- lookahead buffer is short instead of char so that EOF + / can be represented correctly. + */ + unsigned long len; + short buf[MAX_LEX_LOOKAHEAD]; + unsigned long getPtr; + /* context stack */ + unsigned long lexModeStackTop; + enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE]; + /* token buffer */ + unsigned long maxToken; + char *strs; + unsigned long strsLen; + } lexBuf; + +static void lexPushMode(enum LexMode mode) + { + if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1)) + yyerror("lexical context stack overflow"); + else { + lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode; + } + } + +static void lexPopMode(int top) + { + /* special case of pop for ease of error recovery -- this + version will never underflow */ + if (top) + lexBuf.lexModeStackTop = 0; + else + if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--; + } + +static int lexWithinMode(enum LexMode mode) { + unsigned long i; + for (i=0;i<lexBuf.lexModeStackTop;i++) + if (mode == lexBuf.lexModeStack[i]) return 1; + return 0; + } + +static char lexGetc_() + { + /* get next char from input, no buffering. */ + if (lexBuf.curPos == lexBuf.inputLen) + return EOF; + else if (lexBuf.inputString) + return *(lexBuf.inputString + lexBuf.curPos++); + else { +#ifdef INCLUDEMFC + char result; + return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF; +#else + return fgetc(lexBuf.inputFile); +#endif + } + } + +static int lexGeta() + { + ++lexBuf.len; + return (lexBuf.buf[lexBuf.getPtr] = lexGetc_()); + } + +static int lexGeta_(int i) + { + ++lexBuf.len; + return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_()); + } + +static void lexSkipLookahead() { + if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) { + /* don't skip EOF. */ + lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD; + lexBuf.len--; + } + } + +static int lexLookahead() { + int c = (lexBuf.len)? + lexBuf.buf[lexBuf.getPtr]: + lexGeta(); + /* do the \r\n -> \n or \r -> \n translation here */ + if (c == '\r') { + int a = (lexBuf.len>1)? + lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]: + lexGeta_(1); + if (a == '\n') { + lexSkipLookahead(); + } + lexBuf.buf[lexBuf.getPtr] = c = '\n'; + } + else if (c == '\n') { + int a = (lexBuf.len>1)? + lexBuf.buf[lexBuf.getPtr+1]: + lexGeta_(1); + if (a == '\r') { + lexSkipLookahead(); + } + lexBuf.buf[lexBuf.getPtr] = '\n'; + } + return c; + } + +static int lexGetc() { + int c = lexLookahead(); + if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) { + /* EOF will remain in lookahead buffer */ + lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD; + lexBuf.len--; + } + return c; + } + +static void lexSkipLookaheadWord() { + if (lexBuf.strsLen <= lexBuf.len) { + lexBuf.len -= lexBuf.strsLen; + lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD; + } + } + +static void lexClearToken() + { + lexBuf.strsLen = 0; + } + +static void lexAppendc(int c) + { + lexBuf.strs[lexBuf.strsLen] = c; + /* append up to zero termination */ + if (c == 0) return; + lexBuf.strsLen++; + if (lexBuf.strsLen >= lexBuf.maxToken) { + /* double the token string size */ + lexBuf.maxToken <<= 1; + lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken); + } + } + +static char* lexStr() { + return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1); + } + +static void lexSkipWhite() { + int c = lexLookahead(); + while (c == ' ' || c == '\t') { + lexSkipLookahead(); + c = lexLookahead(); + } + } + +static char* lexGetWord() { + int c; + lexSkipWhite(); + lexClearToken(); + c = lexLookahead(); + while (c != EOF && !strchr("\t\n ;:=",c)) { + lexAppendc(c); + lexSkipLookahead(); + c = lexLookahead(); + } + lexAppendc(0); + return lexStr(); + } + +static void lexPushLookaheadc(int c) { + int putptr; + /* can't putback EOF, because it never leaves lookahead buffer */ + if (c == EOF) return; + putptr = (int)lexBuf.getPtr - 1; + if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD; + lexBuf.getPtr = putptr; + lexBuf.buf[putptr] = c; + lexBuf.len += 1; + } + +static char* lexLookaheadWord() { + /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0 + / and thing bigger than that will stop the lookahead and return 0; + / leading white spaces are not recoverable. + */ + int c; + int len = 0; + int curgetptr = 0; + lexSkipWhite(); + lexClearToken(); + curgetptr = (int)lexBuf.getPtr; /* remember! */ + while (len < (MAX_LEX_LOOKAHEAD_0)) { + c = lexGetc(); + len++; + if (c == EOF || strchr("\t\n ;:=", c)) { + lexAppendc(0); + /* restore lookahead buf. */ + lexBuf.len += len; + lexBuf.getPtr = curgetptr; + return lexStr(); + } + else + lexAppendc(c); + } + lexBuf.len += len; /* char that has been moved to lookahead buffer */ + lexBuf.getPtr = curgetptr; + return 0; + } + +#ifdef _SUPPORT_LINE_FOLDING +static void handleMoreRFC822LineBreak(int c) { + /* suport RFC 822 line break in cases like + * ADR: foo; + * morefoo; + * more foo; + */ + if (c == ';') { + int a; + lexSkipLookahead(); + /* skip white spaces */ + a = lexLookahead(); + while (a == ' ' || a == '\t') { + lexSkipLookahead(); + a = lexLookahead(); + } + if (a == '\n') { + lexSkipLookahead(); + a = lexLookahead(); + if (a == ' ' || a == '\t') { + /* continuation, throw away all the \n and spaces read so + * far + */ + lexSkipWhite(); + lexPushLookaheadc(';'); + } + else { + lexPushLookaheadc('\n'); + lexPushLookaheadc(';'); + } + } + else { + lexPushLookaheadc(';'); + } + } + } + +static char* lexGet1Value() { + int c; + lexSkipWhite(); + c = lexLookahead(); + lexClearToken(); + while (c != EOF && c != ';') { + if (c == '\n') { + int a; + lexSkipLookahead(); + a = lexLookahead(); + if (a == ' ' || a == '\t') { + lexAppendc(' '); + lexSkipLookahead(); + } + else { + lexPushLookaheadc('\n'); + break; + } + } + else { + lexAppendc(c); + lexSkipLookahead(); + } + c = lexLookahead(); + } + lexAppendc(0); + handleMoreRFC822LineBreak(c); + return c==EOF?0:lexStr(); + } +#endif + + +static int match_begin_name(int end) { + char *n = lexLookaheadWord(); + int token = ID; + if (n) { + if (!stricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!stricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!stricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!stricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO; + deleteStr(n); + return token; + } + return 0; + } + + +#ifdef INCLUDEMFC +void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile) +#else +void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile) +#endif + { + /* initialize lex mode stack */ + lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL; + + /* iniatialize lex buffer. */ + lexBuf.inputString = (char*) inputstring; + lexBuf.inputLen = inputlen; + lexBuf.curPos = 0; + lexBuf.inputFile = inputfile; + + lexBuf.len = 0; + lexBuf.getPtr = 0; + + lexBuf.maxToken = MAXTOKEN; + lexBuf.strs = (char*)malloc(MAXTOKEN); + lexBuf.strsLen = 0; + + } + +static void finiLex() { + free(lexBuf.strs); + } + + +/* This parses and converts the base64 format for binary encoding into + * a decoded buffer (allocated with new). See RFC 1521. + */ +static char * lexGetDataFromBase64() + { + unsigned long bytesLen = 0, bytesMax = 0; + int quadIx = 0, pad = 0; + unsigned long trip = 0; + unsigned char b; + int c; + unsigned char *bytes = NULL; + unsigned char *oldBytes = NULL; + + DBG_(("db: lexGetDataFromBase64\n")); + while (1) { + c = lexGetc(); + if (c == '\n') { + ++mime_lineNum; + if (lexLookahead() == '\n') { + /* a '\n' character by itself means end of data */ + break; + } + else continue; /* ignore '\n' */ + } + else { + if ((c >= 'A') && (c <= 'Z')) + b = (unsigned char)(c - 'A'); + else if ((c >= 'a') && (c <= 'z')) + b = (unsigned char)(c - 'a') + 26; + else if ((c >= '0') && (c <= '9')) + b = (unsigned char)(c - '0') + 52; + else if (c == '+') + b = 62; + else if (c == '/') + b = 63; + else if (c == '=') { + b = 0; + pad++; + } else if ((c == ' ') || (c == '\t')) { + continue; + } else { /* error condition */ + if (bytes) free(bytes); + else if (oldBytes) free(oldBytes); + /* error recovery: skip until 2 adjacent newlines. */ + DBG_(("db: invalid character 0x%x '%c'\n", c,c)); + if (c != EOF) { + c = lexGetc(); + while (c != EOF) { + if (c == '\n' && lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + c = lexGetc(); + } + } + return NULL; + } + trip = (trip << 6) | b; + if (++quadIx == 4) { + unsigned char outBytes[3]; + int numOut; + int i; + for (i = 0; i < 3; i++) { + outBytes[2-i] = (unsigned char)(trip & 0xFF); + trip >>= 8; + } + numOut = 3 - pad; + if (bytesLen + numOut > bytesMax) { + if (!bytes) { + bytesMax = 1024; + bytes = (unsigned char*)malloc((size_t)bytesMax); + } + else { + bytesMax <<= 2; + oldBytes = bytes; + bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax); + } + if (bytes == 0) { + mime_error("out of memory while processing BASE64 data\n"); + } + } + if (bytes) { + memcpy(bytes + bytesLen, outBytes, numOut); + bytesLen += numOut; + } + trip = 0; + quadIx = 0; + } + } + } /* while */ + DBG_(("db: bytesLen = %d\n", bytesLen)); + /* kludge: all this won't be necessary if we have tree form + representation */ + if (bytes) { + setValueWithSize(curProp,bytes,(unsigned int)bytesLen); + free(bytes); + } + else if (oldBytes) { + setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen); + free(oldBytes); + } + return 0; + } + +static int match_begin_end_name(int end) { + int token; + lexSkipWhite(); + if (lexLookahead() != ':') return ID; + lexSkipLookahead(); + lexSkipWhite(); + token = match_begin_name(end); + if (token == ID) { + lexPushLookaheadc(':'); + DBG_(("db: ID '%s'\n", yylval.str)); + return ID; + } + else if (token != 0) { + lexSkipLookaheadWord(); + deleteStr(yylval.str); + DBG_(("db: begin/end %d\n", token)); + return token; + } + return 0; + } + +static char* lexGetQuotedPrintable() + { + char cur; + + lexClearToken(); + do { + cur = lexGetc(); + switch (cur) { + case '=': { + int c = 0; + int next[2]; + int i; + for (i = 0; i < 2; i++) { + next[i] = lexGetc(); + if (next[i] >= '0' && next[i] <= '9') + c = c * 16 + next[i] - '0'; + else if (next[i] >= 'A' && next[i] <= 'F') + c = c * 16 + next[i] - 'A' + 10; + else + break; + } + if (i == 0) { + /* single '=' follow by LINESEP is continuation sign? */ + if (next[0] == '\n') { + ++mime_lineNum; + } + else { + lexPushLookaheadc('='); + goto EndString; + } + } + else if (i == 1) { + lexPushLookaheadc(next[1]); + lexPushLookaheadc(next[0]); + lexAppendc('='); + } else { + lexAppendc(c); + } + break; + } /* '=' */ + case '\n': { + lexPushLookaheadc('\n'); + goto EndString; + } + case (char)EOF: + break; + default: + lexAppendc(cur); + break; + } /* switch */ + } while (cur != (char)EOF); + +EndString: + lexAppendc(0); + return lexStr(); + } /* LexQuotedPrintable */ + +int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + if (c == ';') { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); +#ifdef _SUPPORT_LINE_FOLDING + handleMoreRFC822LineBreak(c); +#endif + lexSkipLookahead(); + return SEMICOLON; + } + else if (strchr("\n",c)) { + ++mime_lineNum; + /* consume all line separator(s) adjacent to each other */ + c = lexLookahead(); + while (strchr("\n",c)) { + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; + } + DBG_(("db: LINESEP\n")); + return LINESEP; + } + else { + char *p = 0; + lexPushLookaheadc(c); + if (lexWithinMode(L_BASE64)) { + /* get each char and convert to bin on the fly... */ + p = lexGetDataFromBase64(); + yylval.str = p; + return STRING; + } + else if (lexWithinMode(L_QUOTED_PRINTABLE)) { + p = lexGetQuotedPrintable(); + } + else { +#ifdef _SUPPORT_LINE_FOLDING + p = lexGet1Value(); +#else + p = lexGetStrUntil(";\n"); +#endif + } + if (p) { + DBG_(("db: STRING: '%s'\n", p)); + yylval.str = p; + return STRING; + } + else return 0; + } + } + else { + /* normal mode */ + while (1) { + int c = lexGetc(); + switch(c) { + case ':': { + /* consume all line separator(s) adjacent to each other */ + /* ignoring linesep immediately after colon. */ +/* c = lexLookahead(); + while (strchr("\n",c)) { + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; + }*/ + DBG_(("db: COLON\n")); + return COLON; + } + case ';': + DBG_(("db: SEMICOLON\n")); + return SEMICOLON; + case '=': + DBG_(("db: EQ\n")); + return EQ; + /* ignore whitespace in this mode */ + case '\t': + case ' ': continue; + case '\n': { + ++mime_lineNum; + continue; + } + case EOF: return 0; + break; + default: { + lexPushLookaheadc(c); + if (isalpha(c)) { + char *t = lexGetWord(); + yylval.str = t; + if (!stricmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!stricmp(t,"end")) { + return match_begin_end_name(1); + } + else { + DBG_(("db: ID '%s'\n", t)); + return ID; + } + } + else { + /* unknow token */ + return 0; + } + break; + } + } + } + } + return 0; + } + + +/***************************************************************************/ +/*** Public Functions ****/ +/***************************************************************************/ + +static VObject* Parse_MIMEHelper() + { + ObjStackTop = -1; + mime_numErrors = 0; + mime_lineNum = 1; + vObjList = 0; + curObj = 0; + + if (yyparse() != 0) + return 0; + + finiLex(); + return vObjList; + } + +DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len) + { + initLex(input, len, 0); + return Parse_MIMEHelper(); + } + + +#if INCLUDEMFC + +DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file) + { + unsigned long startPos; + VObject *result; + + initLex(0,-1,file); + startPos = file->GetPosition(); + if (!(result = Parse_MIMEHelper())) + file->Seek(startPos, CFile::begin); + return result; + } + +#else + +VObject* Parse_MIME_FromFile(FILE *file) + { + VObject *result; + long startPos; + + initLex(0,(unsigned long)-1,file); + startPos = ftell(file); + if (!(result = Parse_MIMEHelper())) { + if (startPos >= 0) + fseek(file,startPos,SEEK_SET); + } + return result; + } + +DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname) + { + FILE *fp = fopen(fname,"r"); + if (fp) { + VObject* o = Parse_MIME_FromFile(fp); + fclose(fp); + return o; + } + else { + char msg[256]; + snprintf(msg, sizeof(msg), "can't open file '%s' for reading\n", fname); + mime_error_(msg); + return 0; + } + } + +#endif + + +static MimeErrorHandler mimeErrorHandler; + +DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me) + { + mimeErrorHandler = me; + } + +static void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + snprintf(msg,sizeof(msg),"%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +static void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack(void) +{ + int newsize; + ptrdiff_t i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + + i = yyssp - yyss; + newss = (yyss != 0) + ? (short *)realloc(yyss, newsize * sizeof(*newss)) + : (short *)malloc(newsize * sizeof(*newss)); + if (newss == 0) + return -1; + + yyss = newss; + yyssp = newss + i; + newvs = (yyvs != 0) + ? (YYSTYPE *)realloc(yyvs, newsize * sizeof(*newvs)) + : (YYSTYPE *)malloc(newsize * sizeof(*newvs)); + if (newvs == 0) + return -1; + + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse(void) +{ + register int yym, yyn, yystate; +#if YYDEBUG + register const char *yys; + + if ((yys = getenv("YYDEBUG")) != 0) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = YYEMPTY; + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = YYEMPTY; + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; + + yyerror("syntax error"); + +#ifdef lint + goto yyerrlab; +#endif + +yyerrlab: + ++yynerrs; + +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = YYEMPTY; + goto yyloop; + } + +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + if (yym) + yyval = yyvsp[1-yym]; + else + memset(&yyval, 0, sizeof yyval); + switch (yyn) + { +case 2: +{ addList(&vObjList, yyvsp[0].vobj); curObj = 0; } +break; +case 4: +{ addList(&vObjList, yyvsp[0].vobj); curObj = 0; } +break; +case 7: +{ + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } +break; +case 8: +{ + lexPopMode(0); + yyval.vobj = popVObject(); + } +break; +case 9: +{ + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } +break; +case 10: +{ + lexPopMode(0); + yyval.vobj = popVObject(); + } +break; +case 13: +{ + lexPushMode(L_VALUES); + } +break; +case 14: +{ + if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) + lexPopMode(0); + lexPopMode(0); + } +break; +case 16: +{ + enterProps(yyvsp[0].str); + } +break; +case 18: +{ + enterProps(yyvsp[0].str); + } +break; +case 22: +{ + enterAttr(yyvsp[0].str,0); + } +break; +case 23: +{ + enterAttr(yyvsp[-2].str,yyvsp[0].str); + + } +break; +case 25: +{ enterValues(yyvsp[-1].str); } +break; +case 27: +{ enterValues(yyvsp[0].str); } +break; +case 29: +{ yyval.str = 0; } +break; +case 30: +{ if (!pushVObject(VCCalProp)) YYERROR; } +break; +case 31: +{ yyval.vobj = popVObject(); } +break; +case 32: +{ if (!pushVObject(VCCalProp)) YYERROR; } +break; +case 33: +{ yyval.vobj = popVObject(); } +break; +case 39: +{ + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } +break; +case 40: +{ + lexPopMode(0); + popVObject(); + } +break; +case 41: +{ + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } +break; +case 42: +{ + lexPopMode(0); + popVObject(); + } +break; +case 43: +{ + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } +break; +case 44: +{ + lexPopMode(0); + popVObject(); + } +break; +case 45: +{ + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } +break; +case 46: +{ + lexPopMode(0); + popVObject(); + } +break; + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; + +yyoverflow: + yyerror("yacc stack overflow"); + +yyabort: + return (1); + +yyaccept: + return (0); +} |