19#include "vcardvalueimpl.h"
23#include "icalerror_p.h"
30#define TMP_BUF_SIZE 1024
32LIBICAL_VCARD_EXPORT
struct vcardvalue_impl *vcardvalue_new_impl(vcardvalue_kind kind)
34 struct vcardvalue_impl *v;
51 memset(&(v->data), 0,
sizeof(v->data));
56vcardvalue *vcardvalue_new(vcardvalue_kind kind)
58 return (vcardvalue *)vcardvalue_new_impl(kind);
61vcardvalue *vcardvalue_clone(
const vcardvalue *old)
63 struct vcardvalue_impl *clone;
65 clone = vcardvalue_new_impl(old->kind);
72 memset(clone->id, 0, LIBICAL_VCARDVALUE_ID_LENGTH);
73 strncpy(clone->id, old->id, LIBICAL_VCARDVALUE_ID_LENGTH);
74 clone->kind = old->kind;
75 clone->size = old->size;
77 switch (clone->kind) {
78 case VCARD_TEXT_VALUE:
80 case VCARD_LANGUAGETAG_VALUE: {
81 if (old->data.v_string != 0) {
84 if (clone->data.v_string == 0) {
86 vcardvalue_free(clone);
93 if (old->x_value != 0) {
96 if (clone->x_value == 0) {
98 vcardvalue_free(clone);
106 case VCARD_STRUCTURED_VALUE:
107 if (old->data.v_structured != 0) {
108 clone->data.v_structured =
117 clone->data = old->data;
124char *vcardvalue_strdup_and_dequote_text(
const char **str,
const char *sep)
140 for (p = *str; *p != 0; p++) {
185 }
else if (sep && strchr(sep, *p)) {
211static char *vcardmemory_strdup_and_quote(
char **str,
char **str_p,
size_t *buf_sz,
212 const char *unquoted_str,
bool is_param)
217 *buf_sz = strlen(unquoted_str) + 1;
227 for (p = unquoted_str; *p != 0; p++) {
269static vcardvalue *vcardvalue_new_enum(vcardvalue_kind kind,
int x_type,
const char *str)
271 int e = vcardproperty_kind_and_string_to_enum((
int)kind, str);
272 struct vcardvalue_impl *value;
274 if (e != 0 && vcardproperty_enum_belongs_to_property(vcardproperty_value_kind_to_kind(kind), e)) {
275 value = vcardvalue_new_impl(kind);
276 value->data.v_enum = e;
279 value = vcardvalue_new_impl(kind);
280 value->data.v_enum = x_type;
281 vcardvalue_set_x(value, str);
293static bool simple_str_to_doublestr(
const char *from,
char *result,
int result_len,
char **to)
295 const char *start = NULL;
296 char *end = NULL, *cur = (
char *)from;
298 struct lconv *loc_data = localeconv();
303 if (!from || !result) {
308 while (*cur && isspace((
int)*cur)) {
317 while (*cur && (isdigit((
int)*cur) || *cur ==
'.' || *cur ==
'+' || *cur ==
'-')) {
321 len = (int)(ptrdiff_t)(end - start);
322 if (len + 1 >= result_len) {
324 len = result_len - 1;
331 for (i = 0; i < len; ++i) {
332 if (start[i] ==
'.' &&
333 loc_data && loc_data->decimal_point && loc_data->decimal_point[0] && loc_data->decimal_point[0] !=
'.') {
335 result[i] = loc_data->decimal_point[0];
337 result[i] = start[i];
345 if (sscanf(result,
"%lf", &dtest) != 1) {
351static vcardvalue *vcardvalue_new_from_string_with_error(vcardvalue_kind kind,
353 vcardproperty **error)
355 struct vcardvalue_impl *value = 0;
357 icalerror_check_arg_rz(str != 0,
"str");
364 case VCARD_BOOLEAN_VALUE: {
365 if (!strcmp(str,
"TRUE")) {
366 value = vcardvalue_new_boolean(1);
367 }
else if (!strcmp(str,
"FALSE")) {
368 value = vcardvalue_new_boolean(0);
369 }
else if (error != 0) {
370 char temp[TMP_BUF_SIZE];
371 vcardparameter *errParam;
373 snprintf(temp,
sizeof(temp),
374 "Could not parse %s as a %s property",
375 str, vcardvalue_kind_to_string(kind));
376 errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
377 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
382 case VCARD_VERSION_VALUE:
383 value = vcardvalue_new_enum(kind, (
int)VCARD_VERSION_X, str);
386 case VCARD_KIND_VALUE:
387 value = vcardvalue_new_enum(kind, (
int)VCARD_KIND_X, str);
390 case VCARD_GRAMGENDER_VALUE:
391 value = vcardvalue_new_enum(kind, (
int)VCARD_GRAMGENDER_X, str);
394 case VCARD_INTEGER_VALUE:
395 value = vcardvalue_new_integer(atoi(str));
398 case VCARD_FLOAT_VALUE:
399 value = vcardvalue_new_float((
float)atof(str));
402 case VCARD_UTCOFFSET_VALUE: {
403#pragma GCC diagnostic push
404#pragma GCC diagnostic ignored "-Wformat-nonliteral"
407 unsigned hour, min = 0;
408 int nchar = 0, len = (int)strlen(str);
414 fmt =
"%1[+-]%02u:%02u%n";
416 fmt =
"%1[+-]%02u%02u%n";
419 if (3 != sscanf(str, fmt, sign, &hour, &min, &nchar)) {
422 }
else if (2 != sscanf(str,
"%1[+-]%02u%n", sign, &hour, &nchar)) {
425#pragma GCC diagnostic pop
427 if (len && (len == nchar)) {
428 int utcoffset = (int)(hour * 3600 + min * 60);
431 utcoffset = -utcoffset;
433 value = vcardvalue_new_utcoffset(utcoffset);
434 }
else if (error != 0) {
435 char temp[TMP_BUF_SIZE];
436 vcardparameter *errParam;
438 snprintf(temp,
sizeof(temp),
439 "Could not parse %s as a %s property",
440 str, vcardvalue_kind_to_string(kind));
441 errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
442 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
447 case VCARD_TEXT_VALUE: {
448 char *dequoted_str = vcardvalue_strdup_and_dequote_text(&str, NULL);
450 value = vcardvalue_new_text(dequoted_str);
455 case VCARD_TEXTLIST_VALUE: {
456 value = vcardvalue_new_textlist(vcardtextlist_new_from_string(str,
','));
460 case VCARD_STRUCTURED_VALUE: {
462 value = vcardvalue_new_structured(st);
467 case VCARD_GEO_VALUE: {
470 memset(geo.coords.lat, 0, VCARD_GEO_LEN);
471 memset(geo.coords.lon, 0, VCARD_GEO_LEN);
473 if (simple_str_to_doublestr(str, geo.coords.lat, VCARD_GEO_LEN, &cur)) {
474 goto geo_parsing_error;
477 while (cur && isspace((
int)*cur)) {
482 if (!cur || *cur !=
';') {
483 goto geo_parsing_error;
489 while (cur && isspace((
int)*cur)) {
493 if (simple_str_to_doublestr(cur, geo.coords.lon, VCARD_GEO_LEN, &cur)) {
494 goto geo_parsing_error;
496 value = vcardvalue_new_geo(geo);
501 char temp[TMP_BUF_SIZE];
502 snprintf(temp,
sizeof(temp),
503 "Could not parse %s as a %s value",
504 str, vcardvalue_kind_to_string(kind));
505 vcardparameter *errParam =
506 vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
507 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
511 case VCARD_URI_VALUE:
512 value = vcardvalue_new_uri(str);
515 case VCARD_DATE_VALUE:
516 case VCARD_TIME_VALUE:
517 case VCARD_DATETIME_VALUE:
518 case VCARD_DATEANDORTIME_VALUE:
519 case VCARD_TIMESTAMP_VALUE: {
522 tt = vcardtime_from_string(str, kind == VCARD_TIME_VALUE);
523 if (!vcardtime_is_null_datetime(tt)) {
524 value = vcardvalue_new_impl(kind);
525 value->data.v_time = tt;
532 case VCARD_LANGUAGETAG_VALUE:
533 value = vcardvalue_new_languagetag(str);
536 case VCARD_X_VALUE: {
537 value = vcardvalue_new_x(str);
541 char temp[TMP_BUF_SIZE];
543 snprintf(temp, TMP_BUF_SIZE,
"Unknown type for \'%s\'", str);
544 vcardparameter *errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
545 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
548 snprintf(temp, TMP_BUF_SIZE,
549 "vcardvalue_new_from_string got an unknown value type (%s) for \'%s\'",
550 vcardvalue_kind_to_string(kind), str);
551 icalerror_warn(temp);
556 if (error != 0 && *error == 0 && value == 0) {
557 char temp[TMP_BUF_SIZE];
558 vcardparameter *errParam;
560 snprintf(temp, TMP_BUF_SIZE,
"Failed to parse value: \'%s\'", str);
563 errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
564 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
570vcardvalue *vcardvalue_new_from_string(vcardvalue_kind kind,
const char *str)
572 return vcardvalue_new_from_string_with_error(kind, str, (vcardproperty **)0);
575void vcardvalue_free(vcardvalue *v)
577 icalerror_check_arg_rv((v != 0),
"value");
579 if (v->parent != 0) {
583 if (v->x_value != 0) {
588 case VCARD_TEXT_VALUE:
589 case VCARD_URI_VALUE:
590 case VCARD_LANGUAGETAG_VALUE: {
591 if (v->data.v_string != 0) {
593 v->data.v_string = 0;
598 case VCARD_TEXTLIST_VALUE: {
599 if (v->data.v_textlist != 0) {
600 vcardstrarray_free(v->data.v_textlist);
602 v->data.v_textlist = 0;
606 case VCARD_STRUCTURED_VALUE: {
608 v->data.v_structured = 0;
612 case VCARD_GEO_VALUE: {
613 v->data.v_geo.coords.lat[0] =
'\0';
614 v->data.v_geo.coords.lon[0] =
'\0';
623 v->kind = VCARD_NO_VALUE;
626 memset(&(v->data), 0,
sizeof(v->data));
631bool vcardvalue_is_valid(
const vcardvalue *value)
640static char *vcardvalue_boolean_as_vcard_string_r(
const vcardvalue *value)
645 icalerror_check_arg_rz((value != 0),
"value");
648 data = vcardvalue_get_integer(value);
650 strncpy(str, data ?
"TRUE" :
"FALSE", 6);
655#define MAX_INT_DIGITS 12
657static char *vcardvalue_int_as_vcard_string_r(
const vcardvalue *value)
662 icalerror_check_arg_rz((value != 0),
"value");
665 data = vcardvalue_get_integer(value);
667 snprintf(str, MAX_INT_DIGITS,
"%d", data);
672static char *vcardvalue_utcoffset_as_vcard_string_r(
const vcardvalue *value,
673 vcardproperty_version version)
681 icalerror_check_arg_rz((value != 0),
"value");
684 data = vcardvalue_get_utcoffset(value);
686 if (abs(data) == data) {
693 m = (data - (h * 3600)) / 60;
694 s = (data - (h * 3600) - (m * 60));
699#pragma GCC diagnostic push
700#pragma GCC diagnostic ignored "-Wformat-nonliteral"
702 if (version == VCARD_VERSION_40) {
703 fmt =
"%c%02d%02d%02d";
705 fmt =
"%c%02d:%02d:%02d";
707 }
else if (version == VCARD_VERSION_40) {
717 snprintf(str, size, fmt, sign, h, m, s);
718#pragma GCC diagnostic pop
722static char *vcardvalue_text_as_vcard_string_r(
const vcardvalue *value)
728 return vcardmemory_strdup_and_quote(&str, &str_p, &buf_sz,
729 value->data.v_string, 0);
732static char *vcardvalue_string_as_vcard_string_r(
const vcardvalue *value)
737 icalerror_check_arg_rz((value != 0),
"value");
738 data = value->data.v_string;
740 const size_t len_data = strlen(data) + 1;
743 strncpy(str, data, len_data);
744 str[len_data - 1] =
'\0';
749static void _vcardstrarray_as_vcard_string_r(
char **str,
char **str_p,
size_t *buf_sz,
750 vcardstrarray *array,
const char sep,
753 if (!vcardstrarray_size(array)) {
754 (void)vcardmemory_strdup_and_quote(str, str_p, buf_sz,
"", is_param);
760 for (i = 0; i < vcardstrarray_size(array); i++) {
766 (void)vcardmemory_strdup_and_quote(str, str_p, buf_sz,
767 vcardstrarray_element_at(array, i), is_param);
771char *vcardstrarray_as_vcard_string_r(
const vcardstrarray *array,
const char sep)
774 char *buf_ptr = NULL;
777 _vcardstrarray_as_vcard_string_r(&buf, &buf_ptr, &buf_size,
778 (vcardstrarray *)array, sep, 0);
803 _vcardstrarray_as_vcard_string_r(&buf, &buf_ptr, &buf_size,
804 array,
',', is_param);
813static char *vcardvalue_textlist_as_vcard_string_r(
const vcardvalue *value,
816 icalerror_check_arg_rz((value != 0),
"value");
818 return vcardstrarray_as_vcard_string_r(value->data.v_textlist, sep);
821static char *vcardvalue_structured_as_vcard_string_r(
const vcardvalue *value)
823 icalerror_check_arg_rz((value != 0),
"value");
828static char *vcardvalue_float_as_vcard_string_r(
const vcardvalue *value)
834 icalerror_check_arg_rz((value != 0),
"value");
835 data = vcardvalue_get_float(value);
841 (void)setlocale(LC_NUMERIC,
"C");
845 snprintf(str, 40,
"%f", data);
848 (void)setlocale(LC_NUMERIC, old_locale);
854static char *vcardvalue_geo_as_vcard_string_r(
const vcardvalue *value)
856 icalerror_check_arg_rz((value != 0),
"value");
857 size_t max_len = 2 * VCARD_GEO_LEN;
859 snprintf(str, max_len,
"%s;%s",
860 value->data.v_geo.coords.lat, value->data.v_geo.coords.lon);
861 str[max_len - 1] =
'\0';
865const char *vcardvalue_as_vcard_string(
const vcardvalue *value)
869 buf = vcardvalue_as_vcard_string_r(value);
874char *vcardvalue_as_vcard_string_r(
const vcardvalue *value)
876 vcardproperty_version version = VCARD_VERSION_NONE;
887 version = vcardcomponent_get_version(comp);
891 if (version == VCARD_VERSION_NONE) {
892 version = VCARD_VERSION_30;
895 is_structured = vcardproperty_is_structured(vcardproperty_isa(value->parent));
897 switch (value->kind) {
898 case VCARD_BOOLEAN_VALUE:
899 return vcardvalue_boolean_as_vcard_string_r(value);
901 case VCARD_INTEGER_VALUE:
902 return vcardvalue_int_as_vcard_string_r(value);
904 case VCARD_UTCOFFSET_VALUE:
905 return vcardvalue_utcoffset_as_vcard_string_r(value, version);
907 case VCARD_TEXT_VALUE:
908 return vcardvalue_text_as_vcard_string_r(value);
910 case VCARD_TEXTLIST_VALUE:
911 return vcardvalue_textlist_as_vcard_string_r(value,
912 is_structured ?
';' :
',');
914 case VCARD_STRUCTURED_VALUE:
915 return vcardvalue_structured_as_vcard_string_r(value);
917 case VCARD_GEO_VALUE:
918 return vcardvalue_geo_as_vcard_string_r(value);
920 case VCARD_URI_VALUE:
921 case VCARD_LANGUAGETAG_VALUE:
922 return vcardvalue_string_as_vcard_string_r(value);
924 case VCARD_TIME_VALUE:
925 flags |= VCARDTIME_BARE_TIME;
928 case VCARD_DATE_VALUE:
931 case VCARD_DATETIME_VALUE:
934 case VCARD_DATEANDORTIME_VALUE:
937 case VCARD_TIMESTAMP_VALUE:
938 if (version == VCARD_VERSION_40) {
939 flags |= VCARDTIME_AS_V4;
942 return vcardtime_as_vcard_string_r(value->data.v_time, flags);
944 case VCARD_FLOAT_VALUE:
945 return vcardvalue_float_as_vcard_string_r(value);
947 case VCARD_KIND_VALUE:
948 case VCARD_VERSION_VALUE:
949 case VCARD_GRAMGENDER_VALUE:
950 if (value->x_value != 0) {
954 return vcardproperty_enum_to_string_r(value->data.v_enum);
957 if (value->x_value != 0) {
971vcardvalue_kind vcardvalue_isa(
const vcardvalue *value)
974 return VCARD_NO_VALUE;
980bool vcardvalue_isa_value(
void *value)
982 const struct vcardvalue_impl *impl = (
struct vcardvalue_impl *)value;
984 icalerror_check_arg_rz((value != 0),
"value");
986 if (strcmp(impl->id,
"val") == 0) {
999 switch (value->kind) {
1000 case VCARD_DATE_VALUE:
1001 case VCARD_TIME_VALUE:
1002 case VCARD_DATETIME_VALUE:
1003 case VCARD_DATEANDORTIME_VALUE:
1004 case VCARD_TIMESTAMP_VALUE:
1005 if (vcardtime_is_timestamp(value->data.v_time)) {
1006 value->kind = VCARD_TIMESTAMP_VALUE;
1007 }
else if (vcardtime_is_time(value->data.v_time)) {
1008 value->kind = VCARD_TIME_VALUE;
1009 }
else if (vcardtime_is_date(value->data.v_time)) {
1010 value->kind = VCARD_DATE_VALUE;
1012 value->kind = VCARD_DATETIME_VALUE;
1023 icalerror_check_arg_rv((value != 0),
"value");
1025 value->parent = property;
1030 return value->parent;
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
void icalmemory_free_buffer(void *buf)
Releases a buffer.
char * icalmemory_strdup(const char *s)
Creates a duplicate of a string.
void icalmemory_append_string(char **buf, char **pos, size_t *buf_size, const char *string)
Appends a string to a buffer.
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
void icalmemory_append_char(char **buf, char **pos, size_t *buf_size, char ch)
Appends a character to a buffer.
void icalmemory_add_tmp_buffer(void *buf)
Adds an externally allocated buffer to the ring.
Common memory management routines.
Defines the data structure representing vCard components.
vcardcomponent * vcardproperty_get_parent(const vcardproperty *property)
Returns the parent vcard for the specified property.
Defines the data structure representing vCard properties.
vcardstrarray * vcardstructured_field_at(const vcardstructuredtype *st, size_t position)
Returns the field at the given position in a vcardstructuredtype.
vcardstructuredtype * vcardstructured_new_from_string(const char *str)
Creates a new instance of vcardstructuredtype from a string.
vcardstructuredtype * vcardstructured_clone(const vcardstructuredtype *st)
Clones a vcardstructuredtype.
void vcardstructured_unref(vcardstructuredtype *st)
Decrements the reference count of the vcardstructuredtype.
size_t vcardstructured_num_fields(const vcardstructuredtype *st)
Returns the number of fields in a vcardstructuredtype.
struct vcardstructuredtype_impl vcardstructuredtype
Represents a decoded, structured text value.
Defines functions for creating vCard text lists.
vcardproperty * vcardvalue_get_parent(const vcardvalue *value)
void vcardvalue_set_parent(vcardvalue *value, vcardproperty *property)
void vcardvalue_reset_kind(vcardvalue *value)
char * vcardstructured_as_vcard_string_r(const vcardstructuredtype *st, bool is_param)
Formats a vcardstructuredtype as a vCard property or parameter value.
Defines the data structure representing vCard values.
bool vcardvalue_kind_is_valid(const vcardvalue_kind kind)