diff options
Diffstat (limited to 'src/libical/icalvalue.c')
-rw-r--r-- | src/libical/icalvalue.c | 238 |
1 files changed, 150 insertions, 88 deletions
diff --git a/src/libical/icalvalue.c b/src/libical/icalvalue.c index bad30e2..63a0121 100644 --- a/src/libical/icalvalue.c +++ b/src/libical/icalvalue.c @@ -50,9 +50,9 @@ #include <locale.h> #include <ctype.h> /* for isspace and isdigit */ -#ifdef WIN32 -#define snprintf _snprintf -#define strcasecmp stricmp +#if defined(_MSC_VER) +#define snprintf _snprintf +#define strcasecmp stricmp #endif #if _MAC_OS_ @@ -136,18 +136,37 @@ icalvalue* icalvalue_new_clone(const icalvalue* old) { new->data.v_string=icalmemory_strdup(old->data.v_string); if ( new->data.v_string == 0 ) { + icalvalue_free(new); return 0; } } break; } + case ICAL_ACTION_VALUE: + { + new->data = old->data; + + if (old->data.v_enum == ICAL_ACTION_X) { + //preserve the custom action string + if (old->x_value != 0) { + new->x_value = icalmemory_strdup(old->x_value); + + if (new->x_value == 0) { + icalvalue_free(new); + return 0; + } + } + } + break; + } case ICAL_RECUR_VALUE: { if(old->data.v_recur != 0){ new->data.v_recur = malloc(sizeof(struct icalrecurrencetype)); if(new->data.v_recur == 0){ + icalvalue_free(new); return 0; } @@ -163,6 +182,7 @@ icalvalue* icalvalue_new_clone(const icalvalue* old) { new->x_value=icalmemory_strdup(old->x_value); if (new->x_value == 0) { + icalvalue_free(new); return 0; } } @@ -187,6 +207,7 @@ static char* icalmemory_strdup_and_dequote(const char* str) const char* p; char* out = (char*)malloc(sizeof(char) * strlen(str) +1); char* pout; + int wroteNull = 0; if (out == 0){ return 0; @@ -194,7 +215,11 @@ static char* icalmemory_strdup_and_dequote(const char* str) pout = out; - for (p = str; *p!=0; p++){ + /* Stop the loop when encountering a terminator in the source string + or if a null has been written to the destination. This prevents + reading past the end of the source string if the last character + is a backslash. */ + for (p = str; !wroteNull && *p!=0; p++){ if( *p == '\\') { @@ -202,6 +227,7 @@ static char* icalmemory_strdup_and_dequote(const char* str) switch(*p){ case 0: { + wroteNull = 1; //stops iteration so p isn't incremented past the end of str *pout = '\0'; break; @@ -263,6 +289,84 @@ static char* icalmemory_strdup_and_dequote(const char* str) } /* + * Returns a quoted copy of a string + * @todo This is not RFC2445 compliant. + * The RFC only allows: + * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII + * As such, \t\r\b\f are not allowed, not even escaped + */ +static char* icalmemory_strdup_and_quote(const icalvalue* value, + const char* unquoted_str) +{ + char *str; + char *str_p; + const char *p; + size_t buf_sz; + + buf_sz = strlen(unquoted_str)+1; + + str_p = str = (char*)icalmemory_new_buffer(buf_sz); + + if (str_p == 0){ + return 0; + } + + for(p=unquoted_str; *p!=0; p++){ + + switch(*p){ + case '\n': { + icalmemory_append_string(&str,&str_p,&buf_sz,"\\n"); + break; + } + + case '\t': { + icalmemory_append_string(&str,&str_p,&buf_sz,"\\t"); + break; + } + case '\r': { + icalmemory_append_string(&str,&str_p,&buf_sz,"\\r"); + break; + } + case '\b': { + icalmemory_append_string(&str,&str_p,&buf_sz,"\\b"); + break; + } + case '\f': { + icalmemory_append_string(&str,&str_p,&buf_sz,"\\f"); + break; + } + + case ';': + case ',': + /* unescaped COMMA is allowed in CATEGORIES property as its + considered a list delimiter here, see: + http://tools.ietf.org/html/rfc2445#section-4.3.11 */ + if (icalproperty_isa(value->parent) == ICAL_CATEGORIES_PROPERTY) { + icalmemory_append_char(&str,&str_p,&buf_sz,*p); + break; + } + case '"': + case '\\': { + icalmemory_append_char(&str,&str_p,&buf_sz,'\\'); + icalmemory_append_char(&str,&str_p,&buf_sz,*p); + break; + } + + default: { + icalmemory_append_char(&str,&str_p,&buf_sz,*p); + } + } + } + + /* Assume the last character is not a '\0' and add one. We could + check *str_p != 0, but that would be an uninitialized memory + read. */ + + icalmemory_append_char(&str,&str_p,&buf_sz,'\0'); + return str; +} + +/* * FIXME * * This is a bad API, as it forces callers to specify their own X type. @@ -297,14 +401,16 @@ icalvalue* icalvalue_new_enum(icalvalue_kind kind, int x_type, const char* str) * If you want a code that that does the same job with a decimal separator * dependant on the current locale, then use strtof() from libc. */ -int simple_str_to_float(const char* from, - float *result, - char** to) +int simple_str_to_double(const char* from, + double *result, + char** to) { #define TMP_NUM_SIZE 100 char *start=NULL, *end=NULL, *cur=(char*)from ; char tmp_buf[TMP_NUM_SIZE+1] ; /*hack*/ +#ifndef _WIN32_WCE struct lconv *loc_data = localeconv () ; +#endif int i=0 ; /*sanity checks*/ @@ -335,12 +441,13 @@ int simple_str_to_float(const char* from, return 1 ; } memset(tmp_buf, 0, TMP_NUM_SIZE+1) ; - i=0 ; + /* * copy the float number string into tmp_buf, and take * care to have the (optional) decimal separator be the one * of the current locale. */ +#ifndef _WIN32_WCE for (i=0 ; i < end - from ;++i) { if (start[i] == '.' && loc_data @@ -353,6 +460,9 @@ int simple_str_to_float(const char* from, tmp_buf[i] = start[i] ; } } +#else + GetNumberFormat(LOCALE_SYSTEM_DEFAULT,0,start, NULL, tmp_buf,TMP_NUM_SIZE); +#endif if (to) *to = end ; *result = atof(tmp_buf) ; @@ -388,7 +498,7 @@ icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* case ICAL_BINARY_VALUE: { icalattach *attach; - attach = icalattach_new_from_data ((unsigned char*)str, 0, 0); + attach = icalattach_new_from_data (str, 0, 0); if ( !attach ) break; value = icalvalue_new_attach (attach); @@ -495,7 +605,7 @@ icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* char *cur=NULL ; struct icalgeotype geo = {0.0, 0.0}; - if (simple_str_to_float (str, &geo.lat, &cur)) { + if (simple_str_to_double (str, &geo.lat, &cur)) { goto geo_parsing_error ; } @@ -518,7 +628,7 @@ icalvalue* icalvalue_new_from_string_with_error(icalvalue_kind kind,const char* ++cur ; } - if (simple_str_to_float (cur, &geo.lon, &cur)) { + if (simple_str_to_double (cur, &geo.lon, &cur)) { goto geo_parsing_error ; } value = icalvalue_new_geo (geo) ; @@ -706,6 +816,7 @@ icalvalue_free (icalvalue* v) case ICAL_TEXT_VALUE: case ICAL_CALADDRESS_VALUE: case ICAL_URI_VALUE: + case ICAL_STRING_VALUE: case ICAL_QUERY_VALUE: { if (v->data.v_string != 0) { @@ -766,9 +877,10 @@ static char* icalvalue_binary_as_ical_string_r(const icalvalue* value) { static char* icalvalue_int_as_ical_string_r(const icalvalue* value) { int data; - char* str = (char*)icalmemory_new_buffer(MAX_INT_DIGITS); + char* str; icalerror_check_arg_rz( (value!=0),"value"); + str = (char*)icalmemory_new_buffer(MAX_INT_DIGITS); data = icalvalue_get_integer(value); @@ -782,10 +894,11 @@ static char* icalvalue_utcoffset_as_ical_string_r(const icalvalue* value) { int data,h,m,s; char sign; - char* str = (char*)icalmemory_new_buffer(9); + char* str; icalerror_check_arg_rz( (value!=0),"value"); + str = (char*)icalmemory_new_buffer(9); data = icalvalue_get_utcoffset(value); if (abs(data) == data){ @@ -827,81 +940,8 @@ static char* icalvalue_recur_as_ical_string_r(const icalvalue* value) return icalrecurrencetype_as_string_r(recur); } - /* @todo This is not RFC2445 compliant. - * The RFC only allows: - * TSAFE-CHAR = %x20-21 / %x23-2B / %x2D-39 / %x3C-5B / %x5D-7E / NON-US-ASCII - * As such, \t\r\b\f are not allowed, not even escaped - */ - static char* icalvalue_text_as_ical_string_r(const icalvalue* value) { - char *str; - char *str_p; - const char *p; - size_t buf_sz; - - buf_sz = strlen(value->data.v_string)+1; - - str_p = str = (char*)icalmemory_new_buffer(buf_sz); - - if (str_p == 0){ - return 0; - } - - for(p=value->data.v_string; *p!=0; p++){ - - switch(*p){ - case '\n': { - icalmemory_append_string(&str,&str_p,&buf_sz,"\\n"); - break; - } - - case '\t': { - icalmemory_append_string(&str,&str_p,&buf_sz,"\\t"); - break; - } - case '\r': { - icalmemory_append_string(&str,&str_p,&buf_sz,"\\r"); - break; - } - case '\b': { - icalmemory_append_string(&str,&str_p,&buf_sz,"\\b"); - break; - } - case '\f': { - icalmemory_append_string(&str,&str_p,&buf_sz,"\\f"); - break; - } - - case ';': - case ',': - case '"': - case '\\':{ - icalmemory_append_char(&str,&str_p,&buf_sz,'\\'); - icalmemory_append_char(&str,&str_p,&buf_sz,*p); - break; - } - - default: { - icalmemory_append_char(&str,&str_p,&buf_sz,*p); - } - } - } - - /* Assume the last character is not a '\0' and add one. We could - check *str_p != 0, but that would be an uninitialized memory - read. */ - - - icalmemory_append_char(&str,&str_p,&buf_sz,'\0'); - return str; -} - - -static char* icalvalue_text_as_ical_string(const icalvalue* value) { - char *buf; - buf = icalvalue_text_as_ical_string_r(value); - icalmemory_add_tmp_buffer(buf); - return buf; + return icalmemory_strdup_and_quote(value, value->data.v_string); } @@ -1035,13 +1075,24 @@ static char* icalvalue_float_as_ical_string_r(const icalvalue* value) { float data; char* str; + char* old_locale; icalerror_check_arg_rz( (value!=0),"value"); data = icalvalue_get_float(value); + /* bypass current locale in order to make + sure snprintf uses a '.' as a separator + set locate to 'C' and keep old locale */ + old_locale = strdup (setlocale (LC_NUMERIC,NULL)); + setlocale (LC_NUMERIC,"C"); + str = (char*)icalmemory_new_buffer(40); snprintf(str,40,"%f",data); + /* restore saved locale */ + setlocale (LC_NUMERIC,old_locale); + free (old_locale); + return str; } @@ -1050,14 +1101,25 @@ static char* icalvalue_geo_as_ical_string_r(const icalvalue* value) { struct icalgeotype data; char* str; + char* old_locale; icalerror_check_arg_rz( (value!=0),"value"); data = icalvalue_get_geo(value); + /* bypass current locale in order to make + * sure snprintf uses a '.' as a separator + * set locate to 'C' and keep old locale */ + old_locale = strdup (setlocale (LC_NUMERIC,NULL)); + setlocale (LC_NUMERIC,"C"); + str = (char*)icalmemory_new_buffer(80); snprintf(str,80,"%f;%f",data.lat,data.lon); + /* restore saved locale */ + setlocale (LC_NUMERIC,old_locale); + free (old_locale); + return str; } @@ -1186,7 +1248,7 @@ icalvalue_as_ical_string_r(const icalvalue* value) case ICAL_X_VALUE: if (value->x_value != 0) - return icalmemory_strdup(value->x_value); + return icalmemory_strdup_and_quote(value,value->x_value); /* FALLTHRU */ |