1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /*
4  *  GThumb
5  *
6  *  Copyright (C) 2001-2019 Free Software Foundation, Inc.
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <glib/gprintf.h>
30 #include <gio/gio.h>
31 #include "glib-utils.h"
32 #include "uri-utils.h"
33 
34 #define MAX_PATTERNS 128
35 #define BUFFER_SIZE_FOR_SNIFFING 32
36 
37 
38 /* gobject utils*/
39 
40 
41 gpointer
_g_object_ref(gpointer object)42 _g_object_ref (gpointer object)
43 {
44 	if (object != NULL)
45 		return g_object_ref (object);
46 	else
47 		return NULL;
48 }
49 
50 
51 void
_g_object_unref(gpointer object)52 _g_object_unref (gpointer object)
53 {
54 	if (object != NULL)
55 		g_object_unref (object);
56 }
57 
58 
59 void
_g_clear_object(gpointer p)60 _g_clear_object (gpointer p)
61 {
62 	gpointer *object_p = (gpointer *) p;
63 
64 	if ((object_p != NULL) && (*object_p != NULL)) {
65 		g_object_unref (*object_p);
66 		*object_p = NULL;
67 	}
68 }
69 
70 
71 GList *
_g_object_list_ref(GList * list)72 _g_object_list_ref (GList *list)
73 {
74 	GList *new_list;
75 
76 	if (list == NULL)
77 		return NULL;
78 
79 	new_list = g_list_copy (list);
80 	g_list_foreach (new_list, (GFunc) g_object_ref, NULL);
81 
82 	return new_list;
83 }
84 
85 
86 void
_g_object_list_unref(GList * list)87 _g_object_list_unref (GList *list)
88 {
89 	g_list_foreach (list, (GFunc) _g_object_unref, NULL);
90 	g_list_free (list);
91 }
92 
93 
94 typedef GList GObjectList;
95 
96 
97 G_DEFINE_BOXED_TYPE (GObjectList,
98 		     g_object_list,
99 		     (GBoxedCopyFunc) _g_object_list_ref,
100 		     (GBoxedFreeFunc) _g_object_list_unref)
101 
102 
103 GEnumValue *
_g_enum_type_get_value(GType enum_type,int value)104 _g_enum_type_get_value (GType enum_type,
105 			int   value)
106 {
107 	GEnumClass *class;
108 	GEnumValue *enum_value;
109 
110 	class = G_ENUM_CLASS (g_type_class_ref (enum_type));
111 	enum_value = g_enum_get_value (class, value);
112 	g_type_class_unref (class);
113 
114 	return enum_value;
115 }
116 
117 
118 GEnumValue *
_g_enum_type_get_value_by_nick(GType enum_type,const char * nick)119 _g_enum_type_get_value_by_nick (GType       enum_type,
120 				const char *nick)
121 {
122 	GEnumClass *class;
123 	GEnumValue *enum_value;
124 
125 	class = G_ENUM_CLASS (g_type_class_ref (enum_type));
126 	enum_value = g_enum_get_value_by_nick (class, nick);
127 	g_type_class_unref (class);
128 
129 	return enum_value;
130 }
131 
132 
133 /* idle callback */
134 
135 
136 IdleCall*
idle_call_new(DataFunc func,gpointer data)137 idle_call_new (DataFunc func,
138 	       gpointer data)
139 {
140 	IdleCall *call = g_new0 (IdleCall, 1);
141 	call->func = func;
142 	call->data = data;
143 	return call;
144 }
145 
146 
147 void
idle_call_free(IdleCall * call)148 idle_call_free (IdleCall *call)
149 {
150 	g_free (call);
151 }
152 
153 
154 static gboolean
idle_call_exec_cb(gpointer data)155 idle_call_exec_cb (gpointer data)
156 {
157 	IdleCall *call = data;
158 	(*call->func) (call->data);
159 	return FALSE;
160 }
161 
162 
163 guint
idle_call_exec(IdleCall * call,gboolean use_idle_cb)164 idle_call_exec (IdleCall *call,
165 		gboolean  use_idle_cb)
166 {
167 	if (use_idle_cb)
168 		return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
169 					idle_call_exec_cb,
170 					call,
171 					(GDestroyNotify) idle_call_free);
172 	else {
173 		(*call->func) (call->data);
174 		idle_call_free (call);
175 		return 0;
176 	}
177 }
178 
179 
180 guint
call_when_idle(DataFunc func,gpointer data)181 call_when_idle (DataFunc  func,
182 		gpointer  data)
183 {
184 	return idle_call_exec (idle_call_new (func, data), TRUE);
185 }
186 
187 
188 typedef struct {
189 	gpointer       object;
190 	ReadyCallback  ready_func;
191 	gpointer       user_data;
192 	GError        *error;
193 	guint          id;
194 } ObjectReadyData;
195 
196 
197 static gboolean
exec_object_ready_func(gpointer user_data)198 exec_object_ready_func (gpointer user_data)
199 {
200 	ObjectReadyData *data = user_data;
201 
202 	g_source_remove (data->id);
203 	data->ready_func (data->object, data->error, data->user_data);
204 	_g_object_unref (data->object);
205 	g_free (data);
206 
207 	return FALSE;
208 }
209 
210 
211 void
object_ready_with_error(gpointer object,ReadyCallback ready_func,gpointer user_data,GError * error)212 object_ready_with_error (gpointer       object,
213 			 ReadyCallback  ready_func,
214 			 gpointer       user_data,
215 			 GError        *error)
216 {
217 	ObjectReadyData *data;
218 
219 	data = g_new0 (ObjectReadyData, 1);
220 
221 	data->object = _g_object_ref (object);
222 	data->ready_func = ready_func;
223 	data->user_data = user_data;
224 	data->error = error;
225 	data->id = g_idle_add (exec_object_ready_func, data);
226 }
227 
228 
229 typedef struct {
230 	ReadyFunc  ready_func;
231 	gpointer   user_data;
232 	GError    *error;
233 	guint      id;
234 } ReadyData;
235 
236 
237 static gboolean
exec_ready_func(gpointer user_data)238 exec_ready_func (gpointer user_data)
239 {
240 	ReadyData *data = user_data;
241 
242 	g_source_remove (data->id);
243 	data->ready_func (data->error, data->user_data);
244 	g_free (data);
245 
246 	return FALSE;
247 }
248 
249 
250 void
ready_with_error(ReadyFunc ready_func,gpointer user_data,GError * error)251 ready_with_error (ReadyFunc  ready_func,
252 		  gpointer   user_data,
253 		  GError    *error)
254 {
255 	ReadyData *data;
256 
257 	data = g_new0 (ReadyData, 1);
258 	data->ready_func = ready_func;
259 	data->user_data = user_data;
260 	data->error = error;
261 	data->id = g_idle_add (exec_ready_func, data);
262 }
263 
264 
265 /* debug */
266 
267 
268 void
debug(const char * file,int line,const char * function,const char * format,...)269 debug (const char *file,
270        int         line,
271        const char *function,
272        const char *format,
273        ...)
274 {
275 #ifdef DEBUG
276 	static   gboolean first_time = 0;
277 	static   gboolean print_debug_info = 0;
278 	va_list  args;
279 	char    *str;
280 
281 	if (! first_time) {
282 		first_time = 1;
283 		if (g_getenv ("GTHUMB_DEBUG"))
284 			print_debug_info = 1;
285 	}
286 
287 	if (! print_debug_info)
288 		return;
289 
290 	g_return_if_fail (format != NULL);
291 
292 	va_start (args, format);
293 	str = g_strdup_vprintf (format, args);
294 	va_end (args);
295 
296 	g_fprintf (stderr, "[%s] %s:%d (%s):\n\t%s\n", g_get_prgname(), file, line, function, str);
297 
298 	g_free (str);
299 #endif
300 }
301 
302 
303 void
performance(const char * file,int line,const char * function,const char * format,...)304 performance (const char *file,
305 	     int         line,
306 	     const char *function,
307 	     const char *format,
308 	     ...)
309 {
310 #ifdef DEBUG
311 	va_list args;
312 	char *formatted, *str, *filename;
313 
314 	filename = g_path_get_basename (file);
315 
316 	va_start (args, format);
317 	formatted = g_strdup_vprintf (format, args);
318 	va_end (args);
319 
320 	str = g_strdup_printf ("MARK: %s: (%s:%d) [%s] : %s", g_get_prgname(), filename, line, function, formatted);
321 	g_free (formatted);
322 
323 	access (str, F_OK);
324 	g_free (str);
325 	g_free (filename);
326 #endif
327 }
328 
329 
330 /* GTimeVal utils */
331 
332 
333 /* taken from the glib function g_date_strftime */
334 char *
_g_struct_tm_strftime(struct tm * tm,const char * format)335 _g_struct_tm_strftime (struct tm   *tm,
336 		       const char  *format)
337 {
338 	gsize   locale_format_len = 0;
339 	char   *locale_format;
340 	GError *error = NULL;
341 	gsize   tmpbufsize;
342 	char   *tmpbuf;
343 	gsize   tmplen;
344 	char   *retval;
345 
346 	locale_format = g_locale_from_utf8 (format, -1, NULL, &locale_format_len, &error);
347 	if (error != NULL) {
348 		g_warning (G_STRLOC "Error converting format to locale encoding: %s\n", error->message);
349 		g_error_free (error);
350 		return NULL;
351 	}
352 
353 	tmpbufsize = MAX (128, locale_format_len * 2);
354 	while (TRUE) {
355 		tmpbuf = g_malloc (tmpbufsize);
356 
357 		/* Set the first byte to something other than '\0', to be able to
358 		 * recognize whether strftime actually failed or just returned "".
359 		 */
360 		tmpbuf[0] = '\1';
361 		tmplen = strftime (tmpbuf, tmpbufsize, locale_format, tm);
362 
363 		if ((tmplen == 0) && (tmpbuf[0] != '\0')) {
364 			g_free (tmpbuf);
365 			tmpbufsize *= 2;
366 
367 			if (tmpbufsize > 65536) {
368 				g_warning (G_STRLOC "Maximum buffer size for gth_datetime_strftime exceeded: giving up\n");
369 				g_free (locale_format);
370 				return NULL;
371 			}
372 		}
373 		else
374 			break;
375 	}
376 	g_free (locale_format);
377 
378 	retval = g_locale_to_utf8 (tmpbuf, tmplen, NULL, NULL, &error);
379 	if (error != NULL) {
380 		g_warning (G_STRLOC "Error converting results of strftime to UTF-8: %s\n", error->message);
381 		g_error_free (error);
382 		return NULL;
383 	}
384 
385 	g_free (tmpbuf);
386 
387 	return retval;
388 }
389 
390 
391 int
_g_time_val_cmp(GTimeVal * a,GTimeVal * b)392 _g_time_val_cmp (GTimeVal *a,
393 		 GTimeVal *b)
394 {
395 	if (a->tv_sec == b->tv_sec) {
396 		if (a->tv_usec == b->tv_usec)
397 			return 0;
398 		else
399 			return a->tv_usec > b->tv_usec ? 1 : -1;
400 	}
401 	else if (a->tv_sec > b->tv_sec)
402 		return 1;
403 	else
404 		return -1;
405 }
406 
407 
408 void
_g_time_val_reset(GTimeVal * time_)409 _g_time_val_reset (GTimeVal *time_)
410 {
411 	time_->tv_sec = 0;
412 	time_->tv_usec = 0;
413 }
414 
415 
416 gboolean
_g_time_val_from_exif_date(const char * exif_date,GTimeVal * time_)417 _g_time_val_from_exif_date (const char *exif_date,
418 			    GTimeVal   *time_)
419 {
420 	struct tm tm;
421 	long   val;
422 
423 	g_return_val_if_fail (time_ != NULL, FALSE);
424 
425 	if (exif_date == NULL)
426 		return FALSE;
427 
428 	while (g_ascii_isspace (*exif_date))
429 		exif_date++;
430 
431 	if (*exif_date == '\0')
432 		return FALSE;
433 
434 	if (! g_ascii_isdigit (*exif_date))
435 		return FALSE;
436 
437 	tm.tm_isdst = -1;
438 
439 	/* YYYY */
440 
441 	val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
442 	tm.tm_year = val - 1900;
443 
444 	if (*exif_date != ':')
445 		return FALSE;
446 
447 	/* MM */
448 
449 	exif_date++;
450 	tm.tm_mon = g_ascii_strtoull (exif_date, (char **)&exif_date, 10) - 1;
451 
452 	if (*exif_date != ':')
453 		return FALSE;
454 
455 	/* DD */
456 
457 	exif_date++;
458 	tm.tm_mday = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
459 
460   	if (*exif_date != ' ')
461 		return FALSE;
462 
463   	/* hh */
464 
465   	val = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
466   	tm.tm_hour = val;
467 
468   	if (*exif_date != ':')
469 		return FALSE;
470 
471   	/* mm */
472 
473 	exif_date++;
474 	tm.tm_min = g_ascii_strtoull (exif_date, (char **)&exif_date, 10);
475 
476 	if (*exif_date != ':')
477 		return FALSE;
478 
479       	/* ss */
480 
481 	exif_date++;
482 	tm.tm_sec = strtoul (exif_date, (char **)&exif_date, 10);
483 
484 	time_->tv_sec = mktime (&tm);
485 	time_->tv_usec = 0;
486 
487 	/* usec */
488 
489 	if ((*exif_date == ',') || (*exif_date == '.')) {
490 		glong mul = 100000;
491 
492 		while (g_ascii_isdigit (*++exif_date)) {
493 			time_->tv_usec += (*exif_date - '0') * mul;
494 			mul /= 10;
495 		}
496 	}
497 
498 	while (g_ascii_isspace (*exif_date))
499 		exif_date++;
500 
501 	return *exif_date == '\0';
502 }
503 
504 
505 char *
_g_time_val_to_exif_date(GTimeVal * time_)506 _g_time_val_to_exif_date (GTimeVal *time_)
507 {
508 	char      *retval;
509 	struct tm *tm;
510 	time_t     secs;
511 
512 	g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
513 
514 	secs = time_->tv_sec;
515 	tm = localtime (&secs);
516 	retval = g_strdup_printf ("%4d:%02d:%02d %02d:%02d:%02d",
517 				  tm->tm_year + 1900,
518 				  tm->tm_mon + 1,
519 				  tm->tm_mday,
520 				  tm->tm_hour,
521 				  tm->tm_min,
522 				  tm->tm_sec);
523 
524 	return retval;
525 }
526 
527 
528 static int
_g_time_get_timezone_offset(struct tm * tm)529 _g_time_get_timezone_offset (struct tm *tm)
530 {
531 	int offset = 0;
532 
533 #if defined (HAVE_TM_GMTOFF)
534 	offset = tm->tm_gmtoff;
535 #elif defined (HAVE_TIMEZONE)
536 	if (tm->tm_isdst > 0) {
537   #if defined (HAVE_ALTZONE)
538 		offset = -altzone;
539   #else /* !defined (HAVE_ALTZONE) */
540 		offset = -timezone + 3600;
541   #endif
542 	} else
543 		offset = -timezone;
544 #endif
545 
546 	return offset;
547 }
548 
549 
550 char *
_g_time_val_to_xmp_date(GTimeVal * time_)551 _g_time_val_to_xmp_date (GTimeVal *time_)
552 {
553 	time_t     secs;
554 	struct tm *tm;
555 	int        offset;
556 	char      *retval;
557 
558 	g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
559 
560 	secs = time_->tv_sec;
561 	tm = localtime (&secs);
562 	offset = _g_time_get_timezone_offset (tm);
563 	retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02d%+03d:%02d",
564 				  tm->tm_year + 1900,
565 				  tm->tm_mon + 1,
566 				  tm->tm_mday,
567 				  tm->tm_hour,
568 				  tm->tm_min,
569 				  tm->tm_sec,
570 				  offset / 3600,
571 				  offset % 3600);
572 
573 	return retval;
574 }
575 
576 
577 char *
_g_time_val_strftime(GTimeVal * time_,const char * format)578 _g_time_val_strftime (GTimeVal   *time_,
579 		      const char *format)
580 {
581 	time_t     secs;
582 	struct tm *tm;
583 
584 	if ((format == NULL) || (*format == '\0'))
585 		format = DEFAULT_STRFTIME_FORMAT;
586 
587 	if (strcmp (format, "%q") == 0)
588 		format = "%Y-%m-%d";
589 
590 	secs = time_->tv_sec;
591 	tm = localtime (&secs);
592 
593 	return _g_struct_tm_strftime (tm, format);
594 }
595 
596 
597 /* Bookmark file utils */
598 
599 
600 void
_g_bookmark_file_clear(GBookmarkFile * bookmark)601 _g_bookmark_file_clear (GBookmarkFile *bookmark)
602 {
603 	char **uris;
604 	int    i;
605 
606 	uris = g_bookmark_file_get_uris (bookmark, NULL);
607 	for (i = 0; uris[i] != NULL; i++)
608 		g_bookmark_file_remove_item (bookmark, uris[i], NULL);
609 	g_strfreev (uris);
610 }
611 
612 
613 void
_g_bookmark_file_add_uri(GBookmarkFile * bookmark,const char * uri)614 _g_bookmark_file_add_uri (GBookmarkFile *bookmark,
615 			  const char    *uri)
616 {
617 	g_bookmark_file_set_is_private (bookmark, uri, TRUE);
618 	g_bookmark_file_add_application (bookmark, uri, NULL, NULL);
619 }
620 
621 
622 void
_g_bookmark_file_set_uris(GBookmarkFile * bookmark,GList * uri_list)623 _g_bookmark_file_set_uris (GBookmarkFile *bookmark,
624 			   GList         *uri_list)
625 {
626 	GList *scan;
627 
628 	_g_bookmark_file_clear (bookmark);
629 	for (scan = uri_list; scan; scan = scan->next)
630 		_g_bookmark_file_add_uri (bookmark, scan->data);
631 }
632 
633 
634 /* GList utils */
635 
636 
637 GList *
_g_list_prepend_link(GList * list,GList * link)638 _g_list_prepend_link (GList *list,
639 		      GList *link)
640 {
641 	link->next = list;
642 	if (list != NULL) list->prev = link;
643 	return link;
644 }
645 
646 
647 GList *
_g_list_insert_list_before(GList * list1,GList * sibling,GList * list2)648 _g_list_insert_list_before (GList *list1,
649 			    GList *sibling,
650 			    GList *list2)
651 {
652   if (!list2)
653     {
654       return list1;
655     }
656   else if (!list1)
657     {
658       return list2;
659     }
660   else if (sibling)
661     {
662       GList *list2_last = g_list_last (list2);
663       if (sibling->prev)
664 	{
665 	  sibling->prev->next = list2;
666 	  list2->prev = sibling->prev;
667 	  sibling->prev = list2_last;
668 	  list2_last->next = sibling;
669 	  return list1;
670 	}
671       else
672 	{
673 	  sibling->prev = list2_last;
674 	  list2_last->next = sibling;
675 	  return list2;
676 	}
677     }
678   else
679     {
680       return g_list_concat (list1, list2);
681     }
682 }
683 
684 
685 
686 static int
remove_from_file_list_and_get_position(GList ** file_list,GFile * file)687 remove_from_file_list_and_get_position (GList **file_list,
688 					GFile  *file)
689 {
690 	GList *scan;
691 	int    i = 0;
692 
693 	for (scan = *file_list; scan; scan = scan->next, i++)
694 		if (g_file_equal ((GFile *) scan->data, file))
695 			break;
696 
697 	if (scan == NULL)
698 		return -1;
699 
700 	*file_list = g_list_remove_link (*file_list, scan);
701 
702 	return i;
703 }
704 
705 
706 void
_g_list_reorder(GList * all_files,GList * visible_files,GList * files_to_move,int dest_pos,int ** new_order_p,GList ** new_file_list_p)707 _g_list_reorder (GList  *all_files,
708 		 GList  *visible_files,
709 		 GList  *files_to_move,
710 		 int     dest_pos,
711 		 int   **new_order_p,
712 		 GList **new_file_list_p)
713 {
714 	GHashTable *positions;
715 	GList      *new_visible_files;
716 	GList      *scan;
717 	int        *new_order;
718 	int         pos;
719 	GList      *new_file_list;
720 	GHashTable *visibles;
721 
722 	/* save the original positions */
723 
724 	positions = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, (GDestroyNotify) g_object_unref, NULL);
725 	for (scan = visible_files, pos = 0; scan; scan = scan->next, pos++)
726 		g_hash_table_insert (positions, g_object_ref ((GFile *) scan->data), GINT_TO_POINTER (pos));
727 
728 	/* create the new visible list */
729 
730 	new_visible_files = g_list_copy (visible_files);
731 
732 	for (scan = files_to_move; scan; scan = scan->next) {
733 		int file_pos = remove_from_file_list_and_get_position (&new_visible_files, (GFile *) scan->data);
734 		if (file_pos < dest_pos)
735 			dest_pos--;
736 	}
737 
738 	for (scan = files_to_move; scan; scan = scan->next) {
739 		new_visible_files = g_list_insert (new_visible_files, (GFile *) scan->data, dest_pos);
740 		dest_pos++;
741 	}
742 
743 	/* compute the new order */
744 
745 	new_order = g_new0 (int, g_list_length (new_visible_files));
746 	for (scan = new_visible_files, pos = 0; scan; scan = scan->next, pos++)
747 		new_order[pos] = GPOINTER_TO_INT (g_hash_table_lookup (positions, (GFile *) scan->data));
748 
749 	/* save the new order in the catalog, appending the hidden files at
750 	 * the end. */
751 
752 	new_file_list = _g_object_list_ref (new_visible_files);
753 
754 	visibles = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, (GDestroyNotify) g_object_unref, NULL);
755 	for (scan = new_visible_files; scan; scan = scan->next)
756 		g_hash_table_insert (visibles, g_object_ref ((GFile *) scan->data), GINT_TO_POINTER (1));
757 
758 	new_file_list = g_list_reverse (new_file_list);
759 	for (scan = all_files; scan; scan = scan->next) {
760 		GFile *file = scan->data;
761 
762 		if (g_hash_table_lookup (visibles, file) == NULL)
763 			new_file_list = g_list_prepend (new_file_list, g_object_ref (file));
764 	}
765 	new_file_list = g_list_reverse (new_file_list);
766 
767 	if (new_order_p != NULL)
768 		*new_order_p = new_order;
769 	else
770 		g_free (new_order);
771 
772 	if (new_file_list_p != NULL)
773 		*new_file_list_p = new_file_list;
774 	else
775 		_g_object_list_unref (new_file_list);
776 
777 	g_hash_table_destroy (visibles);
778 	g_list_free (new_visible_files);
779 	g_hash_table_destroy (positions);
780 }
781 
782 
783 /* GStringList */
784 
785 
786 void
_g_string_list_free(GList * string_list)787 _g_string_list_free (GList *string_list)
788 {
789 	if (string_list == NULL)
790 		return;
791 	g_list_foreach (string_list, (GFunc) g_free, NULL);
792 	g_list_free (string_list);
793 
794 }
795 
796 
797 GList *
_g_string_list_dup(GList * string_list)798 _g_string_list_dup (GList *string_list)
799 {
800 	GList *new_list = NULL;
801 	GList *scan;
802 
803 	for (scan = string_list; scan; scan = scan->next)
804 		new_list = g_list_prepend (new_list, g_strdup (scan->data));
805 
806 	return g_list_reverse (new_list);
807 }
808 
809 
810 char **
_g_string_list_to_strv(GList * string_list)811 _g_string_list_to_strv (GList *string_list)
812 {
813 	char  **strv;
814 	GList  *scan;
815 	int     i;
816 
817 	strv = g_new0 (char *, g_list_length (string_list) + 1);
818 	for (scan = string_list, i = 0; scan; scan = scan->next)
819 		strv[i++] = g_strdup ((char *) scan->data);
820 	strv[i++] = NULL;
821 
822 	return strv;
823 }
824 
825 
826 typedef GList GStringList;
827 
828 
829 G_DEFINE_BOXED_TYPE (GStringList,
830 		     g_string_list,
831 		     (GBoxedCopyFunc) _g_string_list_dup,
832 		     (GBoxedFreeFunc) _g_string_list_free)
833 
834 
835 /* Array utils*/
836 
837 
838 char *
_g_string_array_join(GPtrArray * array,const char * separator)839 _g_string_array_join (GPtrArray  *array,
840 		      const char *separator)
841 {
842 	GString *s;
843 	int      i;
844 
845 	s = g_string_new ("");
846 	for (i = 0; i < array->len; i++) {
847 		if ((i > 0) && (separator != NULL))
848 			g_string_append (s, separator);
849 		g_string_append (s, g_ptr_array_index (array, i));
850 	}
851 
852 	return g_string_free (s, FALSE);
853 }
854 
855 
856 GPtrArray *
_g_ptr_array_dup(GPtrArray * array,GCopyFunc copy_func,GDestroyNotify free_func)857 _g_ptr_array_dup (GPtrArray	 *array,
858 		  GCopyFunc	  copy_func,
859 		  GDestroyNotify  free_func)
860 {
861 	GPtrArray *new_array;
862 	int        i;
863 
864 	g_return_val_if_fail (array != NULL, NULL);
865 
866 	new_array = g_ptr_array_sized_new (array->len);
867 	g_ptr_array_set_free_func (new_array, free_func);
868 
869 	if (copy_func != NULL)
870 		for (i = 0; i < array->len; i++)
871 			new_array->pdata[i] = copy_func (array->pdata[i], NULL);
872 	else
873 		for (i = 0; i < array->len; i++)
874 			new_array->pdata[i] = array->pdata[i];
875 
876 	new_array->len = array->len;
877 
878 	return new_array;
879 }
880 
881 
882 /* Regexp utils */
883 
884 
885 /* A pattern is a simpler version of a regexp, where
886  * dots are literal and asterisks mean any sequence of characters. */
887 static char *
_pattern_to_regexp(const char * pattern)888 _pattern_to_regexp (const char *pattern)
889 {
890 	char *tmp;
891 	char *regexp;
892 
893 	tmp = _g_utf8_strip (pattern);
894 	regexp = _g_utf8_translate (tmp,
895 			".", "\\.",
896 			"*", ".*",
897 			NULL);
898 
899 	g_free (tmp);
900 
901 	return regexp;
902 }
903 
904 
905 static char **
_split_patterns(const char * pattern,int * p_size)906 _split_patterns (const char *pattern,
907 		 int        *p_size)
908 {
909 	char **strv;
910 	int    i;
911 	int    size;
912 
913 	if (pattern == NULL)
914 		return NULL;
915 
916 	strv = _g_utf8_split (pattern, ";", MAX_PATTERNS);
917 	size = 0;
918 	for (i = 0; strv[i] != NULL; i++) {
919 		char *tmp;
920 
921 		tmp = strv[i];
922 		strv[i] = _pattern_to_regexp (strv[i]);
923 		size++;
924 
925 		g_free (tmp);
926 	}
927 
928 	if (p_size != NULL) *p_size = size;
929 
930 	return strv;
931 }
932 
933 
934 GRegex **
_g_regex_v_from_pattern(const char * pattern,GRegexCompileFlags compile_options)935 _g_regex_v_from_pattern (const char         *pattern,
936 			 GRegexCompileFlags  compile_options)
937 {
938 	char   **patternv;
939 	int      size;
940 	GRegex **regexps;
941 	int      i;
942 
943 	patternv = _split_patterns (pattern, &size);
944 	if (patternv == NULL)
945 		return NULL;
946 
947 	regexps = g_new0 (GRegex*, size + 1);
948 	for (i = 0; patternv[i] != NULL; i++) {
949 		regexps[i] = g_regex_new (patternv[i],
950 					  G_REGEX_OPTIMIZE | compile_options,
951 					  G_REGEX_MATCH_NOTEMPTY,
952 					  NULL);
953 	}
954 	g_strfreev (patternv);
955 
956 	return regexps;
957 }
958 
959 
960 gboolean
_g_regex_v_match(GRegex ** regexps,const char * str,GRegexMatchFlags match_options)961 _g_regex_v_match (GRegex           **regexps,
962 		  const char        *str,
963 		  GRegexMatchFlags   match_options)
964 {
965 	gboolean matched;
966 	int      i;
967 
968 	if ((regexps == NULL) || (regexps[0] == NULL))
969 		return TRUE;
970 
971 	if (str == NULL)
972 		return FALSE;
973 
974 	matched = FALSE;
975 	for (i = 0; regexps[i] != NULL; i++)
976 		if (g_regex_match (regexps[i], str, match_options, NULL)) {
977 			matched = TRUE;
978 			break;
979 	}
980 
981 	return matched;
982 }
983 
984 
985 void
_g_regex_v_free(GRegex ** regexps)986 _g_regex_v_free (GRegex **regexps)
987 {
988 	int i;
989 
990 	if (regexps == NULL)
991 		return;
992 
993 	for (i = 0; regexps[i] != NULL; i++)
994 		g_regex_unref (regexps[i]);
995 	g_free (regexps);
996 }
997 
998 
999 /* URI utils  */
1000 
1001 
1002 static gboolean
_g_uri_query_is_filetype(const char * uri,GFileType file_type)1003 _g_uri_query_is_filetype (const char *uri,
1004 			  GFileType   file_type)
1005 {
1006 	gboolean   result = FALSE;
1007 	GFile     *file;
1008 	GFileInfo *info;
1009 	GError    *error = NULL;
1010 
1011 	file = g_file_new_for_uri (uri);
1012 
1013 	if (! g_file_query_exists (file, NULL)) {
1014 		g_object_unref (file);
1015 		return FALSE;
1016 	}
1017 
1018 	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
1019 	if (error == NULL) {
1020 		result = (g_file_info_get_file_type (info) == file_type);
1021 	}
1022 	else {
1023 		g_warning ("Failed to get file type for uri %s: %s", uri, error->message);
1024 		g_error_free (error);
1025 	}
1026 
1027 	g_object_unref (info);
1028 	g_object_unref (file);
1029 
1030 	return result;
1031 }
1032 
1033 
1034 gboolean
_g_uri_query_is_file(const char * uri)1035 _g_uri_query_is_file (const char *uri)
1036 {
1037 	return _g_uri_query_is_filetype (uri, G_FILE_TYPE_REGULAR);
1038 }
1039 
1040 
1041 gboolean
_g_uri_query_is_dir(const char * uri)1042 _g_uri_query_is_dir (const char *uri)
1043 {
1044 	return _g_uri_query_is_filetype (uri, G_FILE_TYPE_DIRECTORY);
1045 }
1046 
1047 
1048 char *
_g_filename_clear_for_file(const char * display_name)1049 _g_filename_clear_for_file (const char *display_name)
1050 {
1051 	return _g_utf8_replace_str (display_name, "/", "_");
1052 }
1053 
1054 
1055 /* GFile utils */
1056 
1057 
1058 GFile *
_g_file_new_for_display_name(const char * base_uri,const char * display_name,const char * extension)1059 _g_file_new_for_display_name (const char *base_uri,
1060 			      const char *display_name,
1061 			      const char *extension)
1062 {
1063 	GFile *base;
1064 	char  *name;
1065 	char  *name_escaped;
1066 	GFile *catalog_file;
1067 
1068 	base = g_file_new_for_uri (base_uri);
1069 	name = g_strdup_printf ("%s%s", display_name, extension);
1070 	name_escaped = _g_utf8_replace_str (name, "/", ".");
1071 	catalog_file = g_file_get_child_for_display_name (base, name_escaped, NULL);
1072 
1073 	g_free (name_escaped);
1074 	g_free (name);
1075 	g_object_unref (base);
1076 
1077 	return catalog_file;
1078 }
1079 
1080 
1081 gboolean
_g_file_equal(GFile * file1,GFile * file2)1082 _g_file_equal (GFile *file1,
1083 	       GFile *file2)
1084 {
1085 	if ((file1 == NULL) && (file2 == NULL))
1086 		return TRUE;
1087 	if ((file1 == NULL) || (file2 == NULL))
1088 		return FALSE;
1089 
1090 	return g_file_equal (file1, file2);
1091 }
1092 
1093 
1094 char *
_g_file_get_display_name(GFile * file)1095 _g_file_get_display_name (GFile *file)
1096 {
1097 	char     *name = NULL;
1098 	char     *uri;
1099 	UriParts  parts;
1100 
1101 	uri = g_file_get_uri (file);
1102 	if (_g_uri_split (uri, &parts)) {
1103 		name = g_strdup (_g_path_get_basename (parts.path));
1104 		if (name == NULL) {
1105 			if (parts.host != NULL)
1106 				name = g_strdup (parts.host);
1107 			else
1108 				name = g_strdup ("/");
1109 		}
1110 
1111 		_g_uri_parts_clear (&parts);
1112 	}
1113 	else
1114 		name = g_strdup (_("(invalid value)"));
1115 
1116 	g_free (uri);
1117 
1118 	return name;
1119 }
1120 
1121 
1122 GFileType
_g_file_query_standard_type(GFile * file)1123 _g_file_query_standard_type (GFile *file)
1124 {
1125 	GFileType  result;
1126 	GFileInfo *info;
1127 	GError    *error = NULL;
1128 
1129 	info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, 0, NULL, &error);
1130 	if (error == NULL) {
1131 		result = g_file_info_get_file_type (info);
1132 	}
1133 	else {
1134 		result = G_FILE_ATTRIBUTE_TYPE_INVALID;
1135 		g_error_free (error);
1136 	}
1137 
1138 	if (info != NULL)
1139 		g_object_unref (info);
1140 
1141 	return result;
1142 }
1143 
1144 
1145 GFile *
_g_file_get_destination(GFile * source,GFile * source_base,GFile * destination_folder)1146 _g_file_get_destination (GFile *source,
1147 			 GFile *source_base,
1148 			 GFile *destination_folder)
1149 {
1150 	char       *source_uri;
1151 	char       *basename;
1152 	const char *source_suffix;
1153 	char       *destination_folder_uri;
1154 	char       *destination_uri;
1155 	GFile      *destination;
1156 
1157 	source_uri = g_file_get_uri (source);
1158 	basename = _g_uri_get_basename (source_uri);
1159 	if (source_base != NULL) {
1160 		char *source_base_uri;
1161 
1162 		source_base_uri = g_file_get_uri (source_base);
1163 		source_suffix = source_uri + strlen (source_base_uri);
1164 
1165 		g_free (source_base_uri);
1166 	}
1167 	else
1168 		source_suffix = basename;
1169 
1170 	destination_folder_uri = g_file_get_uri (destination_folder);
1171 	destination_uri = g_strconcat (destination_folder_uri, "/", source_suffix, NULL);
1172 	destination = g_file_new_for_uri (destination_uri);
1173 
1174 	g_free (destination_uri);
1175 	g_free (destination_folder_uri);
1176 	g_free (basename);
1177 	g_free (source_uri);
1178 
1179 	return destination;
1180 }
1181 
1182 
1183 GFile *
_g_file_get_duplicated(GFile * file)1184 _g_file_get_duplicated (GFile *file)
1185 {
1186 	GString    *new_uri;
1187 	char       *uri;
1188 	char       *uri_noext;
1189 	GRegex     *regex;
1190 	GMatchInfo *match_info;
1191 	GFile      *duplicated;
1192 	char       *ext;
1193 
1194 	new_uri = g_string_new ("");
1195 	uri = g_file_get_uri (file);
1196 	uri_noext = _g_uri_remove_extension (uri);
1197 
1198 	regex = g_regex_new ("^(.*)%20\\(([0-9]+)\\)$", 0, 0, NULL);
1199 	g_regex_match (regex, uri_noext, 0, &match_info);
1200 	if (g_match_info_matches (match_info)) {
1201 		char    *word;
1202 		guint64  n;
1203 
1204 		word = g_match_info_fetch (match_info, 1);
1205 		g_string_append (new_uri, word);
1206 		g_free (word);
1207 
1208 		word = g_match_info_fetch (match_info, 2);
1209 		n = g_ascii_strtoull (word, NULL, 10);
1210 		g_string_append_printf (new_uri, "%%20(%" G_GUINT64_FORMAT ")", n + 1);
1211 
1212 		g_free (word);
1213 	}
1214 	else {
1215 		g_string_append (new_uri, uri_noext);
1216 		g_string_append (new_uri, "%20(2)");
1217 	}
1218 
1219 	ext = _g_uri_get_extension (uri);
1220 	g_string_append (new_uri, ext);
1221 	duplicated = g_file_new_for_uri (new_uri->str);
1222 
1223 	g_free (ext);
1224 	g_match_info_free (match_info);
1225 	g_regex_unref (regex);
1226 	g_free (uri_noext);
1227 	g_free (uri);
1228 	g_string_free (new_uri, TRUE);
1229 
1230 	return duplicated;
1231 }
1232 
1233 
1234 GFile *
_g_file_get_child(GFile * file,...)1235 _g_file_get_child (GFile *file,
1236 		   ...)
1237 {
1238 	va_list     args;
1239 	const char *name;
1240 	GFile      *child;
1241 
1242 	child = g_object_ref (file);
1243 
1244 	va_start (args, file);
1245 	while ((name = va_arg (args, const char *)) != NULL) {
1246 		GFile *tmp;
1247 
1248 		tmp = g_file_get_child (child, name);
1249 		g_object_unref (child);
1250 		child = tmp;
1251 	}
1252 	va_end (args);
1253 
1254 	return child;
1255 }
1256 
1257 
1258 GList *
_g_file_list_dup(GList * l)1259 _g_file_list_dup (GList *l)
1260 {
1261 	GList *r = NULL, *scan;
1262 	for (scan = l; scan; scan = scan->next)
1263 		r = g_list_prepend (r, g_file_dup ((GFile*) scan->data));
1264 	return g_list_reverse (r);
1265 }
1266 
1267 
1268 void
_g_file_list_free(GList * l)1269 _g_file_list_free (GList *l)
1270 {
1271 	GList *scan;
1272 	for (scan = l; scan; scan = scan->next)
1273 		g_object_unref (scan->data);
1274 	g_list_free (l);
1275 }
1276 
1277 
1278 GList *
_g_file_list_new_from_uriv(char ** uris)1279 _g_file_list_new_from_uriv (char **uris)
1280 {
1281 	GList *r = NULL;
1282 	int    i;
1283 
1284 	if (uris == NULL)
1285 		return NULL;
1286 
1287 	for (i = 0; uris[i] != NULL; i++)
1288 		r = g_list_prepend (r, g_file_new_for_uri (uris[i]));
1289 
1290 	return g_list_reverse (r);
1291 }
1292 
1293 
1294 GList *
_g_file_list_find_file(GList * l,GFile * file)1295 _g_file_list_find_file (GList *l,
1296 			GFile *file)
1297 {
1298 	GList *scan;
1299 
1300 	for (scan = l; scan; scan = scan->next)
1301 		if (g_file_equal (file, (GFile *) scan->data))
1302 			return scan;
1303 	return NULL;
1304 }
1305 
1306 
1307 const char *
_g_file_query_mime_type(GFile * file,gboolean fast_file_type)1308 _g_file_query_mime_type (GFile    *file,
1309 			 gboolean  fast_file_type)
1310 {
1311 	GFileInfo  *info;
1312 	GError     *err = NULL;
1313  	const char *result = NULL;
1314 
1315 	info = g_file_query_info (file,
1316 				  fast_file_type ?
1317 				  G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE :
1318 				  G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1319 				  0, NULL, &err);
1320 	if (info == NULL) {
1321 		char *uri;
1322 
1323 		uri = g_file_get_uri (file);
1324 		g_warning ("could not get content type for %s: %s", uri, err->message);
1325 		g_free (uri);
1326 		g_clear_error (&err);
1327 	}
1328 	else {
1329 		result = _g_str_get_static (g_content_type_get_mime_type (g_file_info_get_content_type (info)));
1330 		g_object_unref (info);
1331 	}
1332 
1333 	return result;
1334 }
1335 
1336 
1337 int
_g_file_cmp_uris(GFile * a,GFile * b)1338 _g_file_cmp_uris (GFile *a,
1339 		  GFile *b)
1340 {
1341 	char *uri_a;
1342 	char *uri_b;
1343 	int   result;
1344 
1345 	uri_a = g_file_get_uri (a);
1346 	uri_b = g_file_get_uri (b);
1347 	result = g_strcmp0 (uri_a, uri_b);
1348 
1349 	g_free (uri_b);
1350 	g_free (uri_a);
1351 
1352 	return result;
1353 }
1354 
1355 
1356 gboolean
_g_file_has_scheme(GFile * file,const char * scheme)1357 _g_file_has_scheme (GFile      *file,
1358 		    const char *scheme)
1359 {
1360 	char     *file_scheme;
1361 	gboolean  result;
1362 
1363 	file_scheme = g_file_get_uri_scheme (file);
1364 	result = _g_str_equal (file_scheme, scheme);
1365 
1366 	g_free (file_scheme);
1367 
1368 	return result;
1369 }
1370 
1371 
1372 gboolean
_g_file_is_parent(GFile * dir,GFile * file)1373 _g_file_is_parent (GFile *dir,
1374 		   GFile *file)
1375 {
1376 	char     *dir_uri;
1377 	char     *file_uri;
1378 	gboolean  result;
1379 
1380 	dir_uri = g_file_get_uri (dir);
1381 	file_uri = g_file_get_uri (file);
1382 	result = _g_uri_is_parent (dir_uri, file_uri);
1383 
1384 	g_free (file_uri);
1385 	g_free (dir_uri);
1386 
1387 	return result;
1388 }
1389 
1390 
1391 GFile *
_g_file_append_path(GFile * file,const char * path)1392 _g_file_append_path (GFile      *file,
1393 		     const char *path)
1394 {
1395 	char     *uri;
1396 	UriParts  parts;
1397 	char     *new_path;
1398 	char     *new_uri;
1399 	GFile    *new_file;
1400 
1401 	if (path == NULL)
1402 		return g_file_dup (file);
1403 
1404 	uri = g_file_get_uri (file);
1405 	_g_uri_split (uri, &parts);
1406 	new_path = _g_path_join (parts.path, path, NULL);
1407 	_g_str_set (&parts.path, new_path);
1408 	new_uri = _g_uri_join (&parts);
1409 	new_file = g_file_new_for_uri (new_uri);
1410 
1411 	g_free (new_uri);
1412 	_g_uri_parts_clear (&parts);
1413 	g_free (new_path);
1414 	g_free (uri);
1415 
1416 	return new_file;
1417 }
1418 
1419 
1420 static gboolean
attribute_matches_mask(const char * attribute,const char * mask)1421 attribute_matches_mask (const char *attribute,
1422 			const char *mask)
1423 {
1424 	char *pattern_end;
1425 
1426 	pattern_end = g_strstr_len (mask, -1, "*");
1427 	if (pattern_end == NULL)
1428 		return strcmp (attribute, mask) == 0;
1429 	else
1430 		return strncmp (attribute, mask, pattern_end - mask) == 0;
1431 }
1432 
1433 
1434 gboolean
_g_file_attributes_matches_all(const char * attributes,const char * mask)1435 _g_file_attributes_matches_all (const char *attributes,
1436 			        const char *mask)
1437 {
1438 	gboolean   matches_all_mask = TRUE;
1439 	char     **attributes_v;
1440 	char     **mask_v;
1441 	int        j;
1442 
1443 	attributes_v = g_strsplit (attributes, ",", -1);
1444 	mask_v = g_strsplit (mask, ",", -1);
1445 	for (j = 0; matches_all_mask && (attributes_v[j] != NULL); j++) {
1446 		gboolean matches = FALSE;
1447 		int      i;
1448 
1449 		for (i = 0; ! matches && (mask_v[i] != NULL); i++) {
1450 			matches = attribute_matches_mask (attributes_v[j], mask_v[i]);
1451 #if 0
1452 			g_print ("attr: %s <=> mask: %s : %d\n", attributes_v[j], mask_v[i], matches);
1453 #endif
1454 		}
1455 
1456 		matches_all_mask = matches;
1457 	}
1458 
1459 	g_strfreev (mask_v);
1460 	g_strfreev (attributes_v);
1461 
1462 	return matches_all_mask;
1463 }
1464 
1465 
1466 static gboolean
_attributes_matches_mask(const char * attributes,const char * mask)1467 _attributes_matches_mask (const char *attributes,
1468 			  const char *mask)
1469 {
1470 	gboolean   matches = FALSE;
1471 	char     **attributes_v;
1472 	char     **mask_v;
1473 	int        i;
1474 
1475 	attributes_v = g_strsplit (attributes, ",", -1);
1476 	mask_v = g_strsplit (mask, ",", -1);
1477 	for (i = 0; ! matches && (mask_v[i] != NULL); i++) {
1478 		int j;
1479 
1480 		for (j = 0; ! matches && (attributes_v[j] != NULL); j++) {
1481 			matches = attribute_matches_mask (attributes_v[j], mask_v[i]);
1482 #if 0
1483 			g_print ("attr: %s <=> mask: %s : %d\n", attributes_v[j], mask_v[i], matches);
1484 #endif
1485 		}
1486 	}
1487 
1488 	g_strfreev (mask_v);
1489 	g_strfreev (attributes_v);
1490 
1491 	return matches;
1492 }
1493 
1494 
1495 gboolean
_g_file_attributes_matches_any(const char * attributes,const char * mask)1496 _g_file_attributes_matches_any (const char *attributes,
1497 			        const char *mask)
1498 {
1499 	return _attributes_matches_mask (attributes, mask) || _attributes_matches_mask (mask, attributes);
1500 }
1501 
1502 
1503 gboolean
_g_file_attributes_matches_any_v(const char * attributes,char ** attribute_v)1504 _g_file_attributes_matches_any_v (const char *attributes,
1505 				  char      **attribute_v)
1506 {
1507 	gboolean matches;
1508 	int      i;
1509 
1510 	if (attributes == NULL)
1511 		return FALSE;
1512 
1513 	matches = FALSE;
1514 	for (i = 0; ! matches && (attribute_v[i] != NULL); i++)
1515 		matches = _g_file_attributes_matches_any (attributes, attribute_v[i]);
1516 
1517 	return matches;
1518 }
1519 
1520 
1521 /* -- _g_file_info_swap_attributes -- */
1522 
1523 
1524 typedef struct {
1525 	GFileAttributeType type;
1526 	union {
1527 		char      *string;
1528 		char     **stringv;
1529 		gboolean   boolean;
1530 		guint32    uint32;
1531 		gint32     int32;
1532 		guint64    uint64;
1533 		gint64     int64;
1534 		gpointer   object;
1535 	} v;
1536 } _GFileAttributeValue;
1537 
1538 
1539 static void
_g_file_attribute_value_free(_GFileAttributeValue * attr_value)1540 _g_file_attribute_value_free (_GFileAttributeValue *attr_value)
1541 {
1542 	switch (attr_value->type) {
1543 	case G_FILE_ATTRIBUTE_TYPE_STRING:
1544 	case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
1545 		g_free (attr_value->v.string);
1546 		break;
1547 #if GLIB_CHECK_VERSION(2,22,0)
1548 	case G_FILE_ATTRIBUTE_TYPE_STRINGV:
1549 		g_strfreev (attr_value->v.stringv);
1550 		break;
1551 #endif
1552 	case G_FILE_ATTRIBUTE_TYPE_OBJECT:
1553 		g_object_unref (attr_value->v.object);
1554 		break;
1555 	default:
1556 		break;
1557 	}
1558 
1559 	g_free (attr_value);
1560 }
1561 
1562 
1563 static _GFileAttributeValue *
_g_file_info_get_value(GFileInfo * info,const char * attr)1564 _g_file_info_get_value (GFileInfo  *info,
1565 			const char *attr)
1566 {
1567 	_GFileAttributeValue  *attr_value;
1568 	GFileAttributeType     type;
1569 	gpointer               value;
1570 	GFileAttributeStatus   status;
1571 
1572 	attr_value = g_new (_GFileAttributeValue, 1);
1573 	attr_value->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
1574 
1575 	if (! g_file_info_get_attribute_data (info, attr, &type, &value, &status))
1576 		return attr_value;
1577 
1578 	attr_value->type = type;
1579 	switch (type) {
1580 	case G_FILE_ATTRIBUTE_TYPE_INVALID:
1581 		break;
1582 	case G_FILE_ATTRIBUTE_TYPE_STRING:
1583 	case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
1584 		attr_value->v.string = g_strdup ((char *) value);
1585 		break;
1586 #if GLIB_CHECK_VERSION(2,22,0)
1587 	case G_FILE_ATTRIBUTE_TYPE_STRINGV:
1588 		attr_value->v.stringv = g_strdupv ((char **) value);
1589 		break;
1590 #endif
1591 	case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
1592 		attr_value->v.boolean = * ((gboolean *) value);
1593 		break;
1594 	case G_FILE_ATTRIBUTE_TYPE_UINT32:
1595 		attr_value->v.uint32 = * ((guint32 *) value);
1596 		break;
1597 	case G_FILE_ATTRIBUTE_TYPE_INT32:
1598 		attr_value->v.int32 = * ((gint32 *) value);
1599 		break;
1600 	case G_FILE_ATTRIBUTE_TYPE_UINT64:
1601 		attr_value->v.uint64 = * ((guint64 *) value);
1602 		break;
1603 	case G_FILE_ATTRIBUTE_TYPE_INT64:
1604 		attr_value->v.int64 = * ((gint64 *) value);
1605 		break;
1606 	case G_FILE_ATTRIBUTE_TYPE_OBJECT:
1607 		attr_value->v.object = g_object_ref ((GObject *) value);
1608 		break;
1609 	default:
1610 		g_warning ("unknown attribute type: %d", type);
1611 		break;
1612 	}
1613 
1614 	return attr_value;
1615 }
1616 
1617 
1618 static void
_g_file_info_set_value(GFileInfo * info,const char * attr,_GFileAttributeValue * attr_value)1619 _g_file_info_set_value (GFileInfo            *info,
1620 			const char           *attr,
1621 			_GFileAttributeValue *attr_value)
1622 {
1623 	gpointer value = NULL;
1624 
1625 	if (attr_value->type == G_FILE_ATTRIBUTE_TYPE_INVALID)
1626 		return;
1627 
1628 	switch (attr_value->type) {
1629 	case G_FILE_ATTRIBUTE_TYPE_STRING:
1630 	case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
1631 		value = attr_value->v.string;
1632 		break;
1633 #if GLIB_CHECK_VERSION(2,22,0)
1634 	case G_FILE_ATTRIBUTE_TYPE_STRINGV:
1635 		value = attr_value->v.stringv;
1636 		break;
1637 #endif
1638 	case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
1639 		value = &attr_value->v.boolean;
1640 		break;
1641 	case G_FILE_ATTRIBUTE_TYPE_UINT32:
1642 		value = &attr_value->v.uint32;
1643 		break;
1644 	case G_FILE_ATTRIBUTE_TYPE_INT32:
1645 		value = &attr_value->v.int32;
1646 		break;
1647 	case G_FILE_ATTRIBUTE_TYPE_UINT64:
1648 		value = &attr_value->v.uint64;
1649 		break;
1650 	case G_FILE_ATTRIBUTE_TYPE_INT64:
1651 		value = &attr_value->v.int64;
1652 		break;
1653 	case G_FILE_ATTRIBUTE_TYPE_OBJECT:
1654 		value = attr_value->v.object;
1655 		break;
1656 	default:
1657 		g_warning ("Unknown attribute type: %d", attr_value->type);
1658 		break;
1659 	}
1660 
1661 	g_file_info_set_attribute (info, attr, attr_value->type, value);
1662 }
1663 
1664 
1665 void
_g_file_info_swap_attributes(GFileInfo * info,const char * attr1,const char * attr2)1666 _g_file_info_swap_attributes (GFileInfo  *info,
1667 			      const char *attr1,
1668 			      const char *attr2)
1669 {
1670 	_GFileAttributeValue *value1;
1671 	_GFileAttributeValue *value2;
1672 
1673 	value1 = _g_file_info_get_value (info, attr1);
1674 	value2 = _g_file_info_get_value (info, attr2);
1675 
1676 	_g_file_info_set_value (info, attr1, value2);
1677 	_g_file_info_set_value (info, attr2, value1);
1678 
1679 	_g_file_attribute_value_free (value1);
1680 	_g_file_attribute_value_free (value2);
1681 }
1682 
1683 
1684 void
_g_file_info_set_secondary_sort_order(GFileInfo * info,gint32 sort_order)1685 _g_file_info_set_secondary_sort_order (GFileInfo  *info,
1686 				       gint32      sort_order)
1687 {
1688 	g_file_info_set_attribute_int32 (info, "gth::standard::secondary-sort-order", sort_order);
1689 }
1690 
1691 
1692 gint32
_g_file_info_get_secondary_sort_order(GFileInfo * info)1693 _g_file_info_get_secondary_sort_order (GFileInfo  *info)
1694 {
1695 	return g_file_info_get_attribute_int32 (info, "gth::standard::secondary-sort-order");
1696 }
1697 
1698 
1699 void
_g_file_info_update(GFileInfo * dest_info,GFileInfo * src_info)1700 _g_file_info_update (GFileInfo  *dest_info,
1701 		     GFileInfo  *src_info)
1702 {
1703 	char **attributes;
1704 	int    i;
1705 
1706 	if (src_info == NULL)
1707 		return;
1708 
1709 	attributes = g_file_info_list_attributes (src_info, NULL);
1710 	for (i = 0; attributes[i] != NULL; i++) {
1711 		GFileAttributeType   type;
1712 		gpointer             value_pp;
1713 		GFileAttributeStatus status;
1714 
1715 		if (g_file_info_get_attribute_data (src_info,
1716 						    attributes[i],
1717 						    &type,
1718 						    &value_pp,
1719 						    &status))
1720 		{
1721 			g_file_info_set_attribute (dest_info, attributes[i], type, value_pp);
1722 		}
1723 	}
1724 
1725 	g_strfreev (attributes);
1726 }
1727 
1728 
1729 const char *
_g_content_type_guess_from_name(const char * filename)1730 _g_content_type_guess_from_name (const char *filename)
1731 {
1732 	if (filename == NULL)
1733 		return NULL;
1734 
1735 #if WEBP_IS_UNKNOWN_TO_GLIB
1736 	if (_g_str_equal (_g_path_get_extension (filename), ".webp"))
1737 		return "image/webp";
1738 #endif
1739 
1740 	return g_content_type_guess (filename, NULL, 0, NULL);
1741 }
1742 
1743 
1744 gboolean
_g_content_type_is_a(const char * type,const char * supertype)1745 _g_content_type_is_a (const char *type,
1746 		      const char *supertype)
1747 {
1748 	if (type == NULL)
1749 		return FALSE;
1750 	else
1751 		return g_content_type_is_a (type, supertype);
1752 }
1753 
1754 
1755 /* -- _g_content_type_get_from_stream -- */
1756 
1757 
1758 static const char *
get_mime_type_from_magic_numbers(guchar * buffer,gsize buffer_size)1759 get_mime_type_from_magic_numbers (guchar *buffer,
1760 				  gsize   buffer_size)
1761 {
1762 #if ENABLE_MAGIC
1763 
1764 	static magic_t magic = NULL;
1765 
1766 	if (magic == NULL) {
1767 		magic = magic_open (MAGIC_MIME_TYPE);
1768 		if (magic != NULL)
1769 			magic_load (magic, NULL);
1770 		else
1771 			g_warning ("unable to open magic database");
1772 	}
1773 
1774 	if (magic != NULL) {
1775 		const char * mime_type;
1776 
1777 		mime_type = magic_buffer (magic, buffer, buffer_size);
1778 		if (mime_type)
1779 			return mime_type;
1780 
1781 		g_warning ("unable to detect filetype from magic: %s", magic_error (magic));
1782 	}
1783 
1784 #else
1785 
1786 	static const struct magic {
1787 		const unsigned int off;
1788 		const unsigned int len;
1789 		const char * const id;
1790 		const char * const mime_type;
1791 	}
1792 	magic_ids [] = {
1793 		/* some magic ids taken from magic/Magdir/archive from the file-4.21 tarball */
1794 		{ 0,  8, "\x89PNG\x0d\x0a\x1a\x0a",		"image/png" },
1795 		{ 0,  4, "MM\x00\x2a",				"image/tiff" },
1796 		{ 0,  4, "II\x2a\x00",				"image/tiff" },
1797 		{ 0,  4, "GIF8",				"image/gif" },
1798 		{ 0,  3, "\xff\xd8\xff",			"image/jpeg" },
1799 		{ 8,  7, "WEBPVP8",				"image/webp" }
1800 	};
1801 
1802 	int  i;
1803 
1804 	for (i = 0; i < G_N_ELEMENTS (magic_ids); i++) {
1805 		const struct magic * const magic = &magic_ids[i];
1806 
1807 		if ((magic->off + magic->len) > buffer_size)
1808 			continue;
1809 
1810 		if (! memcmp (buffer + magic->off, magic->id, magic->len))
1811 			return magic->mime_type;
1812 	}
1813 
1814 #endif
1815 
1816 	return NULL;
1817 }
1818 
1819 
1820 const char *
_g_content_type_get_from_stream(GInputStream * istream,GFile * file,GCancellable * cancellable,GError ** error)1821 _g_content_type_get_from_stream (GInputStream  *istream,
1822 				 GFile         *file,
1823 				 GCancellable  *cancellable,
1824 				 GError       **error)
1825 {
1826 	guchar      buffer[BUFFER_SIZE_FOR_SNIFFING];
1827 	gsize       n = 0;
1828 	gboolean    result_uncertain = FALSE;
1829 	const char *content_type;
1830 
1831 	if (! g_input_stream_read_all (istream,
1832 				       buffer,
1833 				       BUFFER_SIZE_FOR_SNIFFING,
1834 				       &n,
1835 				       cancellable,
1836 				       error))
1837 	{
1838 		return NULL;
1839 	}
1840 
1841 	content_type = get_mime_type_from_magic_numbers (buffer, n);
1842 	if (content_type == NULL)
1843 		content_type = g_content_type_guess (NULL, buffer, n, &result_uncertain);
1844 	if (result_uncertain)
1845 		content_type = NULL;
1846 
1847 	if (((content_type == NULL)
1848 	     || (strcmp (content_type, "application/xml") == 0)
1849 	     || (strcmp (content_type, "image/tiff") == 0))
1850 	    && (file != NULL))
1851 	{
1852 		char *filename;
1853 
1854 		filename = g_file_get_basename (file);
1855 		content_type = _g_content_type_guess_from_name (filename);
1856 
1857 		g_free (filename);
1858 	}
1859 
1860 	g_seekable_seek (G_SEEKABLE (istream), 0, G_SEEK_SET, cancellable, NULL);
1861 
1862 	return content_type;
1863 }
1864 
1865 
1866 gboolean
_g_mime_type_is_image(const char * mime_type)1867 _g_mime_type_is_image (const char *mime_type)
1868 {
1869 	g_return_val_if_fail (mime_type != NULL, FALSE);
1870 
1871 	return g_content_type_is_a (mime_type, "image/*");
1872 }
1873 
1874 
1875 gboolean
_g_mime_type_is_raw(const char * mime_type)1876 _g_mime_type_is_raw (const char *mime_type)
1877 {
1878 	g_return_val_if_fail (mime_type != NULL, FALSE);
1879 
1880 	return g_content_type_is_a (mime_type, "image/x-dcraw");
1881 }
1882 
1883 
1884 gboolean
_g_mime_type_is_video(const char * mime_type)1885 _g_mime_type_is_video (const char *mime_type)
1886 {
1887 	g_return_val_if_fail (mime_type != NULL, FALSE);
1888 
1889 	return (g_content_type_is_a (mime_type, "video/*")
1890 		|| (strcmp (mime_type, "application/ogg") == 0)
1891 		|| (strcmp (mime_type, "application/vnd.ms-asf") == 0)
1892 		|| (strcmp (mime_type, "application/vnd.rn-realmedia") == 0));
1893 }
1894 
1895 
1896 gboolean
_g_mime_type_is_audio(const char * mime_type)1897 _g_mime_type_is_audio (const char *mime_type)
1898 {
1899 	g_return_val_if_fail (mime_type != NULL, FALSE);
1900 
1901 	return g_content_type_is_a (mime_type, "audio/*");
1902 }
1903 
1904 
1905 gboolean
_g_mime_type_has_transparency(const char * mime_type)1906 _g_mime_type_has_transparency (const char *mime_type)
1907 {
1908 	g_return_val_if_fail (mime_type != NULL, FALSE);
1909 
1910 	return (strcmp (mime_type, "image/png") == 0)
1911 		|| (strcmp (mime_type, "image/gif") == 0)
1912 		|| (strcmp (mime_type, "image/svg+xml") == 0);
1913 }
1914 
1915 
1916 char *
_g_settings_get_uri(GSettings * settings,const char * key)1917 _g_settings_get_uri (GSettings  *settings,
1918 		     const char *key)
1919 {
1920 	char *value;
1921 	char *uri;
1922 
1923 	value = g_settings_get_string (settings, key);
1924 	if ((value == NULL) || (strcmp (value, "") == 0)) {
1925 		g_free (value);
1926 		return NULL;
1927 	}
1928 
1929 	uri = _g_utf8_replace_str (value, "file://~", _g_uri_get_home ());
1930 
1931 	g_free (value);
1932 
1933 	return uri;
1934 }
1935 
1936 
1937 char *
_g_settings_get_uri_or_special_dir(GSettings * settings,const char * key,GUserDirectory directory)1938 _g_settings_get_uri_or_special_dir (GSettings      *settings,
1939 		     	     	    const char     *key,
1940 		     	     	    GUserDirectory  directory)
1941 {
1942 	char *uri;
1943 
1944 	uri = g_settings_get_string (settings, key);
1945 	if ((uri == NULL) || (strcmp (uri, "~") == 0) || (strcmp (uri, "file://~") == 0)) {
1946 		const char *dir;
1947 
1948 		g_free (uri);
1949 		uri = NULL;
1950 
1951 		dir = g_get_user_special_dir (directory);
1952 		if (dir != NULL)
1953 			uri = g_filename_to_uri (dir, NULL, NULL);
1954 		if (uri == NULL)
1955 			uri = g_strdup (_g_uri_get_home ());
1956 	}
1957 	else {
1958 		char *tmp = uri;
1959 		uri = _g_utf8_replace_str (tmp, "file://~", _g_uri_get_home ());
1960 		g_free (tmp);
1961 	}
1962 
1963 	return uri;
1964 }
1965 
1966 
1967 void
_g_settings_set_uri(GSettings * settings,const char * key,const char * uri)1968 _g_settings_set_uri (GSettings  *settings,
1969 		     const char *key,
1970 		     const char *uri)
1971 {
1972 	g_settings_set_string (settings, key, uri);
1973 }
1974 
1975 
1976 void
_g_settings_set_string_list(GSettings * settings,const char * key,GList * list)1977 _g_settings_set_string_list (GSettings  *settings,
1978 			     const char *key,
1979 			     GList      *list)
1980 {
1981 	int     len;
1982 	char  **strv;
1983 	int     i;
1984 	GList  *scan;
1985 
1986 	len = g_list_length (list);
1987 	strv = g_new (char *, len + 1);
1988 	for (i = 0, scan = list; scan; scan = scan->next)
1989 		strv[i++] = scan->data;
1990 	strv[i] = NULL;
1991 
1992 	g_settings_set_strv (settings, key, (const char *const *) strv);
1993 
1994 	g_free (strv);
1995 }
1996 
1997 
1998 GList *
_g_settings_get_string_list(GSettings * settings,const char * key)1999 _g_settings_get_string_list (GSettings  *settings,
2000 			     const char *key)
2001 {
2002 	char **strv;
2003 	int    i;
2004 	GList *list;
2005 
2006 	strv = g_settings_get_strv (settings, key);
2007 	list = NULL;
2008 	for (i = 0; strv[i] != NULL; i++)
2009 		list = g_list_prepend (list, g_strdup (strv[i]));
2010 
2011 	g_strfreev (strv);
2012 
2013 	return g_list_reverse (list);
2014 }
2015 
2016 
2017 GSettings *
_g_settings_new_if_schema_installed(const char * schema_id)2018 _g_settings_new_if_schema_installed (const char *schema_id)
2019 {
2020 	GSettingsSchema *schema;
2021 
2022 	schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
2023 						  schema_id,
2024 						  TRUE);
2025 	if (schema == NULL)
2026 		return NULL;
2027 
2028 	g_settings_schema_unref (schema);
2029 
2030 	return g_settings_new (schema_id);
2031 }
2032 
2033 
2034 /* this is totem_time_to_string renamed, thanks to the authors :) */
2035 char *
_g_format_duration_for_display(gint64 msecs)2036 _g_format_duration_for_display (gint64 msecs)
2037 {
2038         int sec, min, hour, _time;
2039 
2040         _time = (int) (msecs / 1000);
2041         sec = _time % 60;
2042         _time = _time - sec;
2043         min = (_time % (60*60)) / 60;
2044         _time = _time - (min * 60);
2045         hour = _time / (60*60);
2046 
2047         if (hour > 0)
2048         {
2049                 /* hour:minutes:seconds */
2050                 /* Translators: This is a time format, like "9∶05∶02" for 9
2051                  * hours, 5 minutes, and 2 seconds. You may change "∶" to
2052                  * the separator that your locale uses or use "%Id" instead
2053                  * of "%d" if your locale uses localized digits.
2054                  */
2055                 return g_strdup_printf (C_("long time format", "%d∶%02d∶%02d"), hour, min, sec);
2056         }
2057 
2058         /* minutes:seconds */
2059         /* Translators: This is a time format, like "5∶02" for 5
2060          * minutes and 2 seconds. You may change "∶" to the
2061          * separator that your locale uses or use "%Id" instead of
2062          * "%d" if your locale uses localized digits.
2063          */
2064         return g_strdup_printf (C_("short time format", "%d∶%02d"), min, sec);
2065 }
2066 
2067 
2068 char *
_g_format_str_for_file(const char * format,GFile * file)2069 _g_format_str_for_file (const char *format,
2070 			GFile      *file)
2071 {
2072 	char     *uri;
2073 	UriParts  parts;
2074 	char     *name;
2075 	char     *str;
2076 
2077 	uri = g_file_get_uri (file);
2078 	if (! _g_uri_split (uri, &parts) || (parts.path == NULL) || (parts.scheme == NULL))
2079 		name = g_strdup (_("(invalid value)"));
2080 	else if (_g_str_equal (parts.scheme, "file"))
2081 		name = g_strdup (parts.path);
2082 	else if (parts.host != NULL)
2083 		name = g_strdup_printf ("%s://%s%s%s", parts.scheme, parts.host, ((parts.path[0] != '/') ? "/" : ""), parts.path);
2084 	else
2085 		name = g_strdup_printf ("%s://%s", parts.scheme, parts.path);
2086 	str = g_strdup_printf (format, name);
2087 
2088 	g_free (name);
2089 	_g_uri_parts_clear (&parts);
2090 	g_free (uri);
2091 
2092 	return str;
2093 }
2094 
2095 
2096 void
_g_error_free(GError * error)2097 _g_error_free (GError *error)
2098 {
2099 	if (error != NULL)
2100 		g_error_free (error);
2101 }
2102 
2103 
2104 void
toggle_action_activated(GSimpleAction * action,GVariant * parameter,gpointer data)2105 toggle_action_activated (GSimpleAction *action,
2106 			 GVariant      *parameter,
2107 			 gpointer       data)
2108 {
2109 	GVariant *state;
2110 
2111 	state = g_action_get_state (G_ACTION (action));
2112 	g_action_change_state (G_ACTION (action), g_variant_new_boolean (! g_variant_get_boolean (state)));
2113 
2114 	g_variant_unref (state);
2115 }
2116