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