-rw-r--r-- | library/backend/vcc.y | 1199 |
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 | ||
5 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
6 | |||
7 | For purposes of this license notice, the term Licensors shall mean, | ||
8 | collectively, Apple Computer, Inc., AT&T Corp., International | ||
9 | Business Machines Corporation and Siemens Rolm Communications Inc. | ||
10 | The term Licensor shall mean any of the Licensors. | ||
11 | |||
12 | Subject to acceptance of the following conditions, permission is hereby | ||
13 | granted by Licensors without the need for written agreement and without | ||
14 | license or royalty fees, to use, copy, modify and distribute this | ||
15 | software for any purpose. | ||
16 | |||
17 | The above copyright notice and the following four paragraphs must be | ||
18 | reproduced in all copies of this software and any software including | ||
19 | this software. | ||
20 | |||
21 | THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS AND NO LICENSOR SHALL HAVE | ||
22 | ANY OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR | ||
23 | MODIFICATIONS. | ||
24 | |||
25 | IN NO EVENT SHALL ANY LICENSOR BE LIABLE TO ANY PARTY FOR DIRECT, | ||
26 | INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT | ||
27 | OF THE USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | ||
28 | DAMAGE. | ||
29 | |||
30 | EACH LICENSOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, | ||
31 | INCLUDING BUT NOT LIMITED TO ANY WARRANTY OF NONINFRINGEMENT OR THE | ||
32 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
33 | PURPOSE. | ||
34 | |||
35 | The software is provided with RESTRICTED RIGHTS. Use, duplication, or | ||
36 | disclosure by the government are subject to restrictions set forth in | ||
37 | DFARS 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 ****/ | ||
138 | int mime_lineNum, mime_numErrors; /* yyerror() can use these */ | ||
139 | static VObject* vObjList; | ||
140 | static VObject *curProp; | ||
141 | static VObject *curObj; | ||
142 | static VObject* ObjStack[MAXLEVEL]; | ||
143 | static int ObjStackTop; | ||
144 | |||
145 | |||
146 | /* A helpful utility for the rest of the app. */ | ||
147 | #if __CPLUSPLUS__ | ||
148 | extern "C" { | ||
149 | #endif | ||
150 | |||
151 | extern void yyerror(char *s); | ||
152 | |||
153 | #if __CPLUSPLUS__ | ||
154 | }; | ||
155 | #endif | ||
156 | |||
157 | int yyparse(); | ||
158 | |||
159 | enum 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 ****/ | ||
171 | static int pushVObject(const char *prop); | ||
172 | static VObject* popVObject(); | ||
173 | static void lexPopMode(int top); | ||
174 | static int lexWithinMode(enum LexMode mode); | ||
175 | static void lexPushMode(enum LexMode mode); | ||
176 | static void enterProps(const char *s); | ||
177 | static void enterAttr(const char *s1, const char *s2); | ||
178 | static void enterValues(const char *value); | ||
179 | #define mime_error yyerror | ||
180 | void mime_error(char *s); | ||
181 | void 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 | |||
217 | mime: vobjects | ||
218 | ; | ||
219 | |||
220 | vobjects: vobjects vobject | ||
221 | { addList(&vObjList, $2); curObj = 0; } | ||
222 | | vobject | ||
223 | { addList(&vObjList, $1); curObj = 0; } | ||
224 | ; | ||
225 | |||
226 | vobject: vcard | ||
227 | | vcal | ||
228 | ; | ||
229 | |||
230 | vcard: | ||
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 | |||
253 | items: items item | ||
254 | | item | ||
255 | ; | ||
256 | |||
257 | item: 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 | |||
270 | prop: name | ||
271 | { | ||
272 | enterProps($1); | ||
273 | } | ||
274 | attr_params | ||
275 | | name | ||
276 | { | ||
277 | enterProps($1); | ||
278 | } | ||
279 | ; | ||
280 | |||
281 | attr_params: attr_params attr_param | ||
282 | | attr_param | ||
283 | ; | ||
284 | |||
285 | attr_param: SEMICOLON attr | ||
286 | ; | ||
287 | |||
288 | attr: name | ||
289 | { | ||
290 | enterAttr($1,0); | ||
291 | } | ||
292 | | name EQ name | ||
293 | { | ||
294 | enterAttr($1,$3); | ||
295 | |||
296 | } | ||
297 | ; | ||
298 | |||
299 | name: ID | ||
300 | ; | ||
301 | |||
302 | values: value SEMICOLON { enterValues($1); } values | ||
303 | | value | ||
304 | { enterValues($1); } | ||
305 | ; | ||
306 | |||
307 | value: STRING | ||
308 | | | ||
309 | { $$ = 0; } | ||
310 | ; | ||
311 | |||
312 | vcal: | ||
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 | |||
324 | calitems: calitems calitem | ||
325 | | calitem | ||
326 | ; | ||
327 | |||
328 | calitem: | ||
329 | eventitem | ||
330 | | todoitem | ||
331 | | items | ||
332 | ; | ||
333 | |||
334 | eventitem: | ||
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 | |||
358 | todoitem: | ||
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 | /*------------------------------------*/ | ||
384 | static 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. */ | ||
405 | static 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 | |||
419 | static 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 | |||
436 | static void enterProps(const char *s) | ||
437 | { | ||
438 | curProp = addGroup(curObj,s); | ||
439 | deleteStr(s); | ||
440 | } | ||
441 | |||
442 | static 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 | |||
468 | struct 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 | |||
494 | static 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 | |||
503 | static 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 | |||
513 | static 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 | |||
520 | static 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 | |||
537 | static int lexGeta() | ||
538 | { | ||
539 | ++lexBuf.len; | ||
540 | return (lexBuf.buf[lexBuf.getPtr] = lexGetc_()); | ||
541 | } | ||
542 | |||
543 | static int lexGeta_(int i) | ||
544 | { | ||
545 | ++lexBuf.len; | ||
546 | return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_()); | ||
547 | } | ||
548 | |||
549 | static 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 | |||
557 | static 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 | |||
583 | static 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 | |||
593 | static 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 | |||
600 | static void lexClearToken() | ||
601 | { | ||
602 | lexBuf.strsLen = 0; | ||
603 | } | ||
604 | |||
605 | static 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 | |||
618 | static char* lexStr() { | ||
619 | return dupStr(lexBuf.strs,(size_t)lexBuf.strsLen+1); | ||
620 | } | ||
621 | |||
622 | static void lexSkipWhite() { | ||
623 | int c = lexLookahead(); | ||
624 | while (c == ' ' || c == '\t') { | ||
625 | lexSkipLookahead(); | ||
626 | c = lexLookahead(); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | static 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 | |||
644 | static 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 | |||
655 | static 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 | ||
685 | static 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 | |||
721 | static 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 | |||
762 | static 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 | ||
778 | void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile) | ||
779 | #else | ||
780 | void 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 | |||
801 | static 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 | */ | ||
810 | static 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 | |||
911 | static 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 | |||
932 | static 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 | |||
984 | EndString: | ||
985 | lexAppendc(0); | ||
986 | return lexStr(); | ||
987 | } /* LexQuotedPrintable */ | ||
988 | |||
989 | static 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 | |||
1105 | static 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 | /*--------------------------------------------*/ | ||
1121 | DLLEXPORT(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 | |||
1130 | DLLEXPORT(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 | |||
1144 | VObject* 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 | |||
1157 | DLLEXPORT(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 | |||
1177 | static MimeErrorHandler mimeErrorHandler; | ||
1178 | |||
1179 | DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me) | ||
1180 | { | ||
1181 | mimeErrorHandler = me; | ||
1182 | } | ||
1183 | |||
1184 | void 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 | |||
1193 | void mime_error_(char *s) | ||
1194 | { | ||
1195 | if (mimeErrorHandler) { | ||
1196 | mimeErrorHandler(s); | ||
1197 | } | ||
1198 | } | ||
1199 | |||