summaryrefslogtreecommitdiff
path: root/library/backend/vcc.y
Side-by-side diff
Diffstat (limited to 'library/backend/vcc.y') (more/less context) (ignore whitespace changes)
-rw-r--r--library/backend/vcc.y29
1 files changed, 14 insertions, 15 deletions
diff --git a/library/backend/vcc.y b/library/backend/vcc.y
index 4c79368..bec2955 100644
--- a/library/backend/vcc.y
+++ b/library/backend/vcc.y
@@ -316,257 +316,257 @@ vcal:
END_VCAL
{ $$ = popVObject(); }
| BEGIN_VCAL
{ if (!pushVObject(VCCalProp)) YYERROR; }
END_VCAL
{ $$ = popVObject(); }
;
calitems: calitems calitem
| calitem
;
calitem:
eventitem
| todoitem
| items
;
eventitem:
BEGIN_VEVENT
{
lexPushMode(L_VEVENT);
if (!pushVObject(VCEventProp)) YYERROR;
}
items
END_VEVENT
{
lexPopMode(0);
popVObject();
}
| BEGIN_VEVENT
{
lexPushMode(L_VEVENT);
if (!pushVObject(VCEventProp)) YYERROR;
}
END_VEVENT
{
lexPopMode(0);
popVObject();
}
;
todoitem:
BEGIN_VTODO
{
lexPushMode(L_VTODO);
if (!pushVObject(VCTodoProp)) YYERROR;
}
items
END_VTODO
{
lexPopMode(0);
popVObject();
}
| BEGIN_VTODO
{
lexPushMode(L_VTODO);
if (!pushVObject(VCTodoProp)) YYERROR;
}
END_VTODO
{
lexPopMode(0);
popVObject();
}
;
%%
/*------------------------------------*/
static int pushVObject(const char *prop)
{
VObject *newObj;
if (ObjStackTop == MAXLEVEL)
return FALSE;
ObjStack[++ObjStackTop] = curObj;
if (curObj) {
newObj = addProp(curObj,prop);
curObj = newObj;
}
else
curObj = newVObject(prop);
return TRUE;
}
/*---------------------------------------*/
/* This pops the recently built vCard off the stack and returns it. */
static VObject* popVObject()
{
VObject *oldObj;
if (ObjStackTop < 0) {
yyerror("pop on empty Object Stack\n");
return 0;
}
oldObj = curObj;
curObj = ObjStack[ObjStackTop--];
return oldObj;
}
static void enterValues(const char *value)
{
if (fieldedProp && *fieldedProp) {
if (value) {
addPropValue(curProp,*fieldedProp,value);
}
/* else this field is empty, advance to next field */
fieldedProp++;
}
else {
if (value) {
setVObjectStringZValue_(curProp,strdup( value ));
}
}
deleteStr(value);
}
static void enterProps(const char *s)
{
curProp = addGroup(curObj,s);
deleteStr(s);
}
static void enterAttr(const char *s1, const char *s2)
{
- const char *p1, *p2;
+ const char *p1, *p2=0;
p1 = lookupProp_(s1);
if (s2) {
VObject *a;
p2 = lookupProp_(s2);
a = addProp(curProp,p1);
setVObjectStringZValue(a,p2);
}
else
addProp(curProp,p1);
if (qstricmp(p1,VCBase64Prop) == 0 || (s2 && qstricmp(p2,VCBase64Prop)==0))
lexPushMode(L_BASE64);
else if (qstricmp(p1,VCQuotedPrintableProp) == 0
|| (s2 && qstricmp(p2,VCQuotedPrintableProp)==0))
lexPushMode(L_QUOTED_PRINTABLE);
deleteStr(s1); deleteStr(s2);
}
#define MAX_LEX_LOOKAHEAD_0 32
#define MAX_LEX_LOOKAHEAD 64
#define MAX_LEX_MODE_STACK_SIZE 10
#define LEXMODE() (lexBuf.lexModeStack[lexBuf.lexModeStackTop])
struct LexBuf {
/* input */
#ifdef INCLUDEMFC
CFile *inputFile;
#else
FILE *inputFile;
#endif
char *inputString;
unsigned long curPos;
unsigned long inputLen;
/* lookahead buffer */
/* -- lookahead buffer is short instead of char so that EOF
/ can be represented correctly.
*/
unsigned long len;
short buf[MAX_LEX_LOOKAHEAD];
unsigned long getPtr;
/* context stack */
unsigned long lexModeStackTop;
enum LexMode lexModeStack[MAX_LEX_MODE_STACK_SIZE];
/* token buffer */
unsigned long maxToken;
char *strs;
unsigned long strsLen;
} lexBuf;
static void lexPushMode(enum LexMode mode)
{
if (lexBuf.lexModeStackTop == (MAX_LEX_MODE_STACK_SIZE-1))
yyerror("lexical context stack overflow");
else {
lexBuf.lexModeStack[++lexBuf.lexModeStackTop] = mode;
}
}
static void lexPopMode(int top)
{
/* special case of pop for ease of error recovery -- this
version will never underflow */
if (top)
lexBuf.lexModeStackTop = 0;
else
if (lexBuf.lexModeStackTop > 0) lexBuf.lexModeStackTop--;
}
static int lexWithinMode(enum LexMode mode) {
unsigned long i;
for (i=0;i<lexBuf.lexModeStackTop;i++)
if (mode == lexBuf.lexModeStack[i]) return 1;
return 0;
}
static int lexGetc_()
{
/* get next char from input, no buffering. */
if (lexBuf.curPos == lexBuf.inputLen)
return EOF;
else if (lexBuf.inputString)
return *(lexBuf.inputString + lexBuf.curPos++);
else {
#ifdef INCLUDEMFC
char result;
return lexBuf.inputFile->Read(&result, 1) == 1 ? result : EOF;
#else
return fgetc(lexBuf.inputFile);
#endif
}
}
static int lexGeta()
{
++lexBuf.len;
return (lexBuf.buf[lexBuf.getPtr] = lexGetc_());
}
static int lexGeta_(int i)
{
++lexBuf.len;
return (lexBuf.buf[(lexBuf.getPtr+i)%MAX_LEX_LOOKAHEAD] = lexGetc_());
}
static void lexSkipLookahead() {
if (lexBuf.len > 0 && lexBuf.buf[lexBuf.getPtr]!=EOF) {
/* don't skip EOF. */
lexBuf.getPtr = (lexBuf.getPtr + 1) % MAX_LEX_LOOKAHEAD;
lexBuf.len--;
}
}
static int lexLookahead() {
int c = (lexBuf.len)?
lexBuf.buf[lexBuf.getPtr]:
lexGeta();
/* do the \r\n -> \n or \r -> \n translation here */
if (c == '\r') {
int a = (lexBuf.len>1)?
lexBuf.buf[(lexBuf.getPtr+1)%MAX_LEX_LOOKAHEAD]:
lexGeta_(1);
if (a == '\n') {
lexSkipLookahead();
}
lexBuf.buf[lexBuf.getPtr] = c = '\n';
}
else if (c == '\n') {
int a = (lexBuf.len>1)?
@@ -688,480 +688,479 @@ static void handleMoreRFC822LineBreak(int c) {
* morefoo;
* more foo;
*/
if (c == ';') {
int a;
lexSkipLookahead();
/* skip white spaces */
a = lexLookahead();
while (a == ' ' || a == '\t') {
lexSkipLookahead();
a = lexLookahead();
}
if (a == '\n') {
lexSkipLookahead();
a = lexLookahead();
if (a == ' ' || a == '\t') {
/* continuation, throw away all the \n and spaces read so
* far
*/
lexSkipWhite();
lexPushLookaheadc(';');
}
else {
lexPushLookaheadc('\n');
lexPushLookaheadc(';');
}
}
else {
lexPushLookaheadc(';');
}
}
}
static char* lexGet1Value() {
int c;
lexSkipWhite();
c = lexLookahead();
lexClearToken();
while (c != EOF && (c != ';' || !fieldedProp)) {
if (c == '\\' ) {
int a;
lexSkipLookahead();
a = lexLookahead();
if ( a == ';' ) {
lexAppendc( ';' );
lexSkipLookahead();
} else if ( a == '\n' ) {
lexAppendc( '\n' );
lexSkipLookahead();
} else if ( a == '\\' ) {
lexAppendc( '\\' );
lexSkipLookahead();
} else {
lexAppendc('\\');
}
} else if (c == '\n') {
int a;
lexSkipLookahead();
a = lexLookahead();
if (a == ' ' || a == '\t') {
lexAppendc(' ');
lexSkipLookahead();
}
else {
lexPushLookaheadc('\n');
break;
}
}
else {
lexAppendc(c);
lexSkipLookahead();
}
c = lexLookahead();
}
lexAppendc(0);
handleMoreRFC822LineBreak(c);
return c==EOF?0:lexStr();
}
#endif
static int match_begin_name(int end) {
char *n = lexLookaheadWord();
int token = ID;
if (n) {
if (!qstricmp(n,"vcard")) token = end?END_VCARD:BEGIN_VCARD;
else if (!qstricmp(n,"vcalendar")) token = end?END_VCAL:BEGIN_VCAL;
else if (!qstricmp(n,"vevent")) token = end?END_VEVENT:BEGIN_VEVENT;
else if (!qstricmp(n,"vtodo")) token = end?END_VTODO:BEGIN_VTODO;
deleteStr(n);
return token;
}
return 0;
}
#ifdef INCLUDEMFC
void initLex(const char *inputstring, unsigned long inputlen, CFile *inputfile)
#else
void initLex(const char *inputstring, unsigned long inputlen, FILE *inputfile)
#endif
{
// initialize lex mode stack
lexBuf.lexModeStack[lexBuf.lexModeStackTop=0] = L_NORMAL;
// iniatialize lex buffer.
lexBuf.inputString = (char*) inputstring;
lexBuf.inputLen = inputlen;
lexBuf.curPos = 0;
lexBuf.inputFile = inputfile;
lexBuf.len = 0;
lexBuf.getPtr = 0;
lexBuf.maxToken = MAXTOKEN;
lexBuf.strs = (char*)malloc(MAXTOKEN);
lexBuf.strsLen = 0;
}
static void finiLex() {
free(lexBuf.strs);
}
/*-----------------------------------*/
/* This parses and converts the base64 format for binary encoding into
* a decoded buffer (allocated with new). See RFC 1521.
*/
-static char * lexGetDataFromBase64()
+static int lexGetDataFromBase64()
{
unsigned long bytesLen = 0, bytesMax = 0;
int quadIx = 0, pad = 0;
unsigned long trip = 0;
unsigned char b;
int c;
unsigned char *bytes = NULL;
unsigned char *oldBytes = NULL;
DBG_(("db: lexGetDataFromBase64\n"));
while (1) {
c = lexGetc();
+ lexSkipWhite();
if (c == '\n') {
++mime_lineNum;
if (lexLookahead() == '\n') {
/* a '\n' character by itself means end of data */
break;
}
else continue; /* ignore '\n' */
}
else {
if ((c >= 'A') && (c <= 'Z'))
b = (unsigned char)(c - 'A');
else if ((c >= 'a') && (c <= 'z'))
b = (unsigned char)(c - 'a') + 26;
else if ((c >= '0') && (c <= '9'))
b = (unsigned char)(c - '0') + 52;
else if (c == '+')
b = 62;
else if (c == '/')
b = 63;
else if (c == '=') {
b = 0;
pad++;
- } else if ((c == ' ') || (c == '\t')) {
- continue;
} else { /* error condition */
if (bytes) free(bytes);
else if (oldBytes) free(oldBytes);
// error recovery: skip until 2 adjacent newlines.
DBG_(("db: invalid character 0x%x '%c'\n", c,c));
if (c != EOF) {
c = lexGetc();
while (c != EOF) {
- if (c == '\n' && lexLookahead() == '\n') {
- ++mime_lineNum;
- break;
+ if (c == '\n') {
+ lexSkipWhite();
+ if(lexLookahead() == '\n') {
+ ++mime_lineNum;
+ break;
+ }
}
c = lexGetc();
}
}
- return NULL;
+ return c != EOF;
}
trip = (trip << 6) | b;
if (++quadIx == 4) {
unsigned char outBytes[3];
int numOut;
int i;
for (i = 0; i < 3; i++) {
outBytes[2-i] = (unsigned char)(trip & 0xFF);
trip >>= 8;
}
numOut = 3 - pad;
if (bytesLen + numOut > bytesMax) {
if (!bytes) {
bytesMax = 1024;
bytes = (unsigned char*)malloc((size_t)bytesMax);
}
else {
bytesMax <<= 2;
oldBytes = bytes;
bytes = (unsigned char*)realloc(bytes,(size_t)bytesMax);
}
if (bytes == 0) {
mime_error("out of memory while processing BASE64 data\n");
}
}
if (bytes) {
memcpy(bytes + bytesLen, outBytes, numOut);
bytesLen += numOut;
}
trip = 0;
quadIx = 0;
}
}
} /* while */
DBG_(("db: bytesLen = %d\n", bytesLen));
/* kludge: all this won't be necessary if we have tree form
representation */
if (bytes) {
setValueWithSize(curProp,bytes,(unsigned int)bytesLen);
free(bytes);
}
else if (oldBytes) {
setValueWithSize(curProp,oldBytes,(unsigned int)bytesLen);
free(oldBytes);
}
- return 0;
+ return bytesLen;
}
static int match_begin_end_name(int end) {
int token;
lexSkipWhite();
if (lexLookahead() != ':') return ID;
lexSkipLookahead();
lexSkipWhite();
token = match_begin_name(end);
if (token == ID) {
lexPushLookaheadc(':');
DBG_(("db: ID '%s'\n", yylval.str));
return ID;
}
else if (token != 0) {
lexSkipLookaheadWord();
deleteStr(yylval.str);
DBG_(("db: begin/end %d\n", token));
return token;
}
return 0;
}
static char* lexGetQuotedPrintable()
{
int c;
lexSkipWhite();
c = lexLookahead();
lexClearToken();
- while (c != EOF && c != ';') {
+ while (c != EOF && (c != ';' || !fieldedProp)) {
if (c == '\n') {
// break, leave '\n' on remaining chars.
break;
} else if (c == '=') {
int cur = 0;
int next;
lexSkipLookahead(); // skip '='
next = lexLookahead();
if (next == '\n') {
// skip and only skip the \n
lexSkipLookahead();
c = lexLookahead();
++mime_lineNum; // aid in error reporting
continue;
} else if (next >= '0' && next <= '9') {
cur = next - '0';
} else if (next >= 'A' && next <= 'F') {
cur = next - 'A' + 10;
} else {
// we have been sent buggy stuff. doesn't matter
// what we do so long as we keep going.
// should probably spit an error here
lexSkipLookahead();
c = lexLookahead();
continue;
}
lexSkipLookahead(); // skip A-Z0-9
next = lexLookahead();
cur = cur * 16;
// this time really just expecting 0-9A-F
if (next >= '0' && next <= '9') {
cur += next - '0';
} else if (next >= 'A' && next <= 'F') {
cur += next - 'A' + 10;
} else {
// we have been sent buggy stuff. doesn't matter
// what we do so long as we keep going.
// should probably spit an error here
lexSkipLookahead();
c = lexLookahead();
continue;
}
// got a valid escaped =. append it.
lexSkipLookahead(); // skip second 0-9A-F
lexAppendc(cur);
} else {
lexSkipLookahead(); // skip whatever we just read.
lexAppendc(c); // and append it.
}
c = lexLookahead();
}
lexAppendc(0);
return c==EOF?0:lexStr();
}
static int yylex() {
int lexmode = LEXMODE();
if (lexmode == L_VALUES) {
int c = lexGetc();
if (c == ';' && fieldedProp) {
DBG_(("db: SEMICOLON\n"));
lexPushLookaheadc(c);
handleMoreRFC822LineBreak(c);
lexSkipLookahead();
return SEMICOLON;
}
else if (strchr("\n",c)) {
++mime_lineNum;
/* consume all line separator(s) adjacent to each other */
c = lexLookahead();
while (strchr("\n",c)) {
lexSkipLookahead();
c = lexLookahead();
++mime_lineNum;
}
DBG_(("db: LINESEP\n"));
return LINESEP;
}
else {
char *p = 0;
lexPushLookaheadc(c);
if (lexWithinMode(L_BASE64)) {
/* get each char and convert to bin on the fly... */
- p = lexGetDataFromBase64();
-#if 0
- yylval.str = p;
- return STRING;
-#endif
+ yylval.str = NULL;
+ return lexGetDataFromBase64() ? STRING : 0;
}
else if (lexWithinMode(L_QUOTED_PRINTABLE)) {
p = lexGetQuotedPrintable();
}
else {
#ifdef _SUPPORT_LINE_FOLDING
p = lexGet1Value();
#else
p = lexGetStrUntil(";\n");
#endif
}
if (p) {
DBG_(("db: STRING: '%s'\n", p));
yylval.str = p;
return STRING;
}
else return 0;
}
}
else {
/* normal mode */
while (1) {
int c = lexGetc();
switch(c) {
case ':': {
/* consume all line separator(s) adjacent to each other */
/* ignoring linesep immediately after colon. */
/* I don't see this in the spec, and it breaks null values -- WA
c = lexLookahead();
while (strchr("\n",c)) {
lexSkipLookahead();
c = lexLookahead();
++mime_lineNum;
}
*/
DBG_(("db: COLON\n"));
return COLON;
}
case ';':
DBG_(("db: SEMICOLON\n"));
return SEMICOLON;
case '=':
DBG_(("db: EQ\n"));
return EQ;
/* ignore whitespace in this mode */
case '\t':
case ' ': continue;
case '\n': {
++mime_lineNum;
continue;
}
case EOF: return 0;
break;
default: {
lexPushLookaheadc(c);
if (isalnum(c)) {
char *t = lexGetWord();
yylval.str = t;
if (!qstricmp(t, "begin")) {
return match_begin_end_name(0);
}
else if (!qstricmp(t,"end")) {
return match_begin_end_name(1);
}
else {
DBG_(("db: ID '%s'\n", t));
return ID;
}
}
else {
/* unknow token */
return 0;
}
break;
}
}
}
}
return 0;
}
/***************************************************************************/
/*** Public Functions ****/
/***************************************************************************/
static VObject* Parse_MIMEHelper()
{
ObjStackTop = -1;
mime_numErrors = 0;
mime_lineNum = 1;
vObjList = 0;
curObj = 0;
if (yyparse() != 0)
return 0;
finiLex();
return vObjList;
}
/*--------------------------------------------*/
DLLEXPORT(VObject*) Parse_MIME(const char *input, unsigned long len)
{
initLex(input, len, 0);
return Parse_MIMEHelper();
}
#if INCLUDEMFC
DLLEXPORT(VObject*) Parse_MIME_FromFile(CFile *file)
{
unsigned long startPos;
VObject *result;
initLex(0,-1,file);
startPos = file->GetPosition();
if (!(result = Parse_MIMEHelper()))
file->Seek(startPos, CFile::begin);
return result;
}
#else
VObject* Parse_MIME_FromFile(FILE *file)
{
VObject *result;