PageRenderTime 53ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/libical-0.48/src/libicalvcal/vcc.y

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