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