Skip to content

Commit 63addd7

Browse files
committed
vcardparser.c: insert X-LIC-ERROR properties for non-fatal parse errors
1 parent 575afbc commit 63addd7

File tree

2 files changed

+183
-47
lines changed

2 files changed

+183
-47
lines changed

src/libicalvcard/vcardparser.c

+182-47
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <ctype.h>
77
#include <stdio.h>
8+
#include <stdarg.h>
89
#include <stdlib.h>
910
#include <string.h>
1011

@@ -40,6 +41,7 @@ enum parse_error {
4041
PE_QSTRING_EOF,
4142
PE_QSTRING_EOL,
4243
PE_QSTRING_EOV,
44+
PE_VALUE_INVALID,
4345
PE_ILLEGAL_CHAR,
4446
PE_NUMERR /* last */
4547
};
@@ -53,6 +55,7 @@ struct buf {
5355

5456
struct vcardparser_state {
5557
struct buf buf;
58+
struct buf errbuf;
5659
const char *base;
5760
const char *itemstart;
5861
const char *p;
@@ -75,13 +78,20 @@ struct vcardparser_errorpos {
7578
int errorchar;
7679
};
7780

81+
#define BUF_GROW 128
82+
7883
void buf_init(struct buf *buf, size_t size)
7984
{
8085
buf->len = 0;
8186
buf->alloc = size;
8287
buf->s = icalmemory_new_buffer(buf->alloc);
8388
}
8489

90+
static size_t buf_len(struct buf *buf)
91+
{
92+
return buf->len;
93+
}
94+
8595
static void buf_reset(struct buf *buf)
8696
{
8797
buf->len = 0;
@@ -133,6 +143,30 @@ static void buf_trim(struct buf *buf)
133143
}
134144
}
135145

146+
static void buf_vprintf(struct buf *buf, const char *fmt, va_list args)
147+
{
148+
va_list ap;
149+
size_t size, n;
150+
151+
/* Copy args in case we have to try again */
152+
va_copy(ap, args);
153+
154+
size = buf->alloc - buf->len;
155+
n = vsnprintf(buf->s + buf->len, size, fmt, args);
156+
157+
if (n >= size) {
158+
/* Grow the buffer and try again */
159+
size = n + BUF_GROW;
160+
buf->alloc += size;
161+
buf->s = icalmemory_resize_buffer(buf->s, buf->alloc);
162+
163+
n = vsnprintf(buf->s + buf->len, size, fmt, ap);
164+
}
165+
va_end(ap);
166+
167+
buf->len += n;
168+
}
169+
136170
#define NOTESTART() state->itemstart = state->p
137171
#define MAKE(X, Y) X = icalmemory_new_buffer(sizeof(struct Y))
138172
#define PUTC(C) buf_putc(&state->buf, C)
@@ -438,8 +472,31 @@ static int _parse_param_value(struct vcardparser_state *state)
438472
return PE_PARAMVALUE_EOF;
439473
}
440474

475+
static void _parse_error(struct vcardparser_state *state,
476+
enum vcardparameter_xlicerrortype type,
477+
const char *fmt, ...)
478+
{
479+
va_list ap;
480+
481+
va_start(ap, fmt);
482+
buf_reset(&state->errbuf);
483+
buf_vprintf(&state->errbuf, fmt, ap);
484+
va_end(ap);
485+
486+
if (state->prop) vcardproperty_free(state->prop);
487+
488+
state->prop =
489+
vcardproperty_vanew_xlicerror(buf_cstring(&state->errbuf),
490+
vcardparameter_new_xlicerrortype(type),
491+
(void *) 0);
492+
buf_reset(&state->buf);
493+
}
494+
441495
static int _parse_prop_params(struct vcardparser_state *state)
442496
{
497+
vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
498+
const char *group = vcardproperty_get_group(state->prop);
499+
443500
do {
444501
int r;
445502

@@ -449,13 +506,32 @@ static int _parse_prop_params(struct vcardparser_state *state)
449506

450507
/* get the name */
451508
r = _parse_param_name(state);
452-
if (r) return r;
509+
if (r) {
510+
_parse_error(state,
511+
VCARD_XLICERRORTYPE_PARAMETERNAMEPARSEERROR,
512+
"%s '%s' in %s%s%s property. Removing entire property",
513+
vcardparser_errstr(r), buf_cstring(&state->buf),
514+
group ? group : "", group ? "." : "",
515+
vcardproperty_kind_to_string(prop_kind));
516+
return r;
517+
}
518+
519+
vcardproperty_add_parameter(state->prop, state->param);
453520

454521
/* now get the value */
455522
r = _parse_param_value(state);
456-
if (r) return r;
457-
458-
vcardproperty_add_parameter(state->prop, state->param);
523+
if (r) {
524+
vcardparameter_kind param_kind = vcardparameter_isa(state->param);
525+
526+
_parse_error(state,
527+
VCARD_XLICERRORTYPE_PARAMETERVALUEPARSEERROR,
528+
"%s for %s in %s%s%s property. Removing entire property",
529+
vcardparser_errstr(r),
530+
vcardparameter_kind_to_string(param_kind),
531+
group ? group : "", group ? "." : "",
532+
vcardproperty_kind_to_string(prop_kind));
533+
return r;
534+
}
459535

460536
} while (*state->p == ';'); /* another parameter to parse */
461537

@@ -467,6 +543,7 @@ static int _parse_prop_name(struct vcardparser_state *state)
467543
const char *name;
468544
char *group = NULL;
469545
vcardproperty_kind kind;
546+
int r = 0;
470547

471548
NOTESTART();
472549

@@ -510,12 +587,19 @@ static int _parse_prop_name(struct vcardparser_state *state)
510587
buf_reset(&state->buf);
511588

512589
/* no INC - we need to see this char up a layer */
513-
return 0;
590+
return r;
514591

515592
case '.':
516-
if (group)
517-
return PE_PROP_MULTIGROUP;
518-
group = icalmemory_tmp_copy(buf_cstring(&state->buf));
593+
if (group) {
594+
char *tmp =
595+
icalmemory_tmp_buffer(strlen(group) + buf_len(&state->buf) + 2);
596+
sprintf(tmp, "%s.%s", group, buf_cstring(&state->buf));
597+
group = tmp;
598+
r = PE_PROP_MULTIGROUP;
599+
}
600+
else {
601+
group = icalmemory_tmp_copy(buf_cstring(&state->buf));
602+
}
519603
buf_reset(&state->buf);
520604
INC(1);
521605
break;
@@ -664,26 +748,102 @@ static int _parse_prop_value(struct vcardparser_state *state)
664748
buf_cstring(&state->buf));
665749
}
666750

667-
if (!value) return PE_ILLEGAL_CHAR;
751+
if (!value) return PE_VALUE_INVALID;
668752

669753
vcardproperty_set_value(state->prop, value);
670754
buf_reset(&state->buf);
671755

672756
return 0;
673757
}
674758

675-
static int _parse_prop(struct vcardparser_state *state)
759+
static void _parse_eatline(struct vcardparser_state *state)
760+
{
761+
while (*state->p) {
762+
763+
/* Handle control characters and break for NUL char */
764+
HANDLECTRL(state);
765+
766+
switch (*state->p) {
767+
case '\n':
768+
if (state->p[1] == ' ' || state->p[1] == '\t') {/* wrapped line */
769+
INC(2);
770+
break;
771+
}
772+
/* otherwise it's the end of the line */
773+
INC(1);
774+
return;
775+
776+
default:
777+
INC(1);
778+
break;
779+
}
780+
}
781+
}
782+
783+
static void _parse_prop(struct vcardparser_state *state)
676784
{
677785
int r = _parse_prop_name(state);
678-
if (r) return r;
786+
if (r) {
787+
if (r == PE_PROP_MULTIGROUP) {
788+
vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
789+
790+
_parse_error(state,
791+
VCARD_XLICERRORTYPE_PROPERTYPARSEERROR,
792+
"%s '%s.%s'. Removing entire property",
793+
vcardparser_errstr(r),
794+
vcardproperty_get_group(state->prop),
795+
vcardproperty_kind_to_string(prop_kind));
796+
_parse_eatline(state);
797+
}
798+
else if (r == PE_NAME_INVALID) {
799+
_parse_error(state,
800+
VCARD_XLICERRORTYPE_PROPERTYPARSEERROR,
801+
"%s '%s'. Removing entire property",
802+
vcardparser_errstr(r), buf_cstring(&state->buf));
803+
_parse_eatline(state);
804+
}
805+
else {
806+
_parse_error(state,
807+
VCARD_XLICERRORTYPE_PROPERTYPARSEERROR,
808+
"%s '%s'. Ignoring property",
809+
vcardparser_errstr(r), buf_cstring(&state->buf));
810+
}
811+
return;
812+
}
679813

680814
if (*state->p == ';') {
681815
r = _parse_prop_params(state);
682-
if (r) return r;
816+
if (r) {
817+
/* errors handled in _parse_prop_params() */
818+
return;
819+
}
683820
}
684821

685822
INC(1); /* skip ':' */
686-
return _parse_prop_value(state);
823+
r = _parse_prop_value(state);
824+
if (r) {
825+
vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
826+
const char *group = vcardproperty_get_group(state->prop);
827+
828+
if (r == PE_VALUE_INVALID) {
829+
_parse_error(state,
830+
VCARD_XLICERRORTYPE_VALUEPARSEERROR,
831+
"Error parsing '%s' as %s value in %s%s%s property."
832+
" Removing entire property",
833+
buf_cstring(&state->buf),
834+
vcardvalue_kind_to_string(state->value_kind),
835+
group ? group : "", group ? "." : "",
836+
vcardproperty_kind_to_string(prop_kind));
837+
}
838+
else {
839+
_parse_error(state,
840+
VCARD_XLICERRORTYPE_VALUEPARSEERROR,
841+
"%s in %s%s%s property. Removing entire property",
842+
vcardparser_errstr(r),
843+
group ? group : "", group ? "." : "",
844+
vcardproperty_kind_to_string(prop_kind));
845+
}
846+
}
687847
}
688848

689849
static int _parse_vcard(struct vcardparser_state *state,
@@ -701,8 +861,7 @@ static int _parse_vcard(struct vcardparser_state *state,
701861
continue;
702862
}
703863

704-
r = _parse_prop(state);
705-
if (r) break;
864+
_parse_prop(state);
706865

707866
if (vcardproperty_isa(state->prop) == VCARD_BEGIN_PROPERTY) {
708867
const char *val =
@@ -767,7 +926,7 @@ static int vcardparser_parse(struct vcardparser_state *state, int only_one)
767926

768927
state->p = state->base;
769928

770-
buf_init(&state->buf, 100);
929+
buf_init(&state->buf, BUF_GROW);
771930

772931
/* don't parse trailing non-whitespace */
773932
return _parse_vcard(state, state->root, only_one);
@@ -778,6 +937,8 @@ static int vcardparser_parse(struct vcardparser_state *state, int only_one)
778937
static void _free_state(struct vcardparser_state *state)
779938
{
780939
buf_free(&state->buf);
940+
buf_free(&state->errbuf);
941+
781942
if (state->root) vcardcomponent_free(state->root);
782943

783944
memset(state, 0, sizeof(struct vcardparser_state));
@@ -787,36 +948,8 @@ static void vcardparser_free(struct vcardparser_state *state)
787948
{
788949
_free_state(state);
789950
}
790-
#if 0
791-
void vcardparser_fillpos(struct vcardparser_state *state,
792-
struct vcardparser_errorpos *pos)
793-
{
794-
int l = 1;
795-
int c = 0;
796-
const char *p;
797-
798-
memset(pos, 0, sizeof(struct vcardparser_errorpos));
799-
800-
pos->errorpos = state->p - state->base;
801-
pos->startpos = state->itemstart - state->base;
802951

803-
for (p = state->base; p < state->p; p++) {
804-
if (*p == '\n') {
805-
l++;
806-
c = 0;
807-
}
808-
else {
809-
c++;
810-
}
811-
if (p == state->itemstart) {
812-
pos->startline = l;
813-
pos->startchar = c;
814-
}
815-
}
816-
817-
pos->errorline = l;
818-
pos->errorchar = c;
819-
}
952+
/* PUBLIC API */
820953

821954
const char *vcardparser_errstr(int err)
822955
{
@@ -839,6 +972,8 @@ const char *vcardparser_errstr(int err)
839972
return "End of data while parsing property name";
840973
case PE_NAME_EOL:
841974
return "End of line while parsing property name";
975+
case PE_NAME_INVALID:
976+
return "Invalid property name";
842977
case PE_PARAMVALUE_EOF:
843978
return "End of data while parsing parameter value";
844979
case PE_PARAMVALUE_EOL:
@@ -847,13 +982,13 @@ const char *vcardparser_errstr(int err)
847982
return "End of data while parsing quoted value";
848983
case PE_QSTRING_EOL:
849984
return "End of line while parsing quoted value";
985+
case PE_VALUE_INVALID:
986+
return "Invalid value for property";
850987
case PE_ILLEGAL_CHAR:
851988
return "Illegal character in vCard";
852989
}
853990
return "Unknown error";
854991
}
855-
#endif
856-
/* PUBLIC API */
857992

858993
vcardcomponent *vcardparser_parse_string(const char *str)
859994
{

src/libicalvcard/vcardparser.h

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "vcardcomponent.h"
77

88
LIBICAL_VCARD_EXPORT vcardcomponent *vcardparser_parse_string(const char *str);
9+
LIBICAL_VCARD_EXPORT const char *vcardparser_errstr(int err);
910

1011
#endif /* VCARDPARSER_H */
1112

0 commit comments

Comments
 (0)