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;
45 v->id = ICAL_STRUCTURE_TYPE_VALUE;
50 memset(&(v->data), 0,
sizeof(v->data));
55vcardvalue *vcardvalue_new(vcardvalue_kind kind)
57 return (vcardvalue *)vcardvalue_new_impl(kind);
60vcardvalue *vcardvalue_clone(
const vcardvalue *old)
62 struct vcardvalue_impl *clone;
64 clone = vcardvalue_new_impl(old->kind);
71 clone->kind = old->kind;
72 clone->size = old->size;
74 switch (clone->kind) {
75 case VCARD_TEXT_VALUE:
77 case VCARD_LANGUAGETAG_VALUE: {
78 if (old->data.v_string != 0) {
81 if (clone->data.v_string == 0) {
83 vcardvalue_free(clone);
90 if (old->x_value != 0) {
93 if (clone->x_value == 0) {
95 vcardvalue_free(clone);
103 case VCARD_STRUCTURED_VALUE:
104 if (old->data.v_structured != 0) {
105 clone->data.v_structured =
114 clone->data = old->data;
121char *vcardvalue_strdup_and_dequote_text(
const char **str,
const char *sep)
137 for (p = *str; *p != 0; p++) {
182 }
else if (sep && strchr(sep, *p)) {
208static char *vcardmemory_strdup_and_quote(
char **str,
char **str_p,
size_t *buf_sz,
209 const char *unquoted_str,
bool is_param)
214 *buf_sz = strlen(unquoted_str) + 1;
224 for (p = unquoted_str; *p != 0; p++) {
266static vcardvalue *vcardvalue_new_enum(vcardvalue_kind kind,
int x_type,
const char *str)
268 int e = vcardproperty_kind_and_string_to_enum((
int)kind, str);
269 struct vcardvalue_impl *value;
271 if (e != 0 && vcardproperty_enum_belongs_to_property(vcardproperty_value_kind_to_kind(kind), e)) {
272 value = vcardvalue_new_impl(kind);
273 value->data.v_enum = e;
276 value = vcardvalue_new_impl(kind);
277 value->data.v_enum = x_type;
278 vcardvalue_set_x(value, str);
290static bool simple_str_to_doublestr(
const char *from,
char *result,
int result_len,
char **to)
292 const char *start = NULL;
293 char *end = NULL, *cur = (
char *)from;
295 struct lconv *loc_data = localeconv();
300 if (!from || !result) {
305 while (*cur && isspace((
int)*cur)) {
314 while (*cur && (isdigit((
int)*cur) || *cur ==
'.' || *cur ==
'+' || *cur ==
'-')) {
318 len = (int)(ptrdiff_t)(end - start);
319 if (len + 1 >= result_len) {
321 len = result_len - 1;
328 for (i = 0; i < len; ++i) {
329 if (start[i] ==
'.' &&
330 loc_data && loc_data->decimal_point && loc_data->decimal_point[0] && loc_data->decimal_point[0] !=
'.') {
332 result[i] = loc_data->decimal_point[0];
334 result[i] = start[i];
342 if (sscanf(result,
"%lf", &dtest) != 1) {
348static vcardvalue *vcardvalue_new_from_string_with_error(vcardvalue_kind kind,
350 vcardproperty **error)
352 struct vcardvalue_impl *value = 0;
354 icalerror_check_arg_rz(str != 0,
"str");
361 case VCARD_BOOLEAN_VALUE: {
362 if (!strcmp(str,
"TRUE")) {
363 value = vcardvalue_new_boolean(1);
364 }
else if (!strcmp(str,
"FALSE")) {
365 value = vcardvalue_new_boolean(0);
366 }
else if (error != 0) {
367 char temp[TMP_BUF_SIZE];
368 vcardparameter *errParam;
370 snprintf(temp,
sizeof(temp),
371 "Could not parse %s as a %s property",
372 str, vcardvalue_kind_to_string(kind));
373 errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
374 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
379 case VCARD_VERSION_VALUE:
380 value = vcardvalue_new_enum(kind, (
int)VCARD_VERSION_X, str);
383 case VCARD_KIND_VALUE:
384 value = vcardvalue_new_enum(kind, (
int)VCARD_KIND_X, str);
387 case VCARD_GRAMGENDER_VALUE:
388 value = vcardvalue_new_enum(kind, (
int)VCARD_GRAMGENDER_X, str);
391 case VCARD_INTEGER_VALUE:
392 value = vcardvalue_new_integer(atoi(str));
395 case VCARD_FLOAT_VALUE:
396 value = vcardvalue_new_float((
float)atof(str));
399 case VCARD_UTCOFFSET_VALUE: {
400#pragma GCC diagnostic push
401#pragma GCC diagnostic ignored "-Wformat-nonliteral"
404 unsigned hour, min = 0;
405 int nchar = 0, len = (int)strlen(str);
411 fmt =
"%1[+-]%02u:%02u%n";
413 fmt =
"%1[+-]%02u%02u%n";
416 if (3 != sscanf(str, fmt, sign, &hour, &min, &nchar)) {
419 }
else if (2 != sscanf(str,
"%1[+-]%02u%n", sign, &hour, &nchar)) {
422#pragma GCC diagnostic pop
424 if (len && (len == nchar)) {
425 int utcoffset = (int)(hour * 3600 + min * 60);
428 utcoffset = -utcoffset;
430 value = vcardvalue_new_utcoffset(utcoffset);
431 }
else if (error != 0) {
432 char temp[TMP_BUF_SIZE];
433 vcardparameter *errParam;
435 snprintf(temp,
sizeof(temp),
436 "Could not parse %s as a %s property",
437 str, vcardvalue_kind_to_string(kind));
438 errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
439 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
444 case VCARD_TEXT_VALUE: {
445 char *dequoted_str = vcardvalue_strdup_and_dequote_text(&str, NULL);
447 value = vcardvalue_new_text(dequoted_str);
452 case VCARD_TEXTLIST_VALUE: {
453 value = vcardvalue_new_textlist(vcardtextlist_new_from_string(str,
','));
457 case VCARD_STRUCTURED_VALUE: {
459 value = vcardvalue_new_structured(st);
464 case VCARD_GEO_VALUE: {
467 memset(geo.coords.lat, 0, VCARD_GEO_LEN);
468 memset(geo.coords.lon, 0, VCARD_GEO_LEN);
470 if (simple_str_to_doublestr(str, geo.coords.lat, VCARD_GEO_LEN, &cur)) {
471 goto geo_parsing_error;
474 while (cur && isspace((
int)*cur)) {
479 if (!cur || *cur !=
';') {
480 goto geo_parsing_error;
486 while (cur && isspace((
int)*cur)) {
490 if (simple_str_to_doublestr(cur, geo.coords.lon, VCARD_GEO_LEN, &cur)) {
491 goto geo_parsing_error;
493 value = vcardvalue_new_geo(geo);
498 char temp[TMP_BUF_SIZE];
499 snprintf(temp,
sizeof(temp),
500 "Could not parse %s as a %s value",
501 str, vcardvalue_kind_to_string(kind));
502 vcardparameter *errParam =
503 vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
504 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
508 case VCARD_URI_VALUE:
509 value = vcardvalue_new_uri(str);
512 case VCARD_DATE_VALUE:
513 case VCARD_TIME_VALUE:
514 case VCARD_DATETIME_VALUE:
515 case VCARD_DATEANDORTIME_VALUE:
516 case VCARD_TIMESTAMP_VALUE: {
519 tt = vcardtime_from_string(str, kind == VCARD_TIME_VALUE);
520 if (!vcardtime_is_null_datetime(tt)) {
521 value = vcardvalue_new_impl(kind);
522 value->data.v_time = tt;
529 case VCARD_LANGUAGETAG_VALUE:
530 value = vcardvalue_new_languagetag(str);
533 case VCARD_X_VALUE: {
534 value = vcardvalue_new_x(str);
538 char temp[TMP_BUF_SIZE];
540 snprintf(temp, TMP_BUF_SIZE,
"Unknown type for \'%s\'", str);
541 vcardparameter *errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
542 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
545 snprintf(temp, TMP_BUF_SIZE,
546 "vcardvalue_new_from_string got an unknown value type (%s) for \'%s\'",
547 vcardvalue_kind_to_string(kind), str);
548 icalerror_warn(temp);
553 if (error != 0 && *error == 0 && value == 0) {
554 char temp[TMP_BUF_SIZE];
555 vcardparameter *errParam;
557 snprintf(temp, TMP_BUF_SIZE,
"Failed to parse value: \'%s\'", str);
560 errParam = vcardparameter_new_xlicerrortype(VCARD_XLICERRORTYPE_VALUEPARSEERROR);
561 *error = vcardproperty_vanew_xlicerror(temp, errParam, (
void *)0);
567vcardvalue *vcardvalue_new_from_string(vcardvalue_kind kind,
const char *str)
569 return vcardvalue_new_from_string_with_error(kind, str, (vcardproperty **)0);
572void vcardvalue_free(vcardvalue *v)
574 icalerror_check_arg_rv((v != 0),
"value");
576 if (v->parent != 0) {
580 if (v->x_value != 0) {
585 case VCARD_TEXT_VALUE:
586 case VCARD_URI_VALUE:
587 case VCARD_LANGUAGETAG_VALUE: {
588 if (v->data.v_string != 0) {
590 v->data.v_string = 0;
595 case VCARD_TEXTLIST_VALUE: {
596 if (v->data.v_textlist != 0) {
597 vcardstrarray_free(v->data.v_textlist);
599 v->data.v_textlist = 0;
603 case VCARD_STRUCTURED_VALUE: {
605 v->data.v_structured = 0;
609 case VCARD_GEO_VALUE: {
610 v->data.v_geo.coords.lat[0] =
'\0';
611 v->data.v_geo.coords.lon[0] =
'\0';
620 v->kind = VCARD_NO_VALUE;
623 memset(&(v->data), 0,
sizeof(v->data));
624 v->id = ICAL_STRUCTURE_TYPE_VALUE_EMPTY;
628bool vcardvalue_is_valid(
const vcardvalue *value)
637static char *vcardvalue_boolean_as_vcard_string_r(
const vcardvalue *value)
642 icalerror_check_arg_rz((value != 0),
"value");
645 data = vcardvalue_get_integer(value);
647 strncpy(str, data ?
"TRUE" :
"FALSE", 6);
652#define MAX_INT_DIGITS 12
654static char *vcardvalue_int_as_vcard_string_r(
const vcardvalue *value)
659 icalerror_check_arg_rz((value != 0),
"value");
662 data = vcardvalue_get_integer(value);
664 snprintf(str, MAX_INT_DIGITS,
"%d", data);
669static char *vcardvalue_utcoffset_as_vcard_string_r(
const vcardvalue *value,
670 vcardproperty_version version)
678 icalerror_check_arg_rz((value != 0),
"value");
681 data = vcardvalue_get_utcoffset(value);
683 if (abs(data) == data) {
690 m = (data - (h * 3600)) / 60;
691 s = (data - (h * 3600) - (m * 60));
696#pragma GCC diagnostic push
697#pragma GCC diagnostic ignored "-Wformat-nonliteral"
699 if (version == VCARD_VERSION_40) {
700 fmt =
"%c%02d%02d%02d";
702 fmt =
"%c%02d:%02d:%02d";
704 }
else if (version == VCARD_VERSION_40) {
714 snprintf(str, size, fmt, sign, h, m, s);
715#pragma GCC diagnostic pop
719static char *vcardvalue_text_as_vcard_string_r(
const vcardvalue *value)
725 return vcardmemory_strdup_and_quote(&str, &str_p, &buf_sz,
726 value->data.v_string, 0);
729static char *vcardvalue_string_as_vcard_string_r(
const vcardvalue *value)
734 icalerror_check_arg_rz((value != 0),
"value");
735 data = value->data.v_string;
737 const size_t len_data = strlen(data) + 1;
740 strncpy(str, data, len_data);
741 str[len_data - 1] =
'\0';
746static void _vcardstrarray_as_vcard_string_r(
char **str,
char **str_p,
size_t *buf_sz,
747 vcardstrarray *array,
const char sep,
750 if (!vcardstrarray_size(array)) {
751 (void)vcardmemory_strdup_and_quote(str, str_p, buf_sz,
"", is_param);
757 for (i = 0; i < vcardstrarray_size(array); i++) {
763 (void)vcardmemory_strdup_and_quote(str, str_p, buf_sz,
764 vcardstrarray_element_at(array, i), is_param);
768char *vcardstrarray_as_vcard_string_r(
const vcardstrarray *array,
const char sep)
771 char *buf_ptr = NULL;
774 _vcardstrarray_as_vcard_string_r(&buf, &buf_ptr, &buf_size,
775 (vcardstrarray *)array, sep, 0);
800 _vcardstrarray_as_vcard_string_r(&buf, &buf_ptr, &buf_size,
801 array,
',', is_param);
810static char *vcardvalue_textlist_as_vcard_string_r(
const vcardvalue *value,
813 icalerror_check_arg_rz((value != 0),
"value");
815 return vcardstrarray_as_vcard_string_r(value->data.v_textlist, sep);
818static char *vcardvalue_structured_as_vcard_string_r(
const vcardvalue *value)
820 icalerror_check_arg_rz((value != 0),
"value");
825static char *vcardvalue_float_as_vcard_string_r(
const vcardvalue *value)
831 icalerror_check_arg_rz((value != 0),
"value");
832 data = vcardvalue_get_float(value);
838 (void)setlocale(LC_NUMERIC,
"C");
842 snprintf(str, 40,
"%f", data);
845 (void)setlocale(LC_NUMERIC, old_locale);
851static char *vcardvalue_geo_as_vcard_string_r(
const vcardvalue *value)
853 icalerror_check_arg_rz((value != 0),
"value");
854 size_t max_len = 2 * VCARD_GEO_LEN;
856 snprintf(str, max_len,
"%s;%s",
857 value->data.v_geo.coords.lat, value->data.v_geo.coords.lon);
858 str[max_len - 1] =
'\0';
862const char *vcardvalue_as_vcard_string(
const vcardvalue *value)
866 buf = vcardvalue_as_vcard_string_r(value);
871char *vcardvalue_as_vcard_string_r(
const vcardvalue *value)
873 vcardproperty_version version = VCARD_VERSION_NONE;
884 version = vcardcomponent_get_version(comp);
888 if (version == VCARD_VERSION_NONE) {
889 version = VCARD_VERSION_30;
892 is_structured = vcardproperty_is_structured(vcardproperty_isa(value->parent));
894 switch (value->kind) {
895 case VCARD_BOOLEAN_VALUE:
896 return vcardvalue_boolean_as_vcard_string_r(value);
898 case VCARD_INTEGER_VALUE:
899 return vcardvalue_int_as_vcard_string_r(value);
901 case VCARD_UTCOFFSET_VALUE:
902 return vcardvalue_utcoffset_as_vcard_string_r(value, version);
904 case VCARD_TEXT_VALUE:
905 return vcardvalue_text_as_vcard_string_r(value);
907 case VCARD_TEXTLIST_VALUE:
908 return vcardvalue_textlist_as_vcard_string_r(value,
909 is_structured ?
';' :
',');
911 case VCARD_STRUCTURED_VALUE:
912 return vcardvalue_structured_as_vcard_string_r(value);
914 case VCARD_GEO_VALUE:
915 return vcardvalue_geo_as_vcard_string_r(value);
917 case VCARD_URI_VALUE:
918 case VCARD_LANGUAGETAG_VALUE:
919 return vcardvalue_string_as_vcard_string_r(value);
921 case VCARD_TIME_VALUE:
922 flags |= VCARDTIME_BARE_TIME;
925 case VCARD_DATE_VALUE:
928 case VCARD_DATETIME_VALUE:
931 case VCARD_DATEANDORTIME_VALUE:
934 case VCARD_TIMESTAMP_VALUE:
935 if (version == VCARD_VERSION_40) {
936 flags |= VCARDTIME_AS_V4;
939 return vcardtime_as_vcard_string_r(value->data.v_time, flags);
941 case VCARD_FLOAT_VALUE:
942 return vcardvalue_float_as_vcard_string_r(value);
944 case VCARD_KIND_VALUE:
945 case VCARD_VERSION_VALUE:
946 case VCARD_GRAMGENDER_VALUE:
947 if (value->x_value != 0) {
951 return vcardproperty_enum_to_string_r(value->data.v_enum);
954 if (value->x_value != 0) {
968vcardvalue_kind vcardvalue_isa(
const vcardvalue *value)
971 return VCARD_NO_VALUE;
977bool vcardvalue_isa_value(
void *value)
979 const struct vcardvalue_impl *impl = (
struct vcardvalue_impl *)value;
981 icalerror_check_arg_rz((value != 0),
"value");
983 return (impl->id == ICAL_STRUCTURE_TYPE_VALUE);
995 switch (value->kind) {
996 case VCARD_DATE_VALUE:
997 case VCARD_TIME_VALUE:
998 case VCARD_DATETIME_VALUE:
999 case VCARD_DATEANDORTIME_VALUE:
1000 case VCARD_TIMESTAMP_VALUE:
1001 if (vcardtime_is_timestamp(value->data.v_time)) {
1002 value->kind = VCARD_TIMESTAMP_VALUE;
1003 }
else if (vcardtime_is_time(value->data.v_time)) {
1004 value->kind = VCARD_TIME_VALUE;
1005 }
else if (vcardtime_is_date(value->data.v_time)) {
1006 value->kind = VCARD_DATE_VALUE;
1008 value->kind = VCARD_DATETIME_VALUE;
1019 icalerror_check_arg_rv((value != 0),
"value");
1021 value->parent = property;
1026 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)