-rw-r--r-- | library/backend/vcc.y | 2 | ||||
-rw-r--r-- | library/backend/vcc_yacc.cpp | 2 | ||||
-rw-r--r-- | library/backend/vobject.cpp | 1 |
3 files changed, 5 insertions, 0 deletions
diff --git a/library/backend/vcc.y b/library/backend/vcc.y index 94a8fea..4c79368 100644 --- a/library/backend/vcc.y +++ b/library/backend/vcc.y @@ -652,567 +652,569 @@ static void lexPushLookaheadc(int c) { lexBuf.len += 1;
}
static char* lexLookaheadWord() {
/* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
/ and thing bigger than that will stop the lookahead and return 0;
/ leading white spaces are not recoverable.
*/
int c;
int len = 0;
int curgetptr = 0;
lexSkipWhite();
lexClearToken();
curgetptr = (int)lexBuf.getPtr; // remember!
while (len < (MAX_LEX_LOOKAHEAD_0)) {
c = lexGetc();
len++;
if (c == EOF || strchr("\t\n ;:=", c)) {
lexAppendc(0);
/* restore lookahead buf. */
lexBuf.len += len;
lexBuf.getPtr = curgetptr;
return lexStr();
}
else
lexAppendc(c);
}
lexBuf.len += len; /* char that has been moved to lookahead buffer */
lexBuf.getPtr = curgetptr;
return 0;
}
#ifdef _SUPPORT_LINE_FOLDING
static void handleMoreRFC822LineBreak(int c) {
/* suport RFC 822 line break in cases like
* ADR: foo;
* 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()
{
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();
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;
}
c = lexGetc();
}
}
return NULL;
}
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;
}
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 != ';') {
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 }
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;
long startPos;
initLex(0,(unsigned long)-1,file);
startPos = ftell(file);
if (!(result = Parse_MIMEHelper())) {
fseek(file,startPos,SEEK_SET);
}
return result;
}
DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
{
FILE *fp = fopen(fname,"r");
if (fp) {
VObject* o = Parse_MIME_FromFile(fp);
fclose(fp);
return o;
}
else {
char msg[80];
sprintf(msg, "can't open file '%s' for reading\n", fname);
mime_error_(msg);
return 0;
}
}
#endif
/*-------------------------------------*/
static MimeErrorHandler mimeErrorHandler;
DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
{
mimeErrorHandler = me;
}
void mime_error(char *s)
{
char msg[256];
if (mimeErrorHandler) {
sprintf(msg,"%s at line %d", s, mime_lineNum);
mimeErrorHandler(msg);
}
}
void mime_error_(char *s)
{
if (mimeErrorHandler) {
mimeErrorHandler(s);
}
}
diff --git a/library/backend/vcc_yacc.cpp b/library/backend/vcc_yacc.cpp index 5649522..5f53aef 100644 --- a/library/backend/vcc_yacc.cpp +++ b/library/backend/vcc_yacc.cpp @@ -672,770 +672,772 @@ static void lexPushLookaheadc(int c) { lexBuf.len += 1;
}
static char* lexLookaheadWord() {
/* this function can lookahead word with max size of MAX_LEX_LOOKAHEAD_0
/ and thing bigger than that will stop the lookahead and return 0;
/ leading white spaces are not recoverable.
*/
int c;
int len = 0;
int curgetptr = 0;
lexSkipWhite();
lexClearToken();
curgetptr = (int)lexBuf.getPtr; // remember!
while (len < (MAX_LEX_LOOKAHEAD_0)) {
c = lexGetc();
len++;
if (c == EOF || strchr("\t\n ;:=", c)) {
lexAppendc(0);
/* restore lookahead buf. */
lexBuf.len += len;
lexBuf.getPtr = curgetptr;
return lexStr();
}
else
lexAppendc(c);
}
lexBuf.len += len; /* char that has been moved to lookahead buffer */
lexBuf.getPtr = curgetptr;
return 0;
}
#ifdef _SUPPORT_LINE_FOLDING
static void handleMoreRFC822LineBreak(int c) {
/* suport RFC 822 line break in cases like
* ADR: foo;
* 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()
{
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();
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;
}
c = lexGetc();
}
}
return NULL;
}
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;
}
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 != ';') {
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 }
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;
long startPos;
initLex(0,(unsigned long)-1,file);
startPos = ftell(file);
if (!(result = Parse_MIMEHelper())) {
fseek(file,startPos,SEEK_SET);
}
return result;
}
DLLEXPORT(VObject*) Parse_MIME_FromFileName(char *fname)
{
FILE *fp = fopen(fname,"r");
if (fp) {
VObject* o = Parse_MIME_FromFile(fp);
fclose(fp);
return o;
}
else {
char msg[80];
sprintf(msg, "can't open file '%s' for reading\n", fname);
mime_error_(msg);
return 0;
}
}
#endif
/*-------------------------------------*/
static MimeErrorHandler mimeErrorHandler;
DLLEXPORT(void) registerMimeErrorHandler(MimeErrorHandler me)
{
mimeErrorHandler = me;
}
void mime_error(char *s)
{
char msg[256];
if (mimeErrorHandler) {
sprintf(msg,"%s at line %d", s, mime_lineNum);
mimeErrorHandler(msg);
}
}
void mime_error_(char *s)
{
if (mimeErrorHandler) {
mimeErrorHandler(s);
}
}
#line 1240 "y.tab.c" #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab int #if defined(__STDC__) yyparse(void) #else yyparse() #endif { register int yym, yyn, yystate; #if YYDEBUG register char *yys; extern char *getenv(); if (yys = getenv("YYDEBUG")) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = (-1); yyssp = yyss; yyvsp = yyvs; *yyssp = yystate = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; yychar = (-1); if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; yyerror("syntax error"); #ifdef lint goto yyerrlab; #endif yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = (-1); goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; yyval = yyvsp[1-yym]; switch (yyn) { case 2: #line 221 "backend/vcc.y" { addList(&vObjList, yyvsp[0].vobj); curObj = 0; } break; case 3: #line 223 "backend/vcc.y" { addList(&vObjList, yyvsp[0].vobj); curObj = 0; } break; case 6: #line 232 "backend/vcc.y" {
lexPushMode(L_VCARD);
if (!pushVObject(VCCardProp)) YYERROR;
} break; case 7: #line 237 "backend/vcc.y" {
lexPopMode(0);
yyval.vobj = popVObject();
} break; case 8: #line 242 "backend/vcc.y" {
lexPushMode(L_VCARD);
if (!pushVObject(VCCardProp)) YYERROR;
} break; case 9: #line 247 "backend/vcc.y" {
lexPopMode(0);
yyval.vobj = popVObject();
} break; case 12: #line 258 "backend/vcc.y" {
lexPushMode(L_VALUES);
} break; case 13: #line 262 "backend/vcc.y" {
if (lexWithinMode(L_BASE64) || lexWithinMode(L_QUOTED_PRINTABLE))
lexPopMode(0);
lexPopMode(0);
} break; case 15: #line 271 "backend/vcc.y" {
enterProps(yyvsp[0].str);
} break; case 17: #line 276 "backend/vcc.y" {
enterProps(yyvsp[0].str);
} break; diff --git a/library/backend/vobject.cpp b/library/backend/vobject.cpp index b6d17dc..4c8de70 100644 --- a/library/backend/vobject.cpp +++ b/library/backend/vobject.cpp @@ -376,768 +376,769 @@ DLLEXPORT(VObject*) isAPropertyOf(VObject *o, const char *id) DLLEXPORT(VObject*) addGroup(VObject *o, const char *g) { /* a.b.c --> prop(c) prop(VCGrouping=b) prop(VCGrouping=a) */ char *dot = strrchr(g,'.'); if (dot) { VObject *p, *t; char *gs, *n = dot+1; gs = dupStr(g,0); /* so we can write to it. */ /* used to be * t = p = addProp_(o,lookupProp_(n)); */ t = p = addProp_(o,lookupProp(n)); dot = strrchr(gs,'.'); *dot = 0; do { dot = strrchr(gs,'.'); if (dot) { n = dot+1; *dot=0; } else n = gs; /* property(VCGroupingProp=n); * and the value may have VCGrouping property */ t = addProp(t,VCGroupingProp); setVObjectStringZValue(t,lookupProp_(n)); } while (n != gs); deleteStr(gs); return p; } else return addProp_(o,lookupProp(g)); } DLLEXPORT(VObject*) addPropValue(VObject *o, const char *p, const char *v) { VObject *prop; prop = addProp(o,p); setVObjectStringZValue_(prop, strdup( v ) ); return prop; } DLLEXPORT(VObject*) addPropSizedValue_(VObject *o, const char *p, const char *v, unsigned int size) { VObject *prop; prop = addProp(o,p); setValueWithSize_(prop, (void*)v, size); return prop; } DLLEXPORT(VObject*) addPropSizedValue(VObject *o, const char *p, const char *v, unsigned int size) { return addPropSizedValue_(o,p,dupStr(v,size),size); } DLLEXPORT(void) cleanVObject(VObject *o) { if (o == 0) return; if (o->prop) { /* destroy time: cannot use the iterator here. Have to break the cycle in the circular link list and turns it into regular NULL-terminated list -- since at some point of destruction, the reference entry for the iterator to work will not longer be valid. */ VObject *p; p = o->prop->next; o->prop->next = 0; do { VObject *t = p->next; cleanVObject(p); p = t; } while (p); } switch (VALUE_TYPE(o)) { case VCVT_STRINGZ: case VCVT_RAW: // assume they are all allocated by malloc. free((char*)STRINGZ_VALUE_OF(o)); break; case VCVT_VOBJECT: cleanVObject(VOBJECT_VALUE_OF(o)); break; } deleteVObject(o); } DLLEXPORT(void) cleanVObjects(VObject *list) { while (list) { VObject *t = list; list = nextVObjectInList(list); cleanVObject(t); } } /*---------------------------------------------------------------------- The following is a String Table Facilities. ----------------------------------------------------------------------*/ #define STRTBLSIZE 255 static StrItem *strTbl[STRTBLSIZE]; static unsigned int hashStr(const char *s) { unsigned int h = 0; int i; for (i=0;s[i];i++) { h += s[i]*i; } return h % STRTBLSIZE; } DLLEXPORT(const char*) lookupStr(const char *s) { StrItem *t; unsigned int h = hashStr(s); if ((t = strTbl[h]) != 0) { do { if (qstricmp(t->s,s) == 0) { t->refCnt++; return t->s; } t = t->next; } while (t); } s = dupStr(s,0); strTbl[h] = newStrItem(s,strTbl[h]); return s; } DLLEXPORT(void) unUseStr(const char *s) { StrItem *t, *p; unsigned int h = hashStr(s); if ((t = strTbl[h]) != 0) { p = t; do { if (qstricmp(t->s,s) == 0) { t->refCnt--; if (t->refCnt == 0) { if (p == strTbl[h]) { strTbl[h] = t->next; } else { p->next = t->next; } deleteStr(t->s); deleteStrItem(t); return; } } p = t; t = t->next; } while (t); } } DLLEXPORT(void) cleanStrTbl() { int i; for (i=0; i<STRTBLSIZE;i++) { StrItem *t = strTbl[i]; while (t) { StrItem *p; deleteStr(t->s); p = t; t = t->next; deleteStrItem(p); } while (t); strTbl[i] = 0; } } struct PreDefProp { const char *name; const char *alias; const char** fields; unsigned int flags; }; /* flags in PreDefProp */ #define PD_BEGIN 0x1 #define PD_INTERNAL 0x2 static const char *adrFields[] = { VCPostalBoxProp, VCExtAddressProp, VCStreetAddressProp, VCCityProp, VCRegionProp, VCPostalCodeProp, VCCountryNameProp, 0 }; static const char *nameFields[] = { VCFamilyNameProp, VCGivenNameProp, VCAdditionalNamesProp, VCNamePrefixesProp, VCNameSuffixesProp, NULL }; static const char *orgFields[] = { VCOrgNameProp, VCOrgUnitProp, VCOrgUnit2Prop, VCOrgUnit3Prop, VCOrgUnit4Prop, NULL }; static const char *AAlarmFields[] = { VCRunTimeProp, VCSnoozeTimeProp, VCRepeatCountProp, VCAudioContentProp, 0 }; /* ExDate -- has unamed fields */ /* RDate -- has unamed fields */ static const char *DAlarmFields[] = { VCRunTimeProp, VCSnoozeTimeProp, VCRepeatCountProp, VCDisplayStringProp, 0 }; static const char *MAlarmFields[] = { VCRunTimeProp, VCSnoozeTimeProp, VCRepeatCountProp, VCEmailAddressProp, VCNoteProp, 0 }; static const char *PAlarmFields[] = { VCRunTimeProp, VCSnoozeTimeProp, VCRepeatCountProp, VCProcedureNameProp, 0 }; static struct PreDefProp propNames[] = { { VC7bitProp, 0, 0, 0 }, { VC8bitProp, 0, 0, 0 }, { VCAAlarmProp, 0, AAlarmFields, 0 }, { VCAdditionalNamesProp, 0, 0, 0 }, { VCAdrProp, 0, adrFields, 0 }, { VCAgentProp, 0, 0, 0 }, { VCAIFFProp, 0, 0, 0 }, { VCAOLProp, 0, 0, 0 }, { VCAppleLinkProp, 0, 0, 0 }, { VCAttachProp, 0, 0, 0 }, { VCAttendeeProp, 0, 0, 0 }, { VCATTMailProp, 0, 0, 0 }, { VCAudioContentProp, 0, 0, 0 }, { VCAVIProp, 0, 0, 0 }, { VCBase64Prop, 0, 0, 0 }, { VCBBSProp, 0, 0, 0 }, { VCBirthDateProp, 0, 0, 0 }, { VCBMPProp, 0, 0, 0 }, { VCBodyProp, 0, 0, 0 }, { VCBusinessRoleProp, 0, 0, 0 }, { VCCalProp, 0, 0, PD_BEGIN }, { VCCaptionProp, 0, 0, 0 }, { VCCardProp, 0, 0, PD_BEGIN }, { VCCarProp, 0, 0, 0 }, { VCCategoriesProp, 0, 0, 0 }, { VCCellularProp, 0, 0, 0 }, { VCCGMProp, 0, 0, 0 }, { VCCharSetProp, 0, 0, 0 }, { VCCIDProp, VCContentIDProp, 0, 0 }, { VCCISProp, 0, 0, 0 }, { VCCityProp, 0, 0, 0 }, { VCClassProp, 0, 0, 0 }, { VCCommentProp, 0, 0, 0 }, { VCCompletedProp, 0, 0, 0 }, { VCContentIDProp, 0, 0, 0 }, { VCCountryNameProp, 0, 0, 0 }, { VCDAlarmProp, 0, DAlarmFields, 0 }, { VCDataSizeProp, 0, 0, PD_INTERNAL }, { VCDayLightProp, 0, 0, 0 }, { VCDCreatedProp, 0, 0, 0 }, { VCDeliveryLabelProp, 0, 0, 0 }, { VCDescriptionProp, 0, 0, 0 }, { VCDIBProp, 0, 0, 0 }, { VCDisplayStringProp, 0, 0, 0 }, { VCDomesticProp, 0, 0, 0 }, { VCDTendProp, 0, 0, 0 }, { VCDTstartProp, 0, 0, 0 }, { VCDueProp, 0, 0, 0 }, { VCEmailAddressProp, 0, 0, 0 }, { VCEncodingProp, 0, 0, 0 }, { VCEndProp, 0, 0, 0 }, { VCEventProp, 0, 0, PD_BEGIN }, { VCEWorldProp, 0, 0, 0 }, { VCExNumProp, 0, 0, 0 }, { VCExpDateProp, 0, 0, 0 }, { VCExpectProp, 0, 0, 0 }, { VCExtAddressProp, 0, 0, 0 }, { VCFamilyNameProp, 0, 0, 0 }, { VCFaxProp, 0, 0, 0 }, { VCFullNameProp, 0, 0, 0 }, { VCGeoLocationProp, 0, 0, 0 }, { VCGeoProp, 0, 0, 0 }, { VCGIFProp, 0, 0, 0 }, { VCGivenNameProp, 0, 0, 0 }, { VCGroupingProp, 0, 0, 0 }, { VCHomeProp, 0, 0, 0 }, { VCIBMMailProp, 0, 0, 0 }, { VCInlineProp, 0, 0, 0 }, { VCInternationalProp, 0, 0, 0 }, { VCInternetProp, 0, 0, 0 }, { VCISDNProp, 0, 0, 0 }, { VCJPEGProp, 0, 0, 0 }, { VCLanguageProp, 0, 0, 0 }, { VCLastModifiedProp, 0, 0, 0 }, { VCLastRevisedProp, 0, 0, 0 }, { VCLocationProp, 0, 0, 0 }, { VCLogoProp, 0, 0, 0 }, { VCMailerProp, 0, 0, 0 }, { VCMAlarmProp, 0, MAlarmFields, 0 }, { VCMCIMailProp, 0, 0, 0 }, { VCMessageProp, 0, 0, 0 }, { VCMETProp, 0, 0, 0 }, { VCModemProp, 0, 0, 0 }, { VCMPEG2Prop, 0, 0, 0 }, { VCMPEGProp, 0, 0, 0 }, { VCMSNProp, 0, 0, 0 }, { VCNamePrefixesProp, 0, 0, 0 }, { VCNameProp, 0, nameFields, 0 }, { VCNameSuffixesProp, 0, 0, 0 }, { VCNoteProp, 0, 0, 0 }, { VCOrgNameProp, 0, 0, 0 }, { VCOrgProp, 0, orgFields, 0 }, { VCOrgUnit2Prop, 0, 0, 0 }, { VCOrgUnit3Prop, 0, 0, 0 }, { VCOrgUnit4Prop, 0, 0, 0 }, { VCOrgUnitProp, 0, 0, 0 }, { VCPagerProp, 0, 0, 0 }, { VCPAlarmProp, 0, PAlarmFields, 0 }, { VCParcelProp, 0, 0, 0 }, { VCPartProp, 0, 0, 0 }, { VCPCMProp, 0, 0, 0 }, { VCPDFProp, 0, 0, 0 }, { VCPGPProp, 0, 0, 0 }, { VCPhotoProp, 0, 0, 0 }, { VCPICTProp, 0, 0, 0 }, { VCPMBProp, 0, 0, 0 }, { VCPostalBoxProp, 0, 0, 0 }, { VCPostalCodeProp, 0, 0, 0 }, { VCPostalProp, 0, 0, 0 }, { VCPowerShareProp, 0, 0, 0 }, { VCPreferredProp, 0, 0, 0 }, { VCPriorityProp, 0, 0, 0 }, { VCProcedureNameProp, 0, 0, 0 }, { VCProdIdProp, 0, 0, 0 }, { VCProdigyProp, 0, 0, 0 }, { VCPronunciationProp, 0, 0, 0 }, { VCPSProp, 0, 0, 0 }, { VCPublicKeyProp, 0, 0, 0 }, { VCQPProp, VCQuotedPrintableProp, 0, 0 }, + { VCQPProp, VCBase64Prop, 0, 0 }, { VCQuickTimeProp, 0, 0, 0 }, { VCQuotedPrintableProp, 0, 0, 0 }, { VCRDateProp, 0, 0, 0 }, { VCRegionProp, 0, 0, 0 }, { VCRelatedToProp, 0, 0, 0 }, { VCRepeatCountProp, 0, 0, 0 }, { VCResourcesProp, 0, 0, 0 }, { VCRNumProp, 0, 0, 0 }, { VCRoleProp, 0, 0, 0 }, { VCRRuleProp, 0, 0, 0 }, { VCRSVPProp, 0, 0, 0 }, { VCRunTimeProp, 0, 0, 0 }, { VCSequenceProp, 0, 0, 0 }, { VCSnoozeTimeProp, 0, 0, 0 }, { VCStartProp, 0, 0, 0 }, { VCStatusProp, 0, 0, 0 }, { VCStreetAddressProp, 0, 0, 0 }, { VCSubTypeProp, 0, 0, 0 }, { VCSummaryProp, 0, 0, 0 }, { VCTelephoneProp, 0, 0, 0 }, { VCTIFFProp, 0, 0, 0 }, { VCTimeZoneProp, 0, 0, 0 }, { VCTitleProp, 0, 0, 0 }, { VCTLXProp, 0, 0, 0 }, { VCTodoProp, 0, 0, PD_BEGIN }, { VCTranspProp, 0, 0, 0 }, { VCUniqueStringProp, 0, 0, 0 }, { VCURLProp, 0, 0, 0 }, { VCURLValueProp, 0, 0, 0 }, { VCValueProp, 0, 0, 0 }, { VCVersionProp, 0, 0, 0 }, { VCVideoProp, 0, 0, 0 }, { VCVoiceProp, 0, 0, 0 }, { VCWAVEProp, 0, 0, 0 }, { VCWMFProp, 0, 0, 0 }, { VCWorkProp, 0, 0, 0 }, { VCX400Prop, 0, 0, 0 }, { VCX509Prop, 0, 0, 0 }, { VCXRuleProp, 0, 0, 0 }, { 0,0,0,0 } }; static struct PreDefProp* lookupPropInfo(const char* str) { /* brute force for now, could use a hash table here. */ int i; for (i = 0; propNames[i].name; i++) if (qstricmp(str, propNames[i].name) == 0) { return &propNames[i]; } return 0; } DLLEXPORT(const char*) lookupProp_(const char* str) { int i; for (i = 0; propNames[i].name; i++) if (qstricmp(str, propNames[i].name) == 0) { const char* s; s = propNames[i].alias?propNames[i].alias:propNames[i].name; return lookupStr(s); } return lookupStr(str); } DLLEXPORT(const char*) lookupProp(const char* str) { int i; for (i = 0; propNames[i].name; i++) if (qstricmp(str, propNames[i].name) == 0) { const char *s; fieldedProp = propNames[i].fields; s = propNames[i].alias?propNames[i].alias:propNames[i].name; return lookupStr(s); } fieldedProp = 0; return lookupStr(str); } /*---------------------------------------------------------------------- APIs to Output text form. ----------------------------------------------------------------------*/ #define OFILE_REALLOC_SIZE 256 typedef struct OFile { FILE *fp; char *s; int len; int limit; int alloc:1; int fail:1; } OFile; #if 0 static void appendsOFile(OFile *fp, const char *s) { int slen; if (fp->fail) return; slen = strlen(s); if (fp->fp) { fwrite(s,1,slen,fp->fp); } else { stuff: if (fp->len + slen < fp->limit) { memcpy(fp->s+fp->len,s,slen); fp->len += slen; return; } else if (fp->alloc) { fp->limit = fp->limit + OFILE_REALLOC_SIZE; if (OFILE_REALLOC_SIZE <= slen) fp->limit += slen; fp->s = (char *) realloc(fp->s,fp->limit); if (fp->s) goto stuff; } if (fp->alloc) free(fp->s); fp->s = 0; fp->fail = 1; } } static void appendcOFile(OFile *fp, char c) { if (fp->fail) return; if (fp->fp) { fputc(c,fp->fp); } else { stuff: if (fp->len+1 < fp->limit) { fp->s[fp->len] = c; fp->len++; return; } else if (fp->alloc) { fp->limit = fp->limit + OFILE_REALLOC_SIZE; fp->s = (char *) realloc(fp->s,fp->limit); if (fp->s) goto stuff; } if (fp->alloc) free(fp->s); fp->s = 0; fp->fail = 1; } } #else static void appendcOFile_(OFile *fp, char c) { if (fp->fail) return; if (fp->fp) { fputc(c,fp->fp); } else { stuff: if (fp->len+1 < fp->limit) { fp->s[fp->len] = c; fp->len++; return; } else if (fp->alloc) { fp->limit = fp->limit + OFILE_REALLOC_SIZE; fp->s = (char *)realloc(fp->s,fp->limit); if (fp->s) goto stuff; } if (fp->alloc) free(fp->s); fp->s = 0; fp->fail = 1; } } static void appendcOFile(OFile *fp, char c) { if (c == '\n') { /* write out as <CR><LF> */ appendcOFile_(fp,0xd); appendcOFile_(fp,0xa); } else appendcOFile_(fp,c); } static void appendsOFile(OFile *fp, const char *s) { int i, slen; slen = strlen(s); for (i=0; i<slen; i++) { appendcOFile(fp,s[i]); } } #endif static void appendsOFileEncCs(OFile *fp) { if ( vobj_enc_s ) { appendsOFile(fp, ";" VCEncodingProp "="); appendsOFile(fp, vobj_enc_s); } appendsOFile(fp, ";" VCCharSetProp "="); appendsOFile(fp, vobj_cs); } static void initOFile(OFile *fp, FILE *ofp) { fp->fp = ofp; fp->s = 0; fp->len = 0; fp->limit = 0; fp->alloc = 0; fp->fail = 0; } static int writeBase64(OFile *fp, unsigned char *s, long len) { long cur = 0; int i, numQuads = 0; unsigned long trip; unsigned char b; char quad[5]; #define MAXQUADS 16 quad[4] = 0; while (cur < len) { // collect the triplet of bytes into 'trip' trip = 0; for (i = 0; i < 3; i++) { b = (cur < len) ? *(s + cur) : 0; cur++; trip = trip << 8 | b; } // fill in 'quad' with the appropriate four characters for (i = 3; i >= 0; i--) { b = (unsigned char)(trip & 0x3F); trip = trip >> 6; if ((3 - i) < (cur - len)) quad[i] = '='; // pad char else if (b < 26) quad[i] = (char)b + 'A'; else if (b < 52) quad[i] = (char)(b - 26) + 'a'; else if (b < 62) quad[i] = (char)(b - 52) + '0'; else if (b == 62) quad[i] = '+'; else quad[i] = '/'; } // now output 'quad' with appropriate whitespace and line ending appendsOFile(fp, (numQuads == 0 ? " " : "")); appendsOFile(fp, quad); appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : ""))); numQuads = (numQuads + 1) % MAXQUADS; } appendcOFile(fp,'\n'); return 1; } static const char *qpReplaceChar(unsigned char c) { if (c == '\n') { return "=0A=\n"; } else if ( // RFC 1521 (c >= 32 && c <= 60) // Note: " " not allowed at EOL || (c >= 62 && c <= 126) ) { return 0; } static char trans[4]; trans[0] = '='; trans[3] = '\0'; int rem = c % 16; int div = c / 16; if (div < 10) trans[1] = '0' + div; else trans[1] = 'A' + (div - 10); if (rem < 10) trans[2] = '0' + rem; else trans[2] = 'A' + (rem - 10); return trans; } static void writeEncString(OFile *fp, const char *s, bool nosemi) { /* only A-Z, 0-9 and "'" (ASCII code 39) "(" (ASCII code 40) ")" (ASCII code 41) "+" (ASCII code 43) "," (ASCII code 44) "-" (ASCII code 45) "/" (ASCII code 47) "?" (ASCII code 63) should remain un-encoded. '=' needs to be encoded as it is the escape character. ';' needs to be as it is a field separator. */ const char *p = s; switch ( vobj_enc ) { case EightBit: while (*p) { if ( *p == '\n' || nosemi && ( *p == '\\' || *p == ';' ) ) appendcOFile(fp, '\\'); appendcOFile(fp, *p); p++; } break; case QuotedPrintable: while (*p) { const char *rep = qpReplaceChar(*p); if (rep) appendsOFile(fp, rep); else if ( *p == ';' && nosemi ) appendsOFile(fp, "=3B"); else if ( *p == ' ' ) { if ( !p[1] || p[1] == '\n' ) // RFC 1521 appendsOFile(fp, "=20"); else appendcOFile(fp, *p); } else appendcOFile(fp, *p); p++; } break; case Base64: writeBase64(fp, (unsigned char*)p, strlen(p)); break; } } static bool includesUnprintable(VObject *o) { if (o) { if (VALUE_TYPE(o) == VCVT_STRINGZ) { const char *p = STRINGZ_VALUE_OF(o); if (p) { while (*p) { if (*p==' ' && (!p[1] || p[1]=='\n') // RFC 1521: spaces at ends need quoting || qpReplaceChar(*p) ) return TRUE; p++; } } } } return FALSE; } static void writeVObject_(OFile *fp, VObject *o); static void writeValue(OFile *fp, VObject *o, unsigned long size, bool nosemi) { if (o == 0) return; switch (VALUE_TYPE(o)) { case VCVT_STRINGZ: { writeEncString(fp, STRINGZ_VALUE_OF(o), nosemi); break; } case VCVT_UINT: { char buf[16]; sprintf(buf,"%u", INTEGER_VALUE_OF(o)); appendsOFile(fp,buf); break; } case VCVT_ULONG: { char buf[16]; |