36static ICAL_GLOBAL_VAR
void *xprop_value_kind_data = NULL;
66#define BUF_INITIALIZER \
70struct vcardparser_state {
74 const char *itemstart;
76 vcardproperty *version;
82 vcardparameter *param;
83 vcardvalue_kind value_kind;
86struct vcardparser_errorpos {
97void buf_init(
struct buf *buf,
size_t size)
104static size_t buf_len(
const struct buf *buf)
109static void buf_reset(
struct buf *buf)
114static void buf_free(
struct buf *buf)
121 buf->len = buf->alloc = 0;
124static void _buf_putc(
struct buf *buf,
char c)
126 char *pos = buf->s + buf->len;
131static void buf_putc(
struct buf *buf,
char c)
138static const char *buf_cstring(
struct buf *buf)
140 _buf_putc(buf,
'\0');
145static void buf_trim(
struct buf *buf)
152 const char *s = buf_cstring(buf);
154 for (buf->len = 0; *s; s++) {
155 if (isspace((
int)*s)) {
158 buf->s[buf->len++] = *s;
162#pragma GCC diagnostic push
163#pragma GCC diagnostic ignored "-Wformat-nonliteral"
164static void buf_vprintf(
struct buf *buf,
const char *fmt, va_list args)
172 size = buf->alloc - buf->len;
173 n = (size_t)vsnprintf(buf->s + buf->len, size, fmt, args);
181 n = (size_t)vsnprintf(buf->s + buf->len, size, fmt, ap);
187#pragma GCC diagnostic pop
189#define NOTESTART() state->itemstart = state->p
190#define MAKE(X, Y) X = icalmemory_new_buffer(sizeof(struct Y))
191#define PUTC(C) buf_putc(&state->buf, C)
192#define INC(I) state->p += I
194 ((ch) > 0 && (ch) <= 0x1f && (ch) != '\r' && (ch) != '\n' && (ch) != '\t')
195#define HANDLECTRL(state) \
197 if (IS_CTRL(*(state)->p)) { \
198 while (IS_CTRL(*(state)->p)) \
201 if ((*(state)->p) == 0) \
205static int _parse_param_name(
struct vcardparser_state *state)
207 vcardparameter_kind kind;
216 name = buf_cstring(&state->buf);
219 if (kind == VCARD_X_PARAMETER) {
221 }
else if (kind == VCARD_IANA_PARAMETER) {
224 buf_reset(&state->buf);
238 if (state->p[1] !=
' ' && state->p[1] !=
'\t') {
256static int _parse_param_quoted(
struct vcardparser_state *state,
257 bool is_structured,
bool is_multivalued)
276 if (state->p[1] ==
'\r') {
279 if (state->p[1] ==
'\n') {
280 if (state->p[2] !=
' ' && state->p[2] !=
'\t') {
281 return PE_QSTRING_EOL;
286 return PE_BACKQUOTE_EOF;
288 if (state->p[1] ==
'n' || state->p[1] ==
'N') {
290 }
else if (is_structured && strchr(
";,", state->p[1])) {
302 if (state->p[1] ==
'\r') {
305 if (state->p[1] ==
'\n') {
306 if (state->p[2] !=
' ' && state->p[2] !=
'\t') {
307 return PE_QSTRING_EOL;
311 if (state->p[1] ==
'\'') {
314 }
else if (state->p[1] ==
'n') {
317 }
else if (state->p[1] ==
'^') {
330 if (state->p[1] !=
' ' && state->p[1] !=
'\t') {
331 return PE_QSTRING_EOL;
337 if (is_multivalued && !is_structured) {
338 return PE_QSTRING_EOV;
350 return PE_QSTRING_EOF;
353static int _parse_param_value(
struct vcardparser_state *state)
355 bool is_multivalued = vcardparameter_is_multivalued(state->param);
356 bool is_structured = vcardparameter_is_structured(state->param);
366 if (state->p[1] ==
'\r') {
369 if (state->p[1] ==
'\n') {
370 if (state->p[2] !=
' ' && state->p[2] !=
'\t') {
371 return PE_PARAMVALUE_EOL;
376 return PE_BACKQUOTE_EOF;
378 if (state->p[1] ==
'n' || state->p[1] ==
'N') {
388 if (state->p[1] ==
'\r') {
391 if (state->p[1] ==
'\n') {
392 if (state->p[2] !=
' ' && state->p[2] !=
'\t') {
393 return PE_PARAMVALUE_EOL;
397 if (state->p[1] ==
'\'') {
400 }
else if (state->p[1] ==
'n') {
403 }
else if (state->p[1] ==
'^') {
414 while ((r = _parse_param_quoted(state,
416 is_multivalued)) == PE_QSTRING_EOV) {
417 vcardparameter_add_value_from_string(state->param,
418 buf_cstring(&state->buf));
420 buf_reset(&state->buf);
431 if (is_multivalued) {
432 vcardparameter_add_value_from_string(state->param,
433 buf_cstring(&state->buf));
435 vcardparameter_set_value_from_string(state->param,
436 buf_cstring(&state->buf));
440 vcardvalue_kind kind =
441 vcardvalue_string_to_kind(buf_cstring(&state->buf));
442 if (kind != VCARD_NO_VALUE) {
443 state->value_kind = kind;
448 buf_reset(&state->buf);
457 if (state->p[1] !=
' ' && state->p[1] !=
'\t') {
458 return PE_PARAMVALUE_EOL;
464 if (is_multivalued) {
465 vcardparameter_add_value_from_string(state->param,
466 buf_cstring(&state->buf));
467 buf_reset(&state->buf);
481 return PE_PARAMVALUE_EOF;
484static void _parse_error(
struct vcardparser_state *state,
485 enum vcardparameter_xlicerrortype type,
486 const char *fmt, ...)
491 buf_reset(&state->errbuf);
492 buf_vprintf(&state->errbuf, fmt, ap);
496 vcardproperty_free(state->prop);
498 state->version = NULL;
501 vcardparameter *errParam = vcardparameter_new_xlicerrortype(type);
502 state->prop = vcardproperty_vanew_xlicerror(buf_cstring(&state->errbuf),
505 buf_reset(&state->buf);
508static int _parse_prop_params(
struct vcardparser_state *state)
510 vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
511 const char *group = vcardproperty_get_group(state->prop);
521 r = _parse_param_name(state);
524 VCARD_XLICERRORTYPE_PARAMETERNAMEPARSEERROR,
525 "%s '%s' in %s%s%s property. Removing entire property",
526 vcardparser_errstr(r), buf_cstring(&state->buf),
527 group ? group :
"", group ?
"." :
"",
528 vcardproperty_kind_to_string(prop_kind));
532 vcardproperty_add_parameter(state->prop, state->param);
535 r = _parse_param_value(state);
540 VCARD_XLICERRORTYPE_PARAMETERVALUEPARSEERROR,
541 "%s for %s in %s%s%s property. Removing entire property",
542 vcardparser_errstr(r),
544 group ? group :
"", group ?
"." :
"",
545 vcardproperty_kind_to_string(prop_kind));
549 }
while (*state->p ==
';');
554static int _parse_prop_name(
struct vcardparser_state *state)
557 const char *group = NULL;
558 vcardproperty_kind kind;
559 vcardproperty_version version = VCARD_VERSION_NONE;
571 name = buf_cstring(&state->buf);
572 kind = vcardproperty_string_to_kind(name);
574 state->prop = vcardproperty_new(kind);
576 return PE_NAME_INVALID;
579 if (kind == VCARD_X_PROPERTY) {
580 vcardproperty_set_x_name(state->prop, name);
584 vcardproperty_set_group(state->prop, group);
587 if (state->version) {
588 version = vcardproperty_get_version(state->version);
593 case VCARD_GEO_PROPERTY:
594 state->value_kind = version == VCARD_VERSION_40 ? VCARD_URI_VALUE : VCARD_GEO_VALUE;
597 case VCARD_KEY_PROPERTY:
598 case VCARD_LOGO_PROPERTY:
599 case VCARD_PHOTO_PROPERTY:
600 case VCARD_SOUND_PROPERTY:
601 state->value_kind = version == VCARD_VERSION_40 ? VCARD_URI_VALUE : VCARD_TEXT_VALUE;
604 case VCARD_TZ_PROPERTY:
605 state->value_kind = version == VCARD_VERSION_40 ? VCARD_TEXT_VALUE : VCARD_UTCOFFSET_VALUE;
608 case VCARD_UID_PROPERTY:
609 state->value_kind = version == VCARD_VERSION_40 ? VCARD_URI_VALUE : VCARD_TEXT_VALUE;
612 case VCARD_X_PROPERTY:
614 xprop_value_kind_func ? xprop_value_kind_func(name, xprop_value_kind_data)
619 state->value_kind = vcardproperty_kind_to_value_kind(kind);
623 buf_reset(&state->buf);
630 size_t tmpLen = strlen(group) + buf_len(&state->buf) + 2;
632 snprintf(tmp, tmpLen - 1,
"%s.%s", group, buf_cstring(&state->buf));
634 r = PE_PROP_MULTIGROUP;
638 buf_reset(&state->buf);
646 if (state->p[1] ==
' ' || state->p[1] ==
'\t') {
648 }
else if (!state->buf.len) {
666static int _parse_prop_value(
struct vcardparser_state *state)
668 vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
669 vcardvalue *value = NULL;
680 while (state->p[1] && strchr(
"\r\n", state->p[1])) {
681 if (state->p[1] ==
'\r') {
684 if (state->p[1] ==
'\n') {
685 if (state->p[2] !=
' ' && state->p[2] !=
'\t') {
708 if (state->p[1] ==
' ' || state->p[1] ==
'\t') {
728 if (prop_kind == VCARD_VERSION_PROPERTY) {
729 buf_trim(&state->buf);
730 state->version = state->prop;
733 if (state->value_kind == VCARD_TEXTLIST_VALUE) {
734 char sep = vcardproperty_is_structured(prop_kind) ?
';' :
',';
735 vcardstrarray *textlist =
736 vcardtextlist_new_from_string(buf_cstring(&state->buf), sep);
738 value = vcardvalue_new_textlist(textlist);
741 value = vcardvalue_new_from_string(state->value_kind,
742 buf_cstring(&state->buf));
746 return PE_VALUE_INVALID;
749 vcardproperty_set_value(state->prop, value);
750 buf_reset(&state->buf);
755static void _parse_eatline(
struct vcardparser_state *state)
763 if (state->p[1] ==
' ' || state->p[1] ==
'\t') {
778static void _parse_prop(
struct vcardparser_state *state)
780 int r = _parse_prop_name(state);
782 if (r == PE_PROP_MULTIGROUP) {
783 vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
786 VCARD_XLICERRORTYPE_PROPERTYPARSEERROR,
787 "%s '%s.%s'. Removing entire property",
788 vcardparser_errstr(r),
789 vcardproperty_get_group(state->prop),
790 vcardproperty_kind_to_string(prop_kind));
791 _parse_eatline(state);
792 }
else if (r == PE_NAME_INVALID) {
794 VCARD_XLICERRORTYPE_PROPERTYPARSEERROR,
795 "%s '%s'. Removing entire property",
796 vcardparser_errstr(r), buf_cstring(&state->buf));
797 _parse_eatline(state);
800 VCARD_XLICERRORTYPE_PROPERTYPARSEERROR,
801 "%s '%s'. Ignoring property",
802 vcardparser_errstr(r), buf_cstring(&state->buf));
807 if (*state->p ==
';') {
808 r = _parse_prop_params(state);
816 r = _parse_prop_value(state);
818 vcardproperty_kind prop_kind = vcardproperty_isa(state->prop);
819 const char *group = vcardproperty_get_group(state->prop);
821 if (r == PE_VALUE_INVALID) {
823 VCARD_XLICERRORTYPE_VALUEPARSEERROR,
824 "Error parsing '%s' as %s value in %s%s%s property."
825 " Removing entire property",
826 buf_cstring(&state->buf),
827 vcardvalue_kind_to_string(state->value_kind),
828 group ? group :
"", group ?
"." :
"",
829 vcardproperty_kind_to_string(prop_kind));
832 VCARD_XLICERRORTYPE_VALUEPARSEERROR,
833 "%s in %s%s%s property. Removing entire property",
834 vcardparser_errstr(r),
835 group ? group :
"", group ?
"." :
"",
836 vcardproperty_kind_to_string(prop_kind));
841static int _parse_vcard(
struct vcardparser_state *state,
842 vcardcomponent *comp,
int only_one)
845 const char *cardstart = state->p;
850 if (*state->p ==
'\r' || *state->p ==
'\n' ||
851 *state->p ==
' ' || *state->p ==
'\t') {
858 if (vcardproperty_isa(state->prop) == VCARD_BEGIN_PROPERTY) {
859 if (vcardvalue_isa(vcardproperty_get_value(state->prop)) !=
861 r = PE_VALUE_INVALID;
866 vcardvalue_get_text(vcardproperty_get_value(state->prop));
867 vcardcomponent_kind kind = vcardcomponent_string_to_kind(val);
869 if (kind == VCARD_NO_COMPONENT) {
870 state->itemstart = cardstart;
871 r = PE_MISMATCHED_CARD;
875 vcardproperty_free(state->prop);
879 vcardcomponent_add_component(comp, sub);
880 r = _parse_vcard(state, sub, 0);
886 state->itemstart = cardstart;
887 r = PE_MISMATCHED_CARD;
889 }
else if (vcardproperty_isa(state->prop) == VCARD_END_PROPERTY) {
890 if (vcardvalue_isa(vcardproperty_get_value(state->prop)) !=
892 r = PE_VALUE_INVALID;
897 vcardvalue_get_text(vcardproperty_get_value(state->prop));
898 vcardcomponent_kind kind = vcardcomponent_string_to_kind(val);
900 if (kind != vcardcomponent_isa(comp)) {
903 state->itemstart = cardstart;
904 r = PE_MISMATCHED_CARD;
909 vcardcomponent_add_property(comp, state->prop);
915 if (vcardproperty_isa(state->prop) != VCARD_END_PROPERTY) {
916 r = PE_FINISHED_EARLY;
919 vcardproperty_free(state->prop);
926static int vcardparser_parse(
struct vcardparser_state *state,
int only_one)
930 state->p = state->base;
932 buf_init(&state->buf, BUF_GROW);
933 buf_init(&state->errbuf, BUF_GROW);
936 return _parse_vcard(state, state->root, only_one);
941static void _free_state(
struct vcardparser_state *state)
943 buf_free(&state->buf);
944 buf_free(&state->errbuf);
947 vcardcomponent_free(state->root);
950 memset(state, 0,
sizeof(
struct vcardparser_state));
953static void vcardparser_free(
struct vcardparser_state *state)
960const char *vcardparser_errstr(
int err)
963 case PE_BACKQUOTE_EOF:
964 return "EOF after backslash";
965 case PE_BEGIN_PARAMS:
966 return "Params on BEGIN field";
967 case PE_PROP_MULTIGROUP:
968 return "Multiple group levels in property name";
969 case PE_FINISHED_EARLY:
970 return "vCard not completed";
972 return "End of data while parsing parameter key";
974 return "End of line while parsing parameter key";
975 case PE_MISMATCHED_CARD:
976 return "Closed a different card name than opened";
978 return "End of data while parsing property name";
980 return "End of line while parsing property name";
981 case PE_NAME_INVALID:
982 return "Invalid property name";
983 case PE_PARAMVALUE_EOF:
984 return "End of data while parsing parameter value";
985 case PE_PARAMVALUE_EOL:
986 return "End of line while parsing parameter value";
988 return "End of data while parsing quoted value";
990 return "End of line while parsing quoted value";
992 return "End of line while parsing multi or structured value";
993 case PE_VALUE_INVALID:
994 return "Invalid value for property";
995 case PE_ILLEGAL_CHAR:
996 return "Illegal character in vCard";
999 return "Unknown error";
1003vcardcomponent *vcardparser_parse_string(
const char *str)
1005 struct vcardparser_state parser;
1006 vcardcomponent *vcard = NULL;
1009 memset(&parser, 0,
sizeof(
struct vcardparser_state));
1012 r = vcardparser_parse(&parser, 0);
1014 if (vcardcomponent_count_components(parser.root,
1015 VCARD_VCARD_COMPONENT) == 1) {
1016 vcard = vcardcomponent_get_first_component(parser.root,
1017 VCARD_VCARD_COMPONENT);
1018 vcardcomponent_remove_component(parser.root, vcard);
1020 vcard = parser.root;
1025 vcardparser_free(&parser);
1032 xprop_value_kind_func = func;
1033 xprop_value_kind_data = data;
void icalmemory_free_buffer(void *buf)
Releases a buffer.
void * icalmemory_resize_buffer(void *buf, size_t size)
Resizes a buffer created with icalmemory_new_buffer().
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
char * icalmemory_tmp_copy(const char *str)
Creates a copy of the given string, stored on the ring buffer, and returns it.
void icalmemory_append_char(char **buf, char **pos, size_t *buf_size, char ch)
Appends a character to a buffer.
void * icalmemory_tmp_buffer(size_t size)
Creates a new temporary buffer on the ring and returns it.
Common memory management routines.
vcardcomponent * vcardcomponent_new(vcardcomponent_kind kind)
Constructor.
Defines the data structure representing vCard components.
void vcardparameter_set_xname(vcardparameter *param, const char *v)
Sets the X-name of param to v.
vcardparameter_kind vcardparameter_isa(const vcardparameter *parameter)
void vcardparameter_set_iana_name(vcardparameter *param, const char *v)
Sets the IANA name of param to v.
vcardparameter * vcardparameter_new(vcardparameter_kind kind)
Creates new vcardparameter object.
Defines the data structure representing vCard parameters.
const char * vcardparameter_kind_to_string(vcardparameter_kind kind)
Returns a string representing the given vcardparameter_kind.
vcardparameter_kind vcardparameter_string_to_kind(const char *string)
Returns the vcardparameter_kind for a given string.
void vcardparser_set_xprop_value_kind(vcard_xprop_value_kind_func func, void *data)
Registers a parser callback to override the default value type of an x-property.
Line-oriented parsing vCard format.
vcardvalue_kind(* vcard_xprop_value_kind_func)(const char *name, void *data)
Callback function pointer to define x-property default value types.
Defines the data structure representing vCard properties.
Defines functions for creating vCard text lists.
Defines the data structure representing vCard values.