tracker-0.16.2/src/libtracker-common/tracker-date-time.c

Location Tool Test ID Function Issue
tracker-date-time.c:316:2 clang-analyzer Function call argument is an uninitialized value
  1 /*
  2  * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
  3  * Copyright (C) 2008-2010, Nokia <ivan.frade@nokia.com>
  4  *
  5  * This library is free software; you can redistribute it and/or
  6  * modify it under the terms of the GNU Lesser General Public
  7  * License as published by the Free Software Foundation; either
  8  * version 2.1 of the License, or (at your option) any later version.
  9  *
 10  * This library is distributed in the hope that it will be useful,
 11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  * Lesser General Public License for more details.
 14  *
 15  * You should have received a copy of the GNU Lesser General Public
 16  * License along with this library; if not, write to the
 17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 18  * Boston, MA  02110-1301, USA.
 19  */
 20 
 21 #include "config.h"
 22 
 23 /* For timegm usage on __GLIBC__ */
 24 #ifndef _GNU_SOURCE
 25 #define _GNU_SOURCE
 26 #endif
 27 
 28 #include <strings.h>
 29 #include <string.h>
 30 #include <math.h>
 31 #include <stdio.h>
 32 #include <stdlib.h>
 33 #include <time.h>
 34 
 35 #include <glib.h>
 36 
 37 #include "tracker-date-time.h"
 38 #include "tracker-type-utils.h"
 39 
 40 GQuark tracker_date_error_quark (void) {
 41 	return g_quark_from_static_string ("tracker_date_error-quark");
 42 }
 43 
 44 gdouble
 45 tracker_string_to_date (const gchar *date_string,
 46                         gint        *offset_p,
 47                         GError      **error)
 48 {
 49 	/* TODO Add more checks and use GError to report invalid input
 50 	 * as this is potential user input.
 51 	 */
 52 
 53 	static GRegex *regex = NULL;
 54 
 55 	GMatchInfo *match_info;
 56 	gchar      *match;
 57 	struct tm tm;
 58 	gdouble t;
 59 	gint offset;
 60 	gboolean timezoned;
 61 
 62 	g_return_val_if_fail (date_string, -1);
 63 
 64 	/* We should have a valid iso 8601 date in format
 65 	 * YYYY-MM-DDThh:mm:ss with optional TZ
 66 	 */
 67 
 68 	if (!regex) {
 69 		GError *e = NULL;
 70 		regex = g_regex_new ("^(-?[0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])T([0-9][0-9]):([0-9][0-9]):([0-9][0-9])(\\.[0-9]+)?(Z|(\\+|-)([0-9][0-9]):?([0-9][0-9]))?$", 0, 0, &e);
 71 		if (e) {
 72 			g_error ("%s", e->message);
 73 		}
 74 	}
 75 
 76 	if (!g_regex_match (regex, date_string, 0, &match_info)) {
 77 		g_match_info_free (match_info);
 78 		g_set_error (error, TRACKER_DATE_ERROR, TRACKER_DATE_ERROR_INVALID_ISO8601,
 79 		             "Not a ISO 8601 date string. Allowed form is [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]");
 80 		return -1;
 81 	}
 82 
 83 	memset (&tm, 0, sizeof (struct tm));
 84 
 85 	/* year */
 86 	match = g_match_info_fetch (match_info, 1);
 87 	tm.tm_year = atoi (match) - 1900;
 88 	g_free (match);
 89 
 90 	/* month */
 91 	match = g_match_info_fetch (match_info, 2);
 92 	tm.tm_mon = atoi (match) - 1;
 93 	g_free (match);
 94 
 95 	/* day of month */
 96 	match = g_match_info_fetch (match_info, 3);
 97 	tm.tm_mday = atoi (match);
 98 	g_free (match);
 99 
100 	/* hour */
101 	match = g_match_info_fetch (match_info, 4);
102 	tm.tm_hour = atoi (match);
103 	g_free (match);
104 
105 	/* minute */
106 	match = g_match_info_fetch (match_info, 5);
107 	tm.tm_min = atoi (match);
108 	g_free (match);
109 
110 	/* second */
111 	match = g_match_info_fetch (match_info, 6);
112 	tm.tm_sec = atoi (match);
113 	g_free (match);
114 
115 	match = g_match_info_fetch (match_info, 8);
116 	timezoned = (match && strlen (match) > 0);
117 	g_free (match);
118 
119 	if (timezoned) {
120 		/* timezoned */
121 
122 		/* mktime() always assumes that "tm" is in locale time but we
123 		 * want to keep control on time, so we go to UTC
124 		 */
125 #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__GLIBC__))
126 		t  = mktime (&tm);
127 		t -= timezone;
128 #else
129 		t = timegm (&tm);
130 #endif
131 
132 		offset = 0;
133 
134 		match = g_match_info_fetch (match_info, 9);
135 		if (match && strlen (match) > 0) {
136 			/* non-UTC timezone */
137 
138 			gboolean positive_offset;
139 
140 			positive_offset = (match[0] == '+');
141 			g_free (match);
142 
143 			match = g_match_info_fetch (match_info, 10);
144 			offset = atoi (match) * 3600;
145 			g_free (match);
146 
147 			match = g_match_info_fetch (match_info, 11);
148 			offset += atoi (match) * 60;
149 			g_free (match);
150 
151 			if (!positive_offset) {
152 				offset = -offset;
153 			}
154 
155 			if (offset < -14 * 3600 || offset > 14 * 3600) {
156 				g_set_error (error, TRACKER_DATE_ERROR, TRACKER_DATE_ERROR_OFFSET,
157 				             "UTC offset too large: %d seconds", offset);
158 				g_match_info_free (match_info);
159 				return -1;
160 			}
161 
162 			t -= offset;
163 		}
164 	} else {
165 		time_t t2;
166 
167 		/* local time */
168 		tm.tm_isdst = -1;
169 
170 		t = mktime (&tm);
171 
172 		/* calculate UTC offset, requires timegm for correct result
173 		   with past times when timezone had different UTC offset */
174 #if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__GLIBC__))
175 		offset = -timezone + (tm.tm_isdst > 0 ? 3600 : 0);
176 #else
177 		t2 = timegm (&tm);
178 		offset = t2 - (time_t) t;
179 #endif
180 	}
181 
182 	match = g_match_info_fetch (match_info, 7);
183 	if (match && strlen (match) > 0) {
184 		char milliseconds[4] = "000\0";
185 		/* first character of match is decimal point
186 		   we're interested in a maximum of 3 decimal places (milliseconds) */
187 		memcpy (milliseconds, match + 1, MIN (3, strlen (match + 1)));
188 		t += (gdouble) atoi (milliseconds) / 1000;
189 	}
190 	g_free (match);
191 
192 	g_match_info_free (match_info);
193 
194 	if (offset_p) {
195 		*offset_p = offset;
196 	}
197 
198 	return t;
199 }
200 
201 gchar *
202 tracker_date_to_string (gdouble date_time)
203 {
204 	gchar     buffer[30];
205 	time_t seconds;
206 	gint64 total_milliseconds;
207 	gint milliseconds;
208 	struct tm utc_time;
209 	size_t    count;
210 
211 	memset (buffer, '\0', sizeof (buffer));
212 	memset (&utc_time, 0, sizeof (struct tm));
213 
214 	total_milliseconds = (gint64) round (date_time * 1000);
215 	milliseconds = total_milliseconds % 1000;
216 	if (milliseconds < 0) {
217 		milliseconds += 1000;
218 	}
219 	seconds = (time_t) ((total_milliseconds - milliseconds) / 1000);
220 	gmtime_r (&seconds, &utc_time);
221 
222 	/* Output is ISO 8601 format : "YYYY-MM-DDThh:mm:ss" */
223 	count = strftime (buffer, sizeof (buffer), "%FT%T", &utc_time);
224 
225 	/* Append milliseconds (if non-zero) and time zone */
226 	if (milliseconds > 0) {
227 		snprintf (buffer + count, sizeof (buffer) - count, ".%03dZ", milliseconds);
228 	} else {
229 		buffer[count] = 'Z';
230 	}
231 
232 	return count > 0 ? g_strdup (buffer) : NULL;
233 }
234 
235 static void
236 date_time_value_init (GValue *value)
237 {
238 	value->data[0].v_double = 0;
239 	value->data[1].v_int = 0;
240 }
241 
242 static void
243 date_time_value_copy (const GValue *src_value,
244                       GValue       *dest_value)
245 {
246 	dest_value->data[0].v_double = src_value->data[0].v_double;
247 	dest_value->data[1].v_int = src_value->data[1].v_int;
248 }
249 
250 GType
251 tracker_date_time_get_type (void)
252 {
253 	static GType tracker_date_time_type_id = 0;
254 	if (G_UNLIKELY (tracker_date_time_type_id == 0)) {
255 		static const GTypeValueTable value_table = {
256 			date_time_value_init,
257 			NULL,
258 			date_time_value_copy
259 		};
260 		static const GTypeInfo type_info = {
261 			0,
262 			NULL,
263 			NULL,
264 			NULL,
265 			NULL,
266 			NULL,
267 			0,
268 			0,
269 			NULL,
270 			&value_table
271 		};
272 		static const GTypeFundamentalInfo fundamental_info = {
273 			0
274 		};
275 		tracker_date_time_type_id = g_type_register_fundamental (
276 			g_type_fundamental_next (),
277 			"TrackerDateTime",
278 			&type_info,
279 			&fundamental_info,
280 			0);
281 	}
282 	return tracker_date_time_type_id;
283 }
284 
285 void
286 tracker_date_time_set (GValue  *value,
287                        gdouble  time,
288                        gint     offset)
289 {
290 	g_return_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME));
291 	g_return_if_fail (offset >= -14 * 3600 && offset <= 14 * 3600);
292 
293 	value->data[0].v_double = time;
294 	value->data[1].v_int = offset;
295 }
296 
297 void
298 tracker_date_time_set_from_string (GValue      *value,
299                                    const gchar *date_time_string,
300                                    GError     **error)
301 {
302 	gdouble time;
303 	gint offset;
304 	GError *new_error = NULL;
305 
306 	g_return_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME));
307 	g_return_if_fail (date_time_string != NULL);
308 
309 	time = tracker_string_to_date (date_time_string, &offset, &new_error);
310 
311 	if (new_error != NULL) {
312 		g_propagate_error (error, new_error);
313 		return;
314 	}
315 
316 	tracker_date_time_set (value, time, offset);
Function call argument is an uninitialized value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

317 } 318 319 gdouble 320 tracker_date_time_get_time (const GValue *value) 321 { 322 g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0); 323 324 /* UTC timestamp */ 325 return value->data[0].v_double; 326 } 327 328 gint 329 tracker_date_time_get_offset (const GValue *value) 330 { 331 g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0); 332 333 /* UTC offset */ 334 return value->data[1].v_int; 335 } 336 337 gint 338 tracker_date_time_get_local_date (const GValue *value) 339 { 340 gdouble local_timestamp; 341 342 g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0); 343 344 /* return number of days since epoch */ 345 local_timestamp = tracker_date_time_get_time (value) + tracker_date_time_get_offset (value); 346 return (gint) (local_timestamp / 3600 / 24); 347 } 348 349 gint 350 tracker_date_time_get_local_time (const GValue *value) 351 { 352 gdouble local_timestamp; 353 354 g_return_val_if_fail (G_VALUE_HOLDS (value, TRACKER_TYPE_DATE_TIME), 0); 355 356 /* return local time of day */ 357 local_timestamp = tracker_date_time_get_time (value) + tracker_date_time_get_offset (value); 358 return (int) local_timestamp % (24 * 3600); 359 }