From bb7cd69b07a5d6e00a29b23dc8bfebc511d34891 Mon Sep 17 00:00:00 2001 From: schurig Date: Wed, 15 Sep 2004 09:52:10 +0000 Subject: changed CDLF into CR --- (limited to 'library/backend') diff --git a/library/backend/vcc.y b/library/backend/vcc.y index 00e8fed..911e42c 100644 --- a/library/backend/vcc.y +++ b/library/backend/vcc.y @@ -1,1248 +1,1248 @@ -%{ - -/*************************************************************************** -(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 */ -#define __DEBUG 1 - -#if __DEBUG -#define DBG_(x) printf x -#else -#define DBG_(x) -#endif - -/**** External Functions ****/ - -/* assign local name to parser variables and functions so that - we can use more than one yacc based parser. -*/ - -#if 0 -#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 -#ifdef YYPREFIX -#undef YYPREFIX -#endif -#define YYPREFIX "mime_" -#endif - - -#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 -#endif -#endif - -#include -#ifndef __MWERKS__ -#include -#endif -#include -#include -#include - -//#ifdef PALMTOPCENTER -//#include -//#else -#include "vobject_p.h" -//#endif - -/**** Types, Constants ****/ - -#define YYDEBUG 0 /* 1 to compile in some debugging code */ -#define MAXTOKEN 256 /* maximum token (line) length */ -#define YYSTACKSIZE 100 // ~unref ? -#define MAXLEVEL 10 /* max # of nested objects parseable */ - /* (includes outermost) */ - - -/**** Global Variables ****/ -int q_DontDecodeBase64Photo = 0; -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 yyerror(char *s); - -#if __CPLUSPLUS__ - }; -#endif - -int yyparse(); - -enum LexMode { - L_NORMAL, - L_PARAMWORD, - L_VCARD, - L_VCAL, - L_VEVENT, - L_VTODO, - L_VALUES, - L_BASE64, - L_QUOTED_PRINTABLE - }; - -/**** Private Forward Declarations ****/ -static int pushVObject(const char *prop); -static VObject* popVObject(); -static void lexPopMode(int top); -static int lexWithinMode(enum LexMode mode); -static void lexPushMode(enum LexMode mode); -static void enterProps(const char *s); -static void enterAttr(const char *s1, const char *s2); -static void enterValues(const char *value); -#define mime_error yyerror -void mime_error(char *s); -void mime_error_(char *s); - -%} - -/***************************************************************************/ -/*** The grammar ****/ -/***************************************************************************/ - -%union { - char *str; - VObject *vobj; - } - -%token - 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 - -/* - * NEWLINE is the token that would occur outside a vCard, - * while LINESEP is the token that would occur inside a vCard. - */ - -%token - STRING ID - -%type name value - -%type vcard vcal vobject - -%start mime - -%% - - -mime: vobjects - ; - -vobjects: vobjects vobject - { addList(&vObjList, $2); curObj = 0; } - | vobject - { addList(&vObjList, $1); curObj = 0; } - ; - -vobject: vcard - | vcal - ; - -vcard: - BEGIN_VCARD - { - lexPushMode(L_VCARD); - if (!pushVObject(VCCardProp)) YYERROR; - } - items END_VCARD - { - lexPopMode(0); - $$ = popVObject(); - } - | BEGIN_VCARD - { - lexPushMode(L_VCARD); - if (!pushVObject(VCCardProp)) YYERROR; - } - END_VCARD - { - lexPopMode(0); - $$ = popVObject(); - } - ; - -items: items item - | item - ; - -item: prop COLON - { - lexPushMode(L_VALUES); - } - values LINESEP - { - if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) - lexPopMode(0); - lexPopMode(0); - } - | error - ; - -prop: name - { - enterProps($1); - } - attr_params - | name - { - enterProps($1); - } - ; - -attr_params: attr_params attr_param - | attr_param - ; - -attr_param: SEMICOLON attr - ; - -attr: name - { - enterAttr($1,0); - } - | name EQ - { - lexPushMode(L_PARAMWORD); - } - name - { - lexPopMode(0); - enterAttr($1,$4); - } - ; - -name: ID - ; - -values: value SEMICOLON { enterValues($1); } values - | value - { enterValues($1); } - ; - -value: STRING - | - { $$ = 0; } - ; - -vcal: - BEGIN_VCAL - { if (!pushVObject(VCCalProp)) YYERROR; } - calitems - END_VCAL - { $$ = popVObject(); } - | BEGIN_VCAL - { if (!pushVObject(VCCalProp)) YYERROR; } - END_VCAL - { $$ = popVObject(); } - ; - -calitems: calitems calitem - | calitem - ; - -calitem: - eventitem - | todoitem - | items - ; - -eventitem: - BEGIN_VEVENT - { - lexPushMode(L_VEVENT); - if (!pushVObject(VCEventProp)) YYERROR; - } - items - END_VEVENT - { - lexPopMode(0); - popVObject(); - } - | BEGIN_VEVENT - { - lexPushMode(L_VEVENT); - if (!pushVObject(VCEventProp)) YYERROR; - } - END_VEVENT - { - lexPopMode(0); - popVObject(); - } - ; - -todoitem: - BEGIN_VTODO - { - lexPushMode(L_VTODO); - if (!pushVObject(VCTodoProp)) YYERROR; - } - items - END_VTODO - { - lexPopMode(0); - popVObject(); - } - | BEGIN_VTODO - { - lexPushMode(L_VTODO); - if (!pushVObject(VCTodoProp)) YYERROR; - } - END_VTODO - { - lexPopMode(0); - popVObject(); - } - ; - -%% -/*------------------------------------*/ -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) { - setVObjectStringZValue_(curProp,strdup( value )); - } - } - 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=0; - p1 = lookupProp_(s1); - if (s2) { - VObject *a; - p2 = lookupProp_(s2); - a = addProp(curProp,p1); - setVObjectStringZValue(a,p2); - } - else - addProp(curProp,p1); - /* Lookup strings so we can quickly use pointer comparison */ - static const char* base64 = lookupProp_(VCBase64Prop); - static const char* qp = lookupProp_(VCQuotedPrintableProp); - static const char* photo = lookupProp_(VCPhotoProp); - static const char* encoding = lookupProp_(VCEncodingProp); - if ((!q_DontDecodeBase64Photo || vObjectName(curProp) != photo) - && (p1 == base64 || p1 == encoding && p2 == base64)) - lexPushMode(L_BASE64); - else if (p1 == qp || p1 == encoding && p2 == qp) - 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;iRead(&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 char* lexGetParamWord() -{ - int c; - lexClearToken(); - c = lexLookahead(); - while (c >= ' ' && c < 127 && !strchr("[]:=,.;",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 != ';' || !fieldedProp)) { - if (c == '\\' ) { - int a; - lexSkipLookahead(); - a = lexLookahead(); - if ( a == ';' ) { - lexAppendc( ';' ); - lexSkipLookahead(); - } else if ( a == '\n' ) { - lexAppendc( '\n' ); - lexSkipLookahead(); - } else if ( a == '\\' ) { - lexAppendc( '\\' ); - lexSkipLookahead(); - } else { - lexAppendc('\\'); - } - } else 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 (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; - else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; - else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; - else if (!qstricmp(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 int 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(); - lexSkipWhite(); - 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 { /* 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') { - lexSkipWhite(); - if(lexLookahead() == '\n') { - ++mime_lineNum; - break; - } - } - c = lexGetc(); - } - } - return c != EOF; - } - 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 bytesLen; - } - -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() -{ - int c; - lexSkipWhite(); - c = lexLookahead(); - lexClearToken(); - - while (c != EOF && (c != ';' || !fieldedProp)) { - if (c == '\n') { - // break, leave '\n' on remaining chars. - break; - } else if (c == '=') { - int cur = 0; - int next; - - lexSkipLookahead(); // skip '=' - next = lexLookahead(); - - if (next == '\n') { - // skip and only skip the \n - lexSkipLookahead(); - c = lexLookahead(); - ++mime_lineNum; // aid in error reporting - continue; - } else if (next >= '0' && next <= '9') { - cur = next - '0'; - } else if (next >= 'A' && next <= 'F') { - cur = next - 'A' + 10; - } else { - // we have been sent buggy stuff. doesn't matter - // what we do so long as we keep going. - // should probably spit an error here - lexSkipLookahead(); - c = lexLookahead(); - continue; - } - - lexSkipLookahead(); // skip A-Z0-9 - next = lexLookahead(); - - cur = cur * 16; - // this time really just expecting 0-9A-F - if (next >= '0' && next <= '9') { - cur += next - '0'; - } else if (next >= 'A' && next <= 'F') { - cur += next - 'A' + 10; - } else { - // we have been sent buggy stuff. doesn't matter - // what we do so long as we keep going. - // should probably spit an error here - lexSkipLookahead(); - c = lexLookahead(); - continue; - } - - // got a valid escaped =. append it. - lexSkipLookahead(); // skip second 0-9A-F - lexAppendc(cur); - } else { - lexSkipLookahead(); // skip whatever we just read. - lexAppendc(c); // and append it. - } - c = lexLookahead(); - } - lexAppendc(0); - return c==EOF?0:lexStr(); -} - -static int yylex() { - - int lexmode = LEXMODE(); - if (lexmode == L_VALUES) { - int c = lexGetc(); - int c2; - if (c == ';' && fieldedProp) { - DBG_(("db: SEMICOLON\n")); - lexPushLookaheadc(c); - handleMoreRFC822LineBreak(c); - lexSkipLookahead(); - return SEMICOLON; - } - else if (strchr("\n",c) && (c2 = lexLookahead()) != ' ' && c2 != '\t') { - ++mime_lineNum; - /* consume all line separator(s) adjacent to each other */ - while (strchr("\n",c2)) { - lexSkipLookahead(); - c2 = 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... */ - yylval.str = NULL; - return lexGetDataFromBase64() ? STRING : 0; - } - 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 if (lexmode == L_PARAMWORD) { - yylval.str = lexGetParamWord(); - return ID; - } 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. */ - /* I don't see this in the spec, and it breaks null values -- WA - 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 (isalnum(c)) { - char *t = lexGetWord(); - yylval.str = t; - if (!qstricmp(t, "begin")) { - return match_begin_end_name(0); - } - else if (!qstricmp(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())) { - 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[80]; - sprintf(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; - } - -void mime_error(char *s) - { - char msg[256]; - if (mimeErrorHandler) { - sprintf(msg,"%s at line %d", s, mime_lineNum); - mimeErrorHandler(msg); - } - } - -void mime_error_(char *s) - { - if (mimeErrorHandler) { - mimeErrorHandler(s); - } - } - +%{ + +/*************************************************************************** +(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 */ +#define __DEBUG 1 + +#if __DEBUG +#define DBG_(x) printf x +#else +#define DBG_(x) +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#if 0 +#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 +#ifdef YYPREFIX +#undef YYPREFIX +#endif +#define YYPREFIX "mime_" +#endif + + +#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 +#endif +#endif + +#include +#ifndef __MWERKS__ +#include +#endif +#include +#include +#include + +//#ifdef PALMTOPCENTER +//#include +//#else +#include "vobject_p.h" +//#endif + +/**** Types, Constants ****/ + +#define YYDEBUG 0 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 100 // ~unref ? +#define MAXLEVEL 10 /* max # of nested objects parseable */ + /* (includes outermost) */ + + +/**** Global Variables ****/ +int q_DontDecodeBase64Photo = 0; +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 yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yyparse(); + +enum LexMode { + L_NORMAL, + L_PARAMWORD, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static int pushVObject(const char *prop); +static VObject* popVObject(); +static void lexPopMode(int top); +static int lexWithinMode(enum LexMode mode); +static void lexPushMode(enum LexMode mode); +static void enterProps(const char *s); +static void enterAttr(const char *s1, const char *s2); +static void enterValues(const char *value); +#define mime_error yyerror +void mime_error(char *s); +void mime_error_(char *s); + +%} + +/***************************************************************************/ +/*** The grammar ****/ +/***************************************************************************/ + +%union { + char *str; + VObject *vobj; + } + +%token + 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 + +/* + * NEWLINE is the token that would occur outside a vCard, + * while LINESEP is the token that would occur inside a vCard. + */ + +%token + STRING ID + +%type name value + +%type vcard vcal vobject + +%start mime + +%% + + +mime: vobjects + ; + +vobjects: vobjects vobject + { addList(&vObjList, $2); curObj = 0; } + | vobject + { addList(&vObjList, $1); curObj = 0; } + ; + +vobject: vcard + | vcal + ; + +vcard: + BEGIN_VCARD + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } + items END_VCARD + { + lexPopMode(0); + $$ = popVObject(); + } + | BEGIN_VCARD + { + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; + } + END_VCARD + { + lexPopMode(0); + $$ = popVObject(); + } + ; + +items: items item + | item + ; + +item: prop COLON + { + lexPushMode(L_VALUES); + } + values LINESEP + { + if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) + lexPopMode(0); + lexPopMode(0); + } + | error + ; + +prop: name + { + enterProps($1); + } + attr_params + | name + { + enterProps($1); + } + ; + +attr_params: attr_params attr_param + | attr_param + ; + +attr_param: SEMICOLON attr + ; + +attr: name + { + enterAttr($1,0); + } + | name EQ + { + lexPushMode(L_PARAMWORD); + } + name + { + lexPopMode(0); + enterAttr($1,$4); + } + ; + +name: ID + ; + +values: value SEMICOLON { enterValues($1); } values + | value + { enterValues($1); } + ; + +value: STRING + | + { $$ = 0; } + ; + +vcal: + BEGIN_VCAL + { if (!pushVObject(VCCalProp)) YYERROR; } + calitems + END_VCAL + { $$ = popVObject(); } + | BEGIN_VCAL + { if (!pushVObject(VCCalProp)) YYERROR; } + END_VCAL + { $$ = popVObject(); } + ; + +calitems: calitems calitem + | calitem + ; + +calitem: + eventitem + | todoitem + | items + ; + +eventitem: + BEGIN_VEVENT + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } + items + END_VEVENT + { + lexPopMode(0); + popVObject(); + } + | BEGIN_VEVENT + { + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; + } + END_VEVENT + { + lexPopMode(0); + popVObject(); + } + ; + +todoitem: + BEGIN_VTODO + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } + items + END_VTODO + { + lexPopMode(0); + popVObject(); + } + | BEGIN_VTODO + { + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; + } + END_VTODO + { + lexPopMode(0); + popVObject(); + } + ; + +%% +/*------------------------------------*/ +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) { + setVObjectStringZValue_(curProp,strdup( value )); + } + } + 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=0; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + /* Lookup strings so we can quickly use pointer comparison */ + static const char* base64 = lookupProp_(VCBase64Prop); + static const char* qp = lookupProp_(VCQuotedPrintableProp); + static const char* photo = lookupProp_(VCPhotoProp); + static const char* encoding = lookupProp_(VCEncodingProp); + if ((!q_DontDecodeBase64Photo || vObjectName(curProp) != photo) + && (p1 == base64 || p1 == encoding && p2 == base64)) + lexPushMode(L_BASE64); + else if (p1 == qp || p1 == encoding && p2 == qp) + 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;iRead(&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 char* lexGetParamWord() +{ + int c; + lexClearToken(); + c = lexLookahead(); + while (c >= ' ' && c < 127 && !strchr("[]:=,.;",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 != ';' || !fieldedProp)) { + if (c == '\\' ) { + int a; + lexSkipLookahead(); + a = lexLookahead(); + if ( a == ';' ) { + lexAppendc( ';' ); + lexSkipLookahead(); + } else if ( a == '\n' ) { + lexAppendc( '\n' ); + lexSkipLookahead(); + } else if ( a == '\\' ) { + lexAppendc( '\\' ); + lexSkipLookahead(); + } else { + lexAppendc('\\'); + } + } else 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 (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!qstricmp(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 int 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(); + lexSkipWhite(); + 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 { /* 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') { + lexSkipWhite(); + if(lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + } + c = lexGetc(); + } + } + return c != EOF; + } + 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 bytesLen; + } + +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() +{ + int c; + lexSkipWhite(); + c = lexLookahead(); + lexClearToken(); + + while (c != EOF && (c != ';' || !fieldedProp)) { + if (c == '\n') { + // break, leave '\n' on remaining chars. + break; + } else if (c == '=') { + int cur = 0; + int next; + + lexSkipLookahead(); // skip '=' + next = lexLookahead(); + + if (next == '\n') { + // skip and only skip the \n + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; // aid in error reporting + continue; + } else if (next >= '0' && next <= '9') { + cur = next - '0'; + } else if (next >= 'A' && next <= 'F') { + cur = next - 'A' + 10; + } else { + // we have been sent buggy stuff. doesn't matter + // what we do so long as we keep going. + // should probably spit an error here + lexSkipLookahead(); + c = lexLookahead(); + continue; + } + + lexSkipLookahead(); // skip A-Z0-9 + next = lexLookahead(); + + cur = cur * 16; + // this time really just expecting 0-9A-F + if (next >= '0' && next <= '9') { + cur += next - '0'; + } else if (next >= 'A' && next <= 'F') { + cur += next - 'A' + 10; + } else { + // we have been sent buggy stuff. doesn't matter + // what we do so long as we keep going. + // should probably spit an error here + lexSkipLookahead(); + c = lexLookahead(); + continue; + } + + // got a valid escaped =. append it. + lexSkipLookahead(); // skip second 0-9A-F + lexAppendc(cur); + } else { + lexSkipLookahead(); // skip whatever we just read. + lexAppendc(c); // and append it. + } + c = lexLookahead(); + } + lexAppendc(0); + return c==EOF?0:lexStr(); +} + +static int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + int c2; + if (c == ';' && fieldedProp) { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); + handleMoreRFC822LineBreak(c); + lexSkipLookahead(); + return SEMICOLON; + } + else if (strchr("\n",c) && (c2 = lexLookahead()) != ' ' && c2 != '\t') { + ++mime_lineNum; + /* consume all line separator(s) adjacent to each other */ + while (strchr("\n",c2)) { + lexSkipLookahead(); + c2 = 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... */ + yylval.str = NULL; + return lexGetDataFromBase64() ? STRING : 0; + } + 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 if (lexmode == L_PARAMWORD) { + yylval.str = lexGetParamWord(); + return ID; + } 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. */ + /* I don't see this in the spec, and it breaks null values -- WA + 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 (isalnum(c)) { + char *t = lexGetWord(); + yylval.str = t; + if (!qstricmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!qstricmp(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())) { + 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[80]; + sprintf(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; + } + +void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + sprintf(msg,"%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + diff --git a/library/backend/vcc_yacc.cpp b/library/backend/vcc_yacc.cpp index 68f11b5..cb8f8c4 100644 --- a/library/backend/vcc_yacc.cpp +++ b/library/backend/vcc_yacc.cpp @@ -9,196 +9,196 @@ static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #define YYRECOVERING (yyerrflag!=0) #define YYPREFIX "yy" #line 1 "vcc.y" - - -/*************************************************************************** -(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 */ -#define __DEBUG 1 - -#if __DEBUG -#define DBG_(x) printf x -#else -#define DBG_(x) -#endif - -/**** External Functions ****/ - -/* assign local name to parser variables and functions so that - we can use more than one yacc based parser. -*/ - -#if 0 -#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 -#ifdef YYPREFIX -#undef YYPREFIX -#endif -#define YYPREFIX "mime_" -#endif - - -#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 -#endif -#endif - -#include -#ifndef __MWERKS__ -#include -#endif -#include -#include -#include - -/*#ifdef PALMTOPCENTER */ -/*#include */ -/*#else */ -#include "vobject_p.h" -/*#endif */ - -/**** Types, Constants ****/ - -#define YYDEBUG 0 /* 1 to compile in some debugging code */ -#define MAXTOKEN 256 /* maximum token (line) length */ -#define YYSTACKSIZE 100 /* ~unref ? */ -#define MAXLEVEL 10 /* max # of nested objects parseable */ - /* (includes outermost) */ - - -/**** Global Variables ****/ -int q_DontDecodeBase64Photo = 0; -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 yyerror(char *s); - -#if __CPLUSPLUS__ - }; -#endif - -int yyparse(); - -enum LexMode { - L_NORMAL, - L_PARAMWORD, - L_VCARD, - L_VCAL, - L_VEVENT, - L_VTODO, - L_VALUES, - L_BASE64, - L_QUOTED_PRINTABLE - }; - -/**** Private Forward Declarations ****/ -static int pushVObject(const char *prop); -static VObject* popVObject(); -static void lexPopMode(int top); -static int lexWithinMode(enum LexMode mode); -static void lexPushMode(enum LexMode mode); -static void enterProps(const char *s); -static void enterAttr(const char *s1, const char *s2); -static void enterValues(const char *value); -#define mime_error yyerror -void mime_error(char *s); -void mime_error_(char *s); - + + +/*************************************************************************** +(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 */ +#define __DEBUG 1 + +#if __DEBUG +#define DBG_(x) printf x +#else +#define DBG_(x) +#endif + +/**** External Functions ****/ + +/* assign local name to parser variables and functions so that + we can use more than one yacc based parser. +*/ + +#if 0 +#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 +#ifdef YYPREFIX +#undef YYPREFIX +#endif +#define YYPREFIX "mime_" +#endif + + +#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 +#endif +#endif + +#include +#ifndef __MWERKS__ +#include +#endif +#include +#include +#include + +/*#ifdef PALMTOPCENTER*/ +/*#include */ +/*#else*/ +#include "vobject_p.h" +/*#endif*/ + +/**** Types, Constants ****/ + +#define YYDEBUG 0 /* 1 to compile in some debugging code */ +#define MAXTOKEN 256 /* maximum token (line) length */ +#define YYSTACKSIZE 100 /* ~unref ?*/ +#define MAXLEVEL 10 /* max # of nested objects parseable */ + /* (includes outermost) */ + + +/**** Global Variables ****/ +int q_DontDecodeBase64Photo = 0; +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 yyerror(char *s); + +#if __CPLUSPLUS__ + }; +#endif + +int yyparse(); + +enum LexMode { + L_NORMAL, + L_PARAMWORD, + L_VCARD, + L_VCAL, + L_VEVENT, + L_VTODO, + L_VALUES, + L_BASE64, + L_QUOTED_PRINTABLE + }; + +/**** Private Forward Declarations ****/ +static int pushVObject(const char *prop); +static VObject* popVObject(); +static void lexPopMode(int top); +static int lexWithinMode(enum LexMode mode); +static void lexPushMode(enum LexMode mode); +static void enterProps(const char *s); +static void enterAttr(const char *s1, const char *s2); +static void enterValues(const char *value); +#define mime_error yyerror +void mime_error(char *s); +void mime_error_(char *s); + #line 193 "vcc.y" -typedef union { - char *str; - VObject *vobj; +typedef union { + char *str; + VObject *vobj; } YYSTYPE; #line 204 "y.tab.c" #define EQ 257 @@ -379,865 +379,865 @@ short yyss[YYSTACKSIZE]; YYSTYPE yyvs[YYSTACKSIZE]; #define yystacksize YYSTACKSIZE #line 390 "vcc.y" - -/*------------------------------------*/ -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) { - setVObjectStringZValue_(curProp,strdup( value )); - } - } - 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=0; - p1 = lookupProp_(s1); - if (s2) { - VObject *a; - p2 = lookupProp_(s2); - a = addProp(curProp,p1); - setVObjectStringZValue(a,p2); - } - else - addProp(curProp,p1); - /* Lookup strings so we can quickly use pointer comparison */ - static const char* base64 = lookupProp_(VCBase64Prop); - static const char* qp = lookupProp_(VCQuotedPrintableProp); - static const char* photo = lookupProp_(VCPhotoProp); - static const char* encoding = lookupProp_(VCEncodingProp); - if ((!q_DontDecodeBase64Photo || vObjectName(curProp) != photo) - && (p1 == base64 || p1 == encoding && p2 == base64)) - lexPushMode(L_BASE64); - else if (p1 == qp || p1 == encoding && p2 == qp) - 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;iRead(&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 char* lexGetParamWord() -{ - int c; - lexClearToken(); - c = lexLookahead(); - while (c >= ' ' && c < 127 && !strchr("[]:=,.;",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 != ';' || !fieldedProp)) { - if (c == '\\' ) { - int a; - lexSkipLookahead(); - a = lexLookahead(); - if ( a == ';' ) { - lexAppendc( ';' ); - lexSkipLookahead(); - } else if ( a == '\n' ) { - lexAppendc( '\n' ); - lexSkipLookahead(); - } else if ( a == '\\' ) { - lexAppendc( '\\' ); - lexSkipLookahead(); - } else { - lexAppendc('\\'); - } - } else 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 (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; - else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; - else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; - else if (!qstricmp(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 int 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(); - lexSkipWhite(); - 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 { /* 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') { - lexSkipWhite(); - if(lexLookahead() == '\n') { - ++mime_lineNum; - break; - } - } - c = lexGetc(); - } - } - return c != EOF; - } - 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 bytesLen; - } - -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() -{ - int c; - lexSkipWhite(); - c = lexLookahead(); - lexClearToken(); - - while (c != EOF && (c != ';' || !fieldedProp)) { - if (c == '\n') { - // break, leave '\n' on remaining chars. - break; - } else if (c == '=') { - int cur = 0; - int next; - - lexSkipLookahead(); // skip '=' - next = lexLookahead(); - - if (next == '\n') { - // skip and only skip the \n - lexSkipLookahead(); - c = lexLookahead(); - ++mime_lineNum; // aid in error reporting - continue; - } else if (next >= '0' && next <= '9') { - cur = next - '0'; - } else if (next >= 'A' && next <= 'F') { - cur = next - 'A' + 10; - } else { - // we have been sent buggy stuff. doesn't matter - // what we do so long as we keep going. - // should probably spit an error here - lexSkipLookahead(); - c = lexLookahead(); - continue; - } - - lexSkipLookahead(); // skip A-Z0-9 - next = lexLookahead(); - - cur = cur * 16; - // this time really just expecting 0-9A-F - if (next >= '0' && next <= '9') { - cur += next - '0'; - } else if (next >= 'A' && next <= 'F') { - cur += next - 'A' + 10; - } else { - // we have been sent buggy stuff. doesn't matter - // what we do so long as we keep going. - // should probably spit an error here - lexSkipLookahead(); - c = lexLookahead(); - continue; - } - - // got a valid escaped =. append it. - lexSkipLookahead(); // skip second 0-9A-F - lexAppendc(cur); - } else { - lexSkipLookahead(); // skip whatever we just read. - lexAppendc(c); // and append it. - } - c = lexLookahead(); - } - lexAppendc(0); - return c==EOF?0:lexStr(); -} - -static int yylex() { - - int lexmode = LEXMODE(); - if (lexmode == L_VALUES) { - int c = lexGetc(); - int c2; - if (c == ';' && fieldedProp) { - DBG_(("db: SEMICOLON\n")); - lexPushLookaheadc(c); - handleMoreRFC822LineBreak(c); - lexSkipLookahead(); - return SEMICOLON; - } - else if (strchr("\n",c) && (c2 = lexLookahead()) != ' ' && c2 != '\t') { - ++mime_lineNum; - /* consume all line separator(s) adjacent to each other */ - while (strchr("\n",c2)) { - lexSkipLookahead(); - c2 = 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... */ - yylval.str = NULL; - return lexGetDataFromBase64() ? STRING : 0; - } - 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 if (lexmode == L_PARAMWORD) { - yylval.str = lexGetParamWord(); - return ID; - } 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. */ - /* I don't see this in the spec, and it breaks null values -- WA - 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 (isalnum(c)) { - char *t = lexGetWord(); - yylval.str = t; - if (!qstricmp(t, "begin")) { - return match_begin_end_name(0); - } - else if (!qstricmp(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())) { - 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[80]; - sprintf(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; - } - -void mime_error(char *s) - { - char msg[256]; - if (mimeErrorHandler) { - sprintf(msg,"%s at line %d", s, mime_lineNum); - mimeErrorHandler(msg); - } - } - -void mime_error_(char *s) - { - if (mimeErrorHandler) { - mimeErrorHandler(s); - } - } - + +/*------------------------------------*/ +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) { + setVObjectStringZValue_(curProp,strdup( value )); + } + } + 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=0; + p1 = lookupProp_(s1); + if (s2) { + VObject *a; + p2 = lookupProp_(s2); + a = addProp(curProp,p1); + setVObjectStringZValue(a,p2); + } + else + addProp(curProp,p1); + /* Lookup strings so we can quickly use pointer comparison */ + static const char* base64 = lookupProp_(VCBase64Prop); + static const char* qp = lookupProp_(VCQuotedPrintableProp); + static const char* photo = lookupProp_(VCPhotoProp); + static const char* encoding = lookupProp_(VCEncodingProp); + if ((!q_DontDecodeBase64Photo || vObjectName(curProp) != photo) + && (p1 == base64 || p1 == encoding && p2 == base64)) + lexPushMode(L_BASE64); + else if (p1 == qp || p1 == encoding && p2 == qp) + 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;iRead(&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 char* lexGetParamWord() +{ + int c; + lexClearToken(); + c = lexLookahead(); + while (c >= ' ' && c < 127 && !strchr("[]:=,.;",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 != ';' || !fieldedProp)) { + if (c == '\\' ) { + int a; + lexSkipLookahead(); + a = lexLookahead(); + if ( a == ';' ) { + lexAppendc( ';' ); + lexSkipLookahead(); + } else if ( a == '\n' ) { + lexAppendc( '\n' ); + lexSkipLookahead(); + } else if ( a == '\\' ) { + lexAppendc( '\\' ); + lexSkipLookahead(); + } else { + lexAppendc('\\'); + } + } else 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 (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD; + else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL; + else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT; + else if (!qstricmp(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 int 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(); + lexSkipWhite(); + 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 { /* 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') { + lexSkipWhite(); + if(lexLookahead() == '\n') { + ++mime_lineNum; + break; + } + } + c = lexGetc(); + } + } + return c != EOF; + } + 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 bytesLen; + } + +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() +{ + int c; + lexSkipWhite(); + c = lexLookahead(); + lexClearToken(); + + while (c != EOF && (c != ';' || !fieldedProp)) { + if (c == '\n') { + // break, leave '\n' on remaining chars. + break; + } else if (c == '=') { + int cur = 0; + int next; + + lexSkipLookahead(); // skip '=' + next = lexLookahead(); + + if (next == '\n') { + // skip and only skip the \n + lexSkipLookahead(); + c = lexLookahead(); + ++mime_lineNum; // aid in error reporting + continue; + } else if (next >= '0' && next <= '9') { + cur = next - '0'; + } else if (next >= 'A' && next <= 'F') { + cur = next - 'A' + 10; + } else { + // we have been sent buggy stuff. doesn't matter + // what we do so long as we keep going. + // should probably spit an error here + lexSkipLookahead(); + c = lexLookahead(); + continue; + } + + lexSkipLookahead(); // skip A-Z0-9 + next = lexLookahead(); + + cur = cur * 16; + // this time really just expecting 0-9A-F + if (next >= '0' && next <= '9') { + cur += next - '0'; + } else if (next >= 'A' && next <= 'F') { + cur += next - 'A' + 10; + } else { + // we have been sent buggy stuff. doesn't matter + // what we do so long as we keep going. + // should probably spit an error here + lexSkipLookahead(); + c = lexLookahead(); + continue; + } + + // got a valid escaped =. append it. + lexSkipLookahead(); // skip second 0-9A-F + lexAppendc(cur); + } else { + lexSkipLookahead(); // skip whatever we just read. + lexAppendc(c); // and append it. + } + c = lexLookahead(); + } + lexAppendc(0); + return c==EOF?0:lexStr(); +} + +static int yylex() { + + int lexmode = LEXMODE(); + if (lexmode == L_VALUES) { + int c = lexGetc(); + int c2; + if (c == ';' && fieldedProp) { + DBG_(("db: SEMICOLON\n")); + lexPushLookaheadc(c); + handleMoreRFC822LineBreak(c); + lexSkipLookahead(); + return SEMICOLON; + } + else if (strchr("\n",c) && (c2 = lexLookahead()) != ' ' && c2 != '\t') { + ++mime_lineNum; + /* consume all line separator(s) adjacent to each other */ + while (strchr("\n",c2)) { + lexSkipLookahead(); + c2 = 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... */ + yylval.str = NULL; + return lexGetDataFromBase64() ? STRING : 0; + } + 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 if (lexmode == L_PARAMWORD) { + yylval.str = lexGetParamWord(); + return ID; + } 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. */ + /* I don't see this in the spec, and it breaks null values -- WA + 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 (isalnum(c)) { + char *t = lexGetWord(); + yylval.str = t; + if (!qstricmp(t, "begin")) { + return match_begin_end_name(0); + } + else if (!qstricmp(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())) { + 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[80]; + sprintf(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; + } + +void mime_error(char *s) + { + char msg[256]; + if (mimeErrorHandler) { + sprintf(msg,"%s at line %d", s, mime_lineNum); + mimeErrorHandler(msg); + } + } + +void mime_error_(char *s) + { + if (mimeErrorHandler) { + mimeErrorHandler(s); + } + } + #line 1242 "y.tab.c" #define YYABORT goto yyabort #define YYREJECT goto yyabort @@ -1389,75 +1389,75 @@ case 3: break; case 6: #line 236 "vcc.y" -{ - lexPushMode(L_VCARD); - if (!pushVObject(VCCardProp)) YYERROR; +{ + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; } break; case 7: #line 241 "vcc.y" -{ - lexPopMode(0); - yyval.vobj = popVObject(); +{ + lexPopMode(0); + yyval.vobj = popVObject(); } break; case 8: #line 246 "vcc.y" -{ - lexPushMode(L_VCARD); - if (!pushVObject(VCCardProp)) YYERROR; +{ + lexPushMode(L_VCARD); + if (!pushVObject(VCCardProp)) YYERROR; } break; case 9: #line 251 "vcc.y" -{ - lexPopMode(0); - yyval.vobj = popVObject(); +{ + lexPopMode(0); + yyval.vobj = popVObject(); } break; case 12: #line 262 "vcc.y" -{ - lexPushMode(L_VALUES); +{ + lexPushMode(L_VALUES); } break; case 13: #line 266 "vcc.y" -{ - if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) - lexPopMode(0); - lexPopMode(0); +{ + if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE)) + lexPopMode(0); + lexPopMode(0); } break; case 15: #line 275 "vcc.y" -{ - enterProps(yyvsp[0].str); +{ + enterProps(yyvsp[0].str); } break; case 17: #line 280 "vcc.y" -{ - enterProps(yyvsp[0].str); +{ + enterProps(yyvsp[0].str); } break; case 21: #line 293 "vcc.y" -{ - enterAttr(yyvsp[0].str,0); +{ + enterAttr(yyvsp[0].str,0); } break; case 22: #line 297 "vcc.y" -{ - lexPushMode(L_PARAMWORD); +{ + lexPushMode(L_PARAMWORD); } break; case 23: #line 301 "vcc.y" -{ - lexPopMode(0); - enterAttr(yyvsp[-3].str,yyvsp[0].str); +{ + lexPopMode(0); + enterAttr(yyvsp[-3].str,yyvsp[0].str); } break; case 25: @@ -1490,58 +1490,58 @@ case 33: break; case 39: #line 344 "vcc.y" -{ - lexPushMode(L_VEVENT); - if (!pushVObject(VCEventProp)) YYERROR; +{ + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; } break; case 40: #line 350 "vcc.y" -{ - lexPopMode(0); - popVObject(); +{ + lexPopMode(0); + popVObject(); } break; case 41: #line 355 "vcc.y" -{ - lexPushMode(L_VEVENT); - if (!pushVObject(VCEventProp)) YYERROR; +{ + lexPushMode(L_VEVENT); + if (!pushVObject(VCEventProp)) YYERROR; } break; case 42: #line 360 "vcc.y" -{ - lexPopMode(0); - popVObject(); +{ + lexPopMode(0); + popVObject(); } break; case 43: #line 368 "vcc.y" -{ - lexPushMode(L_VTODO); - if (!pushVObject(VCTodoProp)) YYERROR; +{ + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; } break; case 44: #line 374 "vcc.y" -{ - lexPopMode(0); - popVObject(); +{ + lexPopMode(0); + popVObject(); } break; case 45: #line 379 "vcc.y" -{ - lexPushMode(L_VTODO); - if (!pushVObject(VCTodoProp)) YYERROR; +{ + lexPushMode(L_VTODO); + if (!pushVObject(VCTodoProp)) YYERROR; } break; case 46: #line 384 "vcc.y" -{ - lexPopMode(0); - popVObject(); +{ + lexPopMode(0); + popVObject(); } break; #line 1548 "y.tab.c" -- cgit v0.9.0.2