summaryrefslogtreecommitdiff
path: root/library/backend/vcc.y
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (unidiff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /library/backend/vcc.y
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'library/backend/vcc.y') (more/less context) (ignore whitespace changes)
-rw-r--r--library/backend/vcc.y1199
1 files changed, 1199 insertions, 0 deletions
diff --git a/library/backend/vcc.y b/library/backend/vcc.y
new file mode 100644
index 0000000..0225982
--- a/dev/null
+++ b/library/backend/vcc.y
@@ -0,0 +1,1199 @@
1%{
2
3/***************************************************************************
4(C) Copyright 1996 Apple Computer, Inc., AT&T Corp., International
5Business Machines Corporation and Siemens Rolm Communications Inc.
6
7For purposes of this license notice, the term Licensors shall mean,
8collectively, Apple Computer, Inc., AT&T Corp., International
9Business Machines Corporation and Siemens Rolm Communications Inc.
10The term Licensor shall mean any of the Licensors.
11
12Subject to acceptance of the following conditions, permission is hereby
13granted by Licensors without the need for written agreement and without
14license or royalty fees, to use, copy, modify and distribute this
15software for any purpose.
16
17The above copyright notice and the following four paragraphs must be
18reproduced in all copies of this software and any software including
19this software.
20
21THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE
22ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR
23MODIFICATIONS.
24
25IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT,
26INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
27OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28DAMAGE.
29
30EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED,
31INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE
32IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33PURPOSE.
34
35The software is provided with RESTRICTED RIGHTS. Use, duplication, or
36disclosure by the government are subject to restrictions set forth in
37DFARS 252.227-7013 or 48 CFR 52.227-19, as applicable.
38
39***************************************************************************/
40
41/*
42 * src: vcc.c
43 * doc: Parser for vCard and vCalendar. Note that this code is
44 * generated by a yacc parser generator. Generally it should not
45 * be edited by hand. The real source is vcc.y. The #line directives
46 * can be commented out here to make it easier to trace through
47 * in a debugger. However, if a bug is found it should
48 * be fixed in vcc.y and this file regenerated.
49 */
50
51
52/* debugging utilities */
53#if __DEBUG
54#define DBG_(x) printf x
55#else
56#define DBG_(x)
57#endif
58
59/**** External Functions ****/
60
61/* assign local name to parser variables and functions so that
62 we can use more than one yacc based parser.
63*/
64
65#if 0
66#define yyparse mime_parse
67#define yylex mime_lex
68#define yyerror mime_error
69#define yychar mime_char
70/* #define p_yyval p_mime_val */
71#undef yyval
72#define yyval mime_yyval
73/* #define p_yylval p_mime_lval */
74#undef yylval
75#define yylval mime_yylval
76#define yydebug mime_debug
77#define yynerrs mime_nerrs
78#define yyerrflag mime_errflag
79#define yyss mime_ss
80#define yyssp mime_ssp
81#define yyvs mime_vs
82#define yyvsp mime_vsp
83#define yylhs mime_lhs
84#define yylen mime_len
85#define yydefred mime_defred
86#define yydgoto mime_dgoto
87#define yysindex mime_sindex
88#define yyrindex mime_rindex
89#define yygindex mime_gindex
90#define yytable mime_table
91#define yycheck mime_check
92#define yyname mime_name
93#define yyrule mime_rule
94#ifdef YYPREFIX
95#undef YYPREFIX
96#endif
97#define YYPREFIX "mime_"
98#endif
99
100
101#ifndef _NO_LINE_FOLDING
102#define _SUPPORT_LINE_FOLDING 1
103#endif
104
105/* undef below if compile with MFC */
106/* #define INCLUDEMFC 1 */
107
108#if defined(WIN32) || defined(_WIN32)
109#ifdef INCLUDEMFC
110#include <afx.h>
111#endif
112#endif
113
114#include <string.h>
115#ifndef __MWERKS__
116#include <stdlib.h>
117#endif
118#include <stdio.h>
119#include <stdlib.h>
120#include <ctype.h>
121
122//#ifdef PALMTOPCENTER
123//#include <qpe/vobject_p.h>
124//#else
125#include "vobject_p.h"
126//#endif
127
128/**** Types, Constants ****/
129
130 #define YYDEBUG 0/* 1 to compile in some debugging code */
131 #define MAXTOKEN 256/* maximum token (line) length */
132 #define YYSTACKSIZE 100// ~unref ?
133 #define MAXLEVEL 10/* max # of nested objects parseable */
134 /* (includes outermost) */
135
136
137/**** Global Variables ****/
138int mime_lineNum, mime_numErrors; /* yyerror() can use these */
139static VObject* vObjList;
140static VObject *curProp;
141static VObject *curObj;
142static VObject* ObjStack[MAXLEVEL];
143static int ObjStackTop;
144
145
146/* A helpful utility for the rest of the app. */
147#if __CPLUSPLUS__
148extern "C" {
149#endif
150
151 extern void yyerror(char *s);
152
153#if __CPLUSPLUS__
154 };
155#endif
156
157int yyparse();
158
159enum LexMode {
160 L_NORMAL,
161 L_VCARD,
162 L_VCAL,
163 L_VEVENT,
164 L_VTODO,
165 L_VALUES,
166 L_BASE64,
167 L_QUOTED_PRINTABLE
168 };
169
170/**** Private Forward Declarations ****/
171static int pushVObject(const char *prop);
172static VObject* popVObject();
173static void lexPopMode(int top);
174static int lexWithinMode(enum LexMode mode);
175static void lexPushMode(enum LexMode mode);
176static void enterProps(const char *s);
177static void enterAttr(const char *s1, const char *s2);
178static void enterValues(const char *value);
179#define mime_error yyerror
180void mime_error(char *s);
181void mime_error_(char *s);
182
183%}
184
185/***************************************************************************/
186/*** The grammar ****/
187/***************************************************************************/
188
189%union {
190 char *str;
191 VObject *vobj;
192 }
193
194%token
195 EQ COLON DOT SEMICOLON SPACE HTAB LINESEP NEWLINE
196 BEGIN_VCARD END_VCARD BEGIN_VCAL END_VCAL
197 BEGIN_VEVENT END_VEVENT BEGIN_VTODO END_VTODO
198 ID
199
200/*
201 * NEWLINE is the token that would occur outside a vCard,
202 * while LINESEP is the token that would occur inside a vCard.
203 */
204
205%token <str>
206 STRING ID
207
208%type <str> name value
209
210%type <vobj> vcard vcal vobject
211
212%start mime
213
214%%
215
216
217mime: vobjects
218 ;
219
220vobjects: vobjects vobject
221 { addList(&vObjList, $2); curObj = 0; }
222 | vobject
223 { addList(&vObjList, $1); curObj = 0; }
224 ;
225
226vobject: vcard
227 | vcal
228 ;
229
230vcard:
231 BEGIN_VCARD
232 {
233 lexPushMode(L_VCARD);
234 if (!pushVObject(VCCardProp)) YYERROR;
235 }
236 items END_VCARD
237 {
238 lexPopMode(0);
239 $$ = popVObject();
240 }
241 | BEGIN_VCARD
242 {
243 lexPushMode(L_VCARD);
244 if (!pushVObject(VCCardProp)) YYERROR;
245 }
246 END_VCARD
247 {
248 lexPopMode(0);
249 $$ = popVObject();
250 }
251 ;
252
253items: items item
254 | item
255 ;
256
257item: prop COLON
258 {
259 lexPushMode(L_VALUES);
260 }
261 values LINESEP
262 {
263 if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
264 lexPopMode(0);
265 lexPopMode(0);
266 }
267 | error
268 ;
269
270prop: name
271 {
272 enterProps($1);
273 }
274 attr_params
275 | name
276 {
277 enterProps($1);
278 }
279 ;
280
281attr_params: attr_params attr_param
282 | attr_param
283 ;
284
285attr_param: SEMICOLON attr
286 ;
287
288attr: name
289 {
290 enterAttr($1,0);
291 }
292 | name EQ name
293 {
294 enterAttr($1,$3);
295
296 }
297 ;
298
299name: ID
300 ;
301
302values: value SEMICOLON { enterValues($1); } values
303 | value
304 { enterValues($1); }
305 ;
306
307value: STRING
308 |
309 { $$ = 0; }
310 ;
311
312vcal:
313 BEGIN_VCAL
314 { if (!pushVObject(VCCalProp)) YYERROR; }
315 calitems
316 END_VCAL
317 { $$ = popVObject(); }
318 | BEGIN_VCAL
319 { if (!pushVObject(VCCalProp)) YYERROR; }
320 END_VCAL
321 { $$ = popVObject(); }
322 ;
323
324calitems: calitems calitem
325 | calitem
326 ;
327
328calitem:
329 eventitem
330 | todoitem
331 | items
332 ;
333
334eventitem:
335 BEGIN_VEVENT
336 {
337 lexPushMode(L_VEVENT);
338 if (!pushVObject(VCEventProp)) YYERROR;
339 }
340 items
341 END_VEVENT
342 {
343 lexPopMode(0);
344 popVObject();
345 }
346 | BEGIN_VEVENT
347 {
348 lexPushMode(L_VEVENT);
349 if (!pushVObject(VCEventProp)) YYERROR;
350 }
351 END_VEVENT
352 {
353 lexPopMode(0);
354 popVObject();
355 }
356 ;
357
358todoitem:
359 BEGIN_VTODO
360 {
361 lexPushMode(L_VTODO);
362 if (!pushVObject(VCTodoProp)) YYERROR;
363 }
364 items
365 END_VTODO
366 {
367 lexPopMode(0);
368 popVObject();
369 }
370 | BEGIN_VTODO
371 {
372 lexPushMode(L_VTODO);
373 if (!pushVObject(VCTodoProp)) YYERROR;
374 }
375 END_VTODO
376 {
377 lexPopMode(0);
378 popVObject();
379 }
380 ;
381
382%%
383/*------------------------------------*/
384static int pushVObject(const char *prop)
385 {
386 VObject *newObj;
387 if (ObjStackTop == MAXLEVEL)
388 return FALSE;
389
390 ObjStack[++ObjStackTop] = curObj;
391
392 if (curObj) {
393 newObj = addProp(curObj,prop);
394 curObj = newObj;
395 }
396 else
397 curObj = newVObject(prop);
398
399 return TRUE;
400 }
401
402
403/*---------------------------------------*/
404/* This pops the recently built vCard off the stack and returns it. */
405static VObject* popVObject()
406 {
407 VObject *oldObj;
408 if (ObjStackTop < 0) {
409 yyerror("pop on empty Object Stack\n");
410 return 0;
411 }
412 oldObj = curObj;
413 curObj = ObjStack[ObjStackTop--];
414
415 return oldObj;
416 }
417
418
419static void enterValues(const char *value)
420 {
421 if (fieldedProp && *fieldedProp) {
422 if (value) {
423 addPropValue(curProp,*fieldedProp,value);
424 }
425 /* else this field is empty, advance to next field */
426 fieldedProp++;
427 }
428 else {
429 if (value) {
430 setVObjectStringZValue_(curProp,strdup( value ));
431 }
432 }
433 deleteStr(value);
434 }
435
436static void enterProps(const char *s)
437 {
438 curProp = addGroup(curObj,s);
439 deleteStr(s);
440 }
441
442static void enterAttr(const char *s1, const char *s2)
443 {
444 const char *p1, *p2;
445 p1 = lookupProp_(s1);
446 if (s2) {
447 VObject *a;
448 p2 = lookupProp_(s2);
449 a = addProp(curProp,p1);
450 setVObjectStringZValue(a,p2);
451 }
452 else
453 addProp(curProp,p1);
454 if (qstricmp(p1,VCBase64Prop) == 0 || (s2 && qstricmp(p2,VCBase64Prop)==0))
455 lexPushMode(L_BASE64);
456 else if (qstricmp(p1,VCQuotedPrintableProp) == 0
457 || (s2 && qstricmp(p2,VCQuotedPrintableProp)==0))
458 lexPushMode(L_QUOTED_PRINTABLE);
459 deleteStr(s1); deleteStr(s2);
460 }
461
462
463#define MAX_LEX_LOOKAHEAD_0 32
464#define MAX_LEX_LOOKAHEAD 64
465#define MAX_LEX_MODE_STACK_SIZE 10
466#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
467
468struct LexBuf {
469 /* input */
470#ifdef INCLUDEMFC
471 CFile *inputFile;
472#else
473 FILE *inputFile;
474#endif
475 char *inputString;
476 unsigned long curPos;
477 unsigned long inputLen;
478 /* lookahead buffer */
479 /* -- lookahead buffer is short instead of char so that EOF
480 / can be represented correctly.
481 */
482 unsigned long len;
483 short buf[MAX_LEX_LOOKAHEAD];
484 unsigned long getPtr;
485 /* context stack */
486 unsigned long lexModeStackTop;
487 enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
488 /* token buffer */
489 unsigned long maxToken;
490 char *strs;
491 unsigned long strsLen;
492 } lexBuf;
493
494static void lexPushMode(enum LexMode mode)
495 {
496 if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
497 yyerror("lexical context stack overflow");
498 else {
499 lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
500 }
501 }
502
503static void lexPopMode(int top)
504 {
505 /* special case of pop for ease of error recovery -- this
506 version will never underflow */
507 if (top)
508 lexBuf.lexModeStackTop = 0;
509 else
510 if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
511 }
512
513static int lexWithinMode(enum LexMode mode) {
514 unsigned long i;
515 for (i=0;i<lexBuf.lexModeStackTop;i++)
516 if (mode == lexBuf.lexModeStack[i]) return 1;
517 return 0;
518 }
519
520static char lexGetc_()
521 {
522 /* get next char from input, no buffering. */
523 if (lexBuf.curPos == lexBuf.inputLen)
524 return EOF;
525 else if (lexBuf.inputString)
526 return *(lexBuf.inputString + lexBuf.curPos++);
527 else {
528#ifdef INCLUDEMFC
529 char result;
530 return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
531#else
532 return fgetc(lexBuf.inputFile);
533#endif
534 }
535 }
536
537static int lexGeta()
538 {
539 ++lexBuf.len;
540 return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
541 }
542
543static int lexGeta_(int i)
544 {
545 ++lexBuf.len;
546 return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
547 }
548
549static void lexSkipLookahead() {
550 if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
551 /* don't skip EOF. */
552 lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
553 lexBuf.len--;
554 }
555 }
556
557static int lexLookahead() {
558 int c = (lexBuf.len)?
559 lexBuf.buf[lexBuf.getPtr]:
560 lexGeta();
561 /* do the \r\n -> \n or \r -> \n translation here */
562 if (c == '\r') {
563 int a = (lexBuf.len>1)?
564 lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
565 lexGeta_(1);
566 if (a == '\n') {
567 lexSkipLookahead();
568 }
569 lexBuf.buf[lexBuf.getPtr] = c = '\n';
570 }
571 else if (c == '\n') {
572 int a = (lexBuf.len>1)?
573 lexBuf.buf[lexBuf.getPtr+1]:
574 lexGeta_(1);
575 if (a == '\r') {
576 lexSkipLookahead();
577 }
578 lexBuf.buf[lexBuf.getPtr] = '\n';
579 }
580 return c;
581 }
582
583static int lexGetc() {
584 int c = lexLookahead();
585 if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
586 /* EOF will remain in lookahead buffer */
587 lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
588 lexBuf.len--;
589 }
590 return c;
591 }
592
593static void lexSkipLookaheadWord() {
594 if (lexBuf.strsLen <= lexBuf.len) {
595 lexBuf.len -= lexBuf.strsLen;
596 lexBuf.getPtr = (lexBuf.getPtr + lexBuf.strsLen) % MAX_LEX_LOOKAHEAD;
597 }
598 }
599
600static void lexClearToken()
601 {
602 lexBuf.strsLen = 0;
603 }
604
605static void lexAppendc(int c)
606 {
607 lexBuf.strs[lexBuf.strsLen] = c;
608 /* append up to zero termination */
609 if (c == 0) return;
610 lexBuf.strsLen++;
611 if (lexBuf.strsLen > lexBuf.maxToken) {
612 /* double the token string size */
613 lexBuf.maxToken <<= 1;
614 lexBuf.strs = (char*) realloc(lexBuf.strs,(size_t)lexBuf.maxToken);
615 }
616 }
617
618static char* lexStr() {
619 return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1);
620 }
621
622static void lexSkipWhite() {
623 int c = lexLookahead();
624 while (c == ' ' || c == '\t') {
625 lexSkipLookahead();
626 c = lexLookahead();
627 }
628 }
629
630static char* lexGetWord() {
631 int c;
632 lexSkipWhite();
633 lexClearToken();
634 c = lexLookahead();
635 while (c != EOF && !strchr("\t\n ;:=",c)) {
636 lexAppendc(c);
637 lexSkipLookahead();
638 c = lexLookahead();
639 }
640 lexAppendc(0);
641 return lexStr();
642 }
643
644static void lexPushLookaheadc(int c) {
645 int putptr;
646 /* can't putback EOF, because it never leaves lookahead buffer */
647 if (c == EOF) return;
648 putptr = (int)lexBuf.getPtr - 1;
649 if (putptr < 0) putptr += MAX_LEX_LOOKAHEAD;
650 lexBuf.getPtr = putptr;
651 lexBuf.buf[putptr] = c;
652 lexBuf.len += 1;
653 }
654
655static char* lexLookaheadWord() {
656 /* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
657 / and thing bigger than that will stop the lookahead and return 0;
658 / leading white spaces are not recoverable.
659 */
660 int c;
661 int len = 0;
662 int curgetptr = 0;
663 lexSkipWhite();
664 lexClearToken();
665 curgetptr = (int)lexBuf.getPtr;// remember!
666 while (len < (MAX_LEX_LOOKAHEAD_0)) {
667 c = lexGetc();
668 len++;
669 if (c == EOF || strchr("\t\n ;:=", c)) {
670 lexAppendc(0);
671 /* restore lookahead buf. */
672 lexBuf.len += len;
673 lexBuf.getPtr = curgetptr;
674 return lexStr();
675 }
676 else
677 lexAppendc(c);
678 }
679 lexBuf.len += len;/* char that has been moved to lookahead buffer */
680 lexBuf.getPtr = curgetptr;
681 return 0;
682 }
683
684#ifdef _SUPPORT_LINE_FOLDING
685static void handleMoreRFC822LineBreak(int c) {
686 /* suport RFC 822 line break in cases like
687 *ADR: foo;
688 * morefoo;
689 * more foo;
690 */
691 if (c == ';') {
692 int a;
693 lexSkipLookahead();
694 /* skip white spaces */
695 a = lexLookahead();
696 while (a == ' ' || a == '\t') {
697 lexSkipLookahead();
698 a = lexLookahead();
699 }
700 if (a == '\n') {
701 lexSkipLookahead();
702 a = lexLookahead();
703 if (a == ' ' || a == '\t') {
704 /* continuation, throw away all the \n and spaces read so
705 * far
706 */
707 lexSkipWhite();
708 lexPushLookaheadc(';');
709 }
710 else {
711 lexPushLookaheadc('\n');
712 lexPushLookaheadc(';');
713 }
714 }
715 else {
716 lexPushLookaheadc(';');
717 }
718 }
719 }
720
721static char* lexGet1Value() {
722 int c;
723 lexSkipWhite();
724 c = lexLookahead();
725 lexClearToken();
726 while (c != EOF && c != ';') {
727 if (c == '\\' ) {
728 int a;
729 lexSkipLookahead();
730 a = lexLookahead();
731 if ( a != ';' ) {
732 lexAppendc('\\');
733 } else {
734 lexAppendc( ';' );
735 lexSkipLookahead();
736 }
737 } else if (c == '\n') {
738 int a;
739 lexSkipLookahead();
740 a = lexLookahead();
741 if (a == ' ' || a == '\t') {
742 lexAppendc(' ');
743 lexSkipLookahead();
744 }
745 else {
746 lexPushLookaheadc('\n');
747 break;
748 }
749 }
750 else {
751 lexAppendc(c);
752 lexSkipLookahead();
753 }
754 c = lexLookahead();
755 }
756 lexAppendc(0);
757 handleMoreRFC822LineBreak(c);
758 return c==EOF?0:lexStr();
759 }
760#endif
761
762static int match_begin_name(int end) {
763 char *n = lexLookaheadWord();
764 int token = ID;
765 if (n) {
766 if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
767 else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
768 else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
769 else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
770 deleteStr(n);
771 return token;
772 }
773 return 0;
774 }
775
776
777#ifdef INCLUDEMFC
778void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
779#else
780void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
781#endif
782 {
783 // initialize lex mode stack
784 lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
785
786 // iniatialize lex buffer.
787 lexBuf.inputString = (char*) inputstring;
788 lexBuf.inputLen = inputlen;
789 lexBuf.curPos = 0;
790 lexBuf.inputFile = inputfile;
791
792 lexBuf.len = 0;
793 lexBuf.getPtr = 0;
794
795 lexBuf.maxToken = MAXTOKEN;
796 lexBuf.strs = (char*)malloc(MAXTOKEN);
797 lexBuf.strsLen = 0;
798
799 }
800
801static void finiLex() {
802 free(lexBuf.strs);
803 }
804
805
806/*-----------------------------------*/
807/* This parses and converts the base64 format for binary encoding into
808 * a decoded buffer (allocated with new). See RFC 1521.
809 */
810static char * lexGetDataFromBase64()
811 {
812 unsigned long bytesLen = 0, bytesMax = 0;
813 int quadIx = 0, pad = 0;
814 unsigned long trip = 0;
815 unsigned char b;
816 int c;
817 unsigned char *bytes = NULL;
818 unsigned char *oldBytes = NULL;
819
820 DBG_(("db: lexGetDataFromBase64\n"));
821 while (1) {
822 c = lexGetc();
823 if (c == '\n') {
824 ++mime_lineNum;
825 if (lexLookahead() == '\n') {
826 /* a '\n' character by itself means end of data */
827 break;
828 }
829 else continue; /* ignore '\n' */
830 }
831 else {
832 if ((c >= 'A') && (c <= 'Z'))
833 b = (unsigned char)(c - 'A');
834 else if ((c >= 'a') && (c <= 'z'))
835 b = (unsigned char)(c - 'a') + 26;
836 else if ((c >= '0') && (c <= '9'))
837 b = (unsigned char)(c - '0') + 52;
838 else if (c == '+')
839 b = 62;
840 else if (c == '/')
841 b = 63;
842 else if (c == '=') {
843 b = 0;
844 pad++;
845 } else if ((c == ' ') || (c == '\t')) {
846 continue;
847 } else { /* error condition */
848 if (bytes) free(bytes);
849 else if (oldBytes) free(oldBytes);
850 // error recovery: skip until 2 adjacent newlines.
851 DBG_(("db: invalid character 0x%x '%c'\n", c,c));
852 if (c != EOF) {
853 c = lexGetc();
854 while (c != EOF) {
855 if (c == '\n' && lexLookahead() == '\n') {
856 ++mime_lineNum;
857 break;
858 }
859 c = lexGetc();
860 }
861 }
862 return NULL;
863 }
864 trip = (trip << 6) | b;
865 if (++quadIx == 4) {
866 unsigned char outBytes[3];
867 int numOut;
868 int i;
869 for (i = 0; i < 3; i++) {
870 outBytes[2-i] = (unsigned char)(trip & 0xFF);
871 trip >>= 8;
872 }
873 numOut = 3 - pad;
874 if (bytesLen + numOut > bytesMax) {
875 if (!bytes) {
876 bytesMax = 1024;
877 bytes = (unsigned char*)malloc((size_t)bytesMax);
878 }
879 else {
880 bytesMax <<= 2;
881 oldBytes = bytes;
882 bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
883 }
884 if (bytes == 0) {
885 mime_error("out of memory while processing BASE64 data\n");
886 }
887 }
888 if (bytes) {
889 memcpy(bytes + bytesLen, outBytes, numOut);
890 bytesLen += numOut;
891 }
892 trip = 0;
893 quadIx = 0;
894 }
895 }
896 } /* while */
897 DBG_(("db: bytesLen = %d\n", bytesLen));
898 /* kludge: all this won't be necessary if we have tree form
899 representation */
900 if (bytes) {
901 setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
902 free(bytes);
903 }
904 else if (oldBytes) {
905 setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
906 free(oldBytes);
907 }
908 return 0;
909 }
910
911static int match_begin_end_name(int end) {
912 int token;
913 lexSkipWhite();
914 if (lexLookahead() != ':') return ID;
915 lexSkipLookahead();
916 lexSkipWhite();
917 token = match_begin_name(end);
918 if (token == ID) {
919 lexPushLookaheadc(':');
920 DBG_(("db: ID '%s'\n", yylval.str));
921 return ID;
922 }
923 else if (token != 0) {
924 lexSkipLookaheadWord();
925 deleteStr(yylval.str);
926 DBG_(("db: begin/end %d\n", token));
927 return token;
928 }
929 return 0;
930 }
931
932static char* lexGetQuotedPrintable()
933 {
934 char cur;
935
936 lexClearToken();
937 do {
938 cur = lexGetc();
939 switch (cur) {
940 case '=': {
941 int c = 0;
942 int next[2];
943 int i;
944 for (i = 0; i < 2; i++) {
945 next[i] = lexGetc();
946 if (next[i] >= '0' && next[i] <= '9')
947 c = c * 16 + next[i] - '0';
948 else if (next[i] >= 'A' && next[i] <= 'F')
949 c = c * 16 + next[i] - 'A' + 10;
950 else
951 break;
952 }
953 if (i == 0) {
954 /* single '=' follow by LINESEP is continuation sign? */
955 if (next[0] == '\n') {
956 ++mime_lineNum;
957 }
958 else {
959 lexPushLookaheadc('=');
960 goto EndString;
961 }
962 }
963 else if (i == 1) {
964 lexPushLookaheadc(next[1]);
965 lexPushLookaheadc(next[0]);
966 lexAppendc('=');
967 } else {
968 lexAppendc(c);
969 }
970 break;
971 } /* '=' */
972 case '\n': {
973 lexPushLookaheadc('\n');
974 goto EndString;
975 }
976 case (char)EOF:
977 break;
978 default:
979 lexAppendc(cur);
980 break;
981 } /* switch */
982 } while (cur != (char)EOF);
983
984EndString:
985 lexAppendc(0);
986 return lexStr();
987 } /* LexQuotedPrintable */
988
989static int yylex() {
990
991 int lexmode = LEXMODE();
992 if (lexmode == L_VALUES) {
993 int c = lexGetc();
994 if (c == ';') {
995 DBG_(("db: SEMICOLON\n"));
996 lexPushLookaheadc(c);
997 handleMoreRFC822LineBreak(c);
998 lexSkipLookahead();
999 return SEMICOLON;
1000 }
1001 else if (strchr("\n",c)) {
1002 ++mime_lineNum;
1003 /* consume all line separator(s) adjacent to each other */
1004 c = lexLookahead();
1005 while (strchr("\n",c)) {
1006 lexSkipLookahead();
1007 c = lexLookahead();
1008 ++mime_lineNum;
1009 }
1010 DBG_(("db: LINESEP\n"));
1011 return LINESEP;
1012 }
1013 else {
1014 char *p = 0;
1015 lexPushLookaheadc(c);
1016 if (lexWithinMode(L_BASE64)) {
1017 /* get each char and convert to bin on the fly... */
1018 p = lexGetDataFromBase64();
1019 yylval.str = p;
1020 return STRING;
1021 }
1022 else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
1023 p = lexGetQuotedPrintable();
1024 }
1025 else {
1026#ifdef _SUPPORT_LINE_FOLDING
1027 p = lexGet1Value();
1028#else
1029 p = lexGetStrUntil(";\n");
1030#endif
1031 }
1032 if (p) {
1033 DBG_(("db: STRING: '%s'\n", p));
1034 yylval.str = p;
1035 return STRING;
1036 }
1037 else return 0;
1038 }
1039 }
1040 else {
1041 /* normal mode */
1042 while (1) {
1043 int c = lexGetc();
1044 switch(c) {
1045 case ':': {
1046 /* consume all line separator(s) adjacent to each other */
1047 /* ignoring linesep immediately after colon. */
1048 c = lexLookahead();
1049 while (strchr("\n",c)) {
1050 lexSkipLookahead();
1051 c = lexLookahead();
1052 ++mime_lineNum;
1053 }
1054 DBG_(("db: COLON\n"));
1055 return COLON;
1056 }
1057 case ';':
1058 DBG_(("db: SEMICOLON\n"));
1059 return SEMICOLON;
1060 case '=':
1061 DBG_(("db: EQ\n"));
1062 return EQ;
1063 /* ignore whitespace in this mode */
1064 case '\t':
1065 case ' ': continue;
1066 case '\n': {
1067 ++mime_lineNum;
1068 continue;
1069 }
1070 case EOF: return 0;
1071 break;
1072 default: {
1073 lexPushLookaheadc(c);
1074 if (isalnum(c)) {
1075 char *t = lexGetWord();
1076 yylval.str = t;
1077 if (!qstricmp(t, "begin")) {
1078 return match_begin_end_name(0);
1079 }
1080 else if (!qstricmp(t,"end")) {
1081 return match_begin_end_name(1);
1082 }
1083 else {
1084 DBG_(("db: ID '%s'\n", t));
1085 return ID;
1086 }
1087 }
1088 else {
1089 /* unknow token */
1090 return 0;
1091 }
1092 break;
1093 }
1094 }
1095 }
1096 }
1097 return 0;
1098 }
1099
1100
1101/***************************************************************************/
1102 /*** Public Functions ****/
1103/***************************************************************************/
1104
1105static VObject* Parse_MIMEHelper()
1106 {
1107 ObjStackTop = -1;
1108 mime_numErrors = 0;
1109 mime_lineNum = 1;
1110 vObjList = 0;
1111 curObj = 0;
1112
1113 if (yyparse() != 0)
1114 return 0;
1115
1116 finiLex();
1117 return vObjList;
1118 }
1119
1120/*--------------------------------------------*/
1121DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
1122 {
1123 initLex(input, len, 0);
1124 return Parse_MIMEHelper();
1125 }
1126
1127
1128#if INCLUDEMFC
1129
1130DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
1131 {
1132 unsigned long startPos;
1133 VObject *result;
1134
1135 initLex(0,-1,file);
1136 startPos = file->GetPosition();
1137 if (!(result = Parse_MIMEHelper()))
1138 file->Seek(startPos, CFile::begin);
1139 return result;
1140 }
1141
1142#else
1143
1144VObject* Parse_MIME_FromFile(FILE *file)
1145 {
1146 VObject *result;
1147 long startPos;
1148
1149 initLex(0,(unsigned long)-1,file);
1150 startPos = ftell(file);
1151 if (!(result = Parse_MIMEHelper())) {
1152 fseek(file,startPos,SEEK_SET);
1153 }
1154 return result;
1155 }
1156
1157DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
1158 {
1159 FILE *fp = fopen(fname,"r");
1160 if (fp) {
1161 VObject* o = Parse_MIME_FromFile(fp);
1162 fclose(fp);
1163 return o;
1164 }
1165 else {
1166 char msg[80];
1167 sprintf(msg, "can't open file '%s' for reading\n", fname);
1168 mime_error_(msg);
1169 return 0;
1170 }
1171 }
1172
1173#endif
1174
1175/*-------------------------------------*/
1176
1177static MimeErrorHandler mimeErrorHandler;
1178
1179DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
1180 {
1181 mimeErrorHandler = me;
1182 }
1183
1184void mime_error(char *s)
1185 {
1186 char msg[256];
1187 if (mimeErrorHandler) {
1188 sprintf(msg,"%s at line %d", s, mime_lineNum);
1189 mimeErrorHandler(msg);
1190 }
1191 }
1192
1193void mime_error_(char *s)
1194 {
1195 if (mimeErrorHandler) {
1196 mimeErrorHandler(s);
1197 }
1198 }
1199