File libical-read-v2-v3-data.patch of Package libical.17519

From c7e767bfe1d218aaf845686f9811195cecc7be2a Mon Sep 17 00:00:00 2001
From: Ken Murchison <murch@fastmail.com>
Date: Wed, 11 Nov 2020 08:50:54 -0500
Subject: [PATCH] icaltzutil_fetch_timezone() should read v2/v3 data when
 available

Rebased by Mike Gorse <mgorse@suse.com>
---
diff -urp libical-1.0.1.orig/src/libical/icaltz-util.c libical-1.0.1/src/libical/icaltz-util.c
--- libical-1.0.1.orig/src/libical/icaltz-util.c	2014-10-09 10:07:05.000000000 -0500
+++ libical-1.0.1/src/libical/icaltz-util.c	2020-11-30 17:23:00.060895834 -0600
@@ -99,6 +99,9 @@
 
 typedef struct 
 {
+	char magic[4];
+	char version;
+	char unused[15];
 	char	ttisgmtcnt [4];	
 	char	ttisstdcnt[4];	
 	char	leapcnt[4];		
@@ -166,6 +169,24 @@ decode (const void *ptr)
 	}
 }
 
+static long long int
+decode64(const void *ptr)
+{
+#if defined(sun) && defined(__SVR4)
+#if defined(_BIG_ENDIAN)
+	return *(const long long int *)ptr;
+#else
+	return BSWAP_64(*(const long long int *)ptr);
+#endif
+#else
+	if ((BYTE_ORDER == BIG_ENDIAN)) {
+	return *(const long long int *)ptr;
+	} else {
+		return (int)bswap_64(*(const long long int *)ptr);
+	}
+#endif
+}
+
 static char *
 zname_from_stridx (char *str, long int idx) 
 {
@@ -217,7 +238,7 @@ icaltzutil_fetch_timezone (const char *l
 {
 	int ret = 0;
 	FILE *f;
-	tzinfo type_cnts;
+	tzinfo header;
 	unsigned int i, num_trans, num_types = 0, num_chars, num_leaps, num_isstd, num_isgmt;
 	time_t *transitions = NULL;
 	time_t start, end;
@@ -229,6 +250,7 @@ icaltzutil_fetch_timezone (const char *l
 	icalproperty *icalprop;
 	icaltimetype dtstart;
 	const char *basedir;
+	int trans_size = 4;
 
 	if(icaltimezone_get_builtin_tzdata()) {
 		return NULL;
@@ -248,31 +270,85 @@ icaltzutil_fetch_timezone (const char *l
 		return NULL;
 	}
 
-	if ((ret = fseek (f, 20, SEEK_SET)) != 0) {
-		icalerror_set_errno (ICAL_FILE_ERROR);
+	/* read version 1 header */
+	EFREAD(&header, 44, 1, f);
+	if (memcmp(header.magic, "TZif", 4)) {
+		icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+		goto error;
+	}
+	switch (header.version) {
+	case 0:
+		break;
+	case '2':
+	case '3':
+		if (sizeof(time_t) == 8)
+			trans_size = 8;
+		break;
+	default:
+		icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
 		goto error;	
 	}
 
-	EFREAD(&type_cnts, 24, 1, f);
+	num_isgmt = (size_t)decode(header.ttisgmtcnt);
+	num_leaps = (size_t)decode(header.leapcnt);
+	num_chars = (size_t)decode(header.charcnt);
+	num_trans = (size_t)decode(header.timecnt);
+	num_isstd = (size_t)decode(header.ttisstdcnt);
+	num_types = (size_t)decode(header.typecnt);
+
+	if (trans_size == 8) {
+		long skip = num_trans * 5 + num_types * 6 +
+			num_chars + num_leaps * 8 + num_isstd + num_isgmt;
+			
+		/* skip version 1 data block */
+		if (fseek(f, skip, SEEK_CUR) != 0) {
+			icalerror_set_errno(ICAL_FILE_ERROR);
+			goto error;
+		}
 
-	num_isgmt = decode (type_cnts.ttisgmtcnt);
-	num_leaps = decode (type_cnts.leapcnt);
-	num_chars = decode (type_cnts.charcnt);
-	num_trans = decode (type_cnts.timecnt);
-	num_isstd = decode (type_cnts.ttisstdcnt);
-	num_types = decode (type_cnts.typecnt);
-
-	transitions = calloc (num_trans, sizeof (time_t));
-	r_trans = calloc (num_trans, 4);
-	EFREAD(r_trans, 4, num_trans, f);
+		/* read version 2+ header */
+		EFREAD(&header, 44, 1, f);
+		if (memcmp(header.magic, "TZif", 4)) {
+			icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
+			goto error;
+		}
+ 
+		num_isgmt = (size_t)decode(header.ttisgmtcnt);
+		num_leaps = (size_t)decode(header.leapcnt);
+		num_chars = (size_t)decode(header.charcnt);
+		num_trans = (size_t)decode(header.timecnt);
+		num_isstd = (size_t)decode(header.ttisstdcnt);
+		num_types = (size_t)decode(header.typecnt);
+	 }
+
+	/* read data block */
+	if (num_trans > 0) {
+		transitions = calloc(num_trans, sizeof(time_t));
+		if (transitions == NULL) {
+			icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+			goto error;
+		}
+		r_trans = calloc(num_trans, trans_size);
+		if (r_trans == NULL) {
+			icalerror_set_errno(ICAL_NEWFAILED_ERROR);
+			goto error;
+		}
+	} else {
+		icalerror_set_errno(ICAL_FILE_ERROR);
+		 goto error;
+	 }
+	EFREAD(r_trans, trans_size, num_trans, f);
 	temp = r_trans;	
 
 	if (num_trans) {
 		trans_idx = calloc (num_trans, sizeof (int));
 		for (i = 0; i < num_trans; i++) {
 			trans_idx [i] = fgetc (f);
-			transitions [i] = decode (r_trans);
-			r_trans += 4;
+			if (trans_size == 8)
+				transitions[i] = (time_t) decode64(r_trans);
+			else
+				transitions[i] = (time_t) decode(r_trans);
+			r_trans += trans_size;
 		}
 	}
 	
@@ -301,10 +377,13 @@ icaltzutil_fetch_timezone (const char *l
 
 	leaps = calloc (num_leaps, sizeof (leap));
 	for (i = 0; i < num_leaps; i++) {
-		char c [4];
+		char c [8];
 
-		EFREAD (c, 4, 1, f);
-		leaps [i].transition = decode (c);
+		EFREAD (c, trans_size, 1, f);
+		if (trans_size == 8)
+			leaps[i].transition = (time_t)decode64(c);
+		else
+			leaps[i].transition = (time_t)decode(c);
 
 		EFREAD (c, 4, 1, f);
 		leaps [i].change = decode (c);
@@ -326,6 +405,10 @@ icaltzutil_fetch_timezone (const char *l
 	while (i < num_types)
 		types [i++].isgmt = 0;
 
+	if (trans_size == 8) {
+		/* XXX	Do we need/want to read and use the footer? */
+	}
+
 	/* Read all the contents now */
 
 	for (i = 0; i < num_types; i++)
openSUSE Build Service is sponsored by