ee93d6cce5494048cdac7ae502fbbefa01c29505
[platform/upstream/glib.git] / gio / gfileattribute.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26
27 #include "gfileattribute.h"
28 #include <glib-object.h>
29 #include "glibintl.h"
30
31 /**
32  * g_file_attribute_value_free:
33  * @attr: a #GFileAttributeValue. 
34  * 
35  * Frees the memory used by @attr.
36  *
37  **/
38 void
39 g_file_attribute_value_free (GFileAttributeValue *attr)
40 {
41   g_return_if_fail (attr != NULL);
42
43   g_file_attribute_value_clear (attr);
44   g_free (attr);
45 }
46
47 /**
48  * g_file_attribute_value_clear:
49  * @attr: a #GFileAttributeValue.
50  *
51  * Clears the value of @attr and sets its type to 
52  * %G_FILE_ATTRIBUTE_TYPE_INVALID.
53  * 
54  **/
55 void
56 g_file_attribute_value_clear (GFileAttributeValue *attr)
57 {
58   g_return_if_fail (attr != NULL);
59
60   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
61       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
62     g_free (attr->u.string);
63   
64   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
65       attr->u.obj != NULL)
66     g_object_unref (attr->u.obj);
67   
68   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
69 }
70
71 /**
72  * g_file_attribute_value_set:
73  * @attr: a #GFileAttributeValue.
74  * @new_value:
75  * 
76  **/
77 void
78 g_file_attribute_value_set (GFileAttributeValue *attr,
79                             const GFileAttributeValue *new_value)
80 {
81   g_return_if_fail (attr != NULL);
82   g_return_if_fail (new_value != NULL);
83
84   g_file_attribute_value_clear (attr);
85   *attr = *new_value;
86
87   if (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING ||
88       attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING)
89     attr->u.string = g_strdup (attr->u.string);
90   
91   if (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT &&
92       attr->u.obj != NULL)
93     g_object_ref (attr->u.obj);
94 }
95
96 /**
97  * g_file_attribute_value_new:
98  * 
99  * Returns: a new #GFileAttributeValue.
100  **/
101 GFileAttributeValue *
102 g_file_attribute_value_new (void)
103 {
104   GFileAttributeValue *attr;
105
106   attr = g_new (GFileAttributeValue, 1);
107   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
108   return attr;
109 }
110
111
112 /**
113  * g_file_attribute_value_dup:
114  * @other: a #GFileAttributeValue to duplicate.
115  * 
116  * Returns: a duplicate of the @other.
117  **/
118 GFileAttributeValue *
119 g_file_attribute_value_dup (const GFileAttributeValue *other)
120 {
121   GFileAttributeValue *attr;
122
123   g_return_val_if_fail (other != NULL, NULL);
124
125   attr = g_new (GFileAttributeValue, 1);
126   attr->type = G_FILE_ATTRIBUTE_TYPE_INVALID;
127   g_file_attribute_value_set (attr, other);
128   return attr;
129 }
130
131 static gboolean
132 valid_char (char c)
133 {
134   return c >= 32 && c <= 126 && c != '\\';
135 }
136
137 static char *
138 escape_byte_string (const char *str)
139 {
140   size_t len;
141   int num_invalid, i;
142   char *escaped_val, *p;
143   unsigned char c;
144   char *hex_digits = "0123456789abcdef";
145   
146   len = strlen (str);
147   
148   num_invalid = 0;
149   for (i = 0; i < len; i++)
150     {
151       if (!valid_char (str[i]))
152         num_invalid++;
153     }
154         
155   if (num_invalid == 0)
156     return g_strdup (str);
157   else
158     {
159       escaped_val = g_malloc (len + num_invalid*3 + 1);
160
161       p = escaped_val;
162       for (i = 0; i < len; i++)
163         {
164           c = str[i];
165           if (valid_char (c))
166             *p++ = c;
167           else
168             {
169               *p++ = '\\';
170               *p++ = 'x';
171               *p++ = hex_digits[(c >> 8) & 0xf];
172               *p++ = hex_digits[c & 0xf];
173             }
174         }
175       *p++ = 0;
176       return escaped_val;
177     }
178 }
179
180 /**
181  * g_file_attribute_value_as_string:
182  * @attr: a #GFileAttributeValue.
183  *
184  * Converts a #GFileAttributeValue to a string for display.
185  * The returned string should be freed when no longer needed
186  * 
187  * Returns: a string from the @attr, %NULL on error, or "&lt;invalid&gt;" if 
188  * @attr is of type %G_FILE_ATTRIBUTE_TYPE_INVALID.
189  **/
190 char *
191 g_file_attribute_value_as_string (const GFileAttributeValue *attr)
192 {
193   char *str;
194
195   g_return_val_if_fail (attr != NULL, NULL);
196
197   switch (attr->type)
198     {
199     case G_FILE_ATTRIBUTE_TYPE_STRING:
200       str = g_strdup (attr->u.string);
201       break;
202     case G_FILE_ATTRIBUTE_TYPE_BYTE_STRING:
203       str = escape_byte_string (attr->u.string);
204       break;
205     case G_FILE_ATTRIBUTE_TYPE_BOOLEAN:
206       str = g_strdup_printf ("%s", attr->u.boolean?"TRUE":"FALSE");
207       break;
208     case G_FILE_ATTRIBUTE_TYPE_UINT32:
209       str = g_strdup_printf ("%u", (unsigned int)attr->u.uint32);
210       break;
211     case G_FILE_ATTRIBUTE_TYPE_INT32:
212       str = g_strdup_printf ("%i", (int)attr->u.int32);
213       break;
214     case G_FILE_ATTRIBUTE_TYPE_UINT64:
215       str = g_strdup_printf ("%"G_GUINT64_FORMAT, attr->u.uint64);
216       break;
217     case G_FILE_ATTRIBUTE_TYPE_INT64:
218       str = g_strdup_printf ("%"G_GINT64_FORMAT, attr->u.int64);
219       break;
220     case G_FILE_ATTRIBUTE_TYPE_OBJECT:
221       str = g_strdup_printf ("%s:%p", g_type_name_from_instance
222                                           ((GTypeInstance *) attr->u.obj),
223                                       attr->u.obj);
224       break;
225     default:
226       g_warning ("Invalid type in GFileInfo attribute");
227       str = g_strdup ("<invalid>");
228       break;
229     }
230   
231   return str;
232 }
233
234 /**
235  * g_file_attribute_value_get_string:
236  * @attr: a #GFileAttributeValue.
237  * 
238  * Returns: 
239  **/
240 const char *
241 g_file_attribute_value_get_string (const GFileAttributeValue *attr)
242 {
243   if (attr == NULL)
244     return NULL;
245
246   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_STRING, NULL);
247
248   return attr->u.string;
249 }
250
251 /**
252  * g_file_attribute_value_get_byte_string:
253  * @attr: a #GFileAttributeValue.
254  * 
255  * Returns: 
256  **/
257 const char *
258 g_file_attribute_value_get_byte_string (const GFileAttributeValue *attr)
259 {
260   if (attr == NULL)
261     return NULL;
262
263   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BYTE_STRING, NULL);
264
265   return attr->u.string;
266 }
267   
268 /**
269  * g_file_attribute_value_get_boolean:
270  * @attr: a #GFileAttributeValue.
271  * 
272  * Returns: 
273  **/
274 gboolean
275 g_file_attribute_value_get_boolean (const GFileAttributeValue *attr)
276 {
277   if (attr == NULL)
278     return FALSE;
279
280   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_BOOLEAN, FALSE);
281
282   return attr->u.boolean;
283 }
284   
285 /**
286  * g_file_attribute_value_get_uint32:
287  * @attr: a #GFileAttributeValue.
288  * 
289  * Returns: 
290  **/
291 guint32
292 g_file_attribute_value_get_uint32 (const GFileAttributeValue *attr)
293 {
294   if (attr == NULL)
295     return 0;
296
297   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT32, 0);
298
299   return attr->u.uint32;
300 }
301
302 /**
303  * g_file_attribute_value_get_int32:
304  * @attr: a #GFileAttributeValue.
305  * 
306  * Returns: 
307  **/
308 gint32
309 g_file_attribute_value_get_int32 (const GFileAttributeValue *attr)
310 {
311   if (attr == NULL)
312     return 0;
313
314   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT32, 0);
315
316   return attr->u.int32;
317 }
318
319 /**
320  * g_file_attribute_value_get_uint64:
321  * @attr: a #GFileAttributeValue.
322  * 
323  * Returns: 
324  **/  
325 guint64
326 g_file_attribute_value_get_uint64 (const GFileAttributeValue *attr)
327 {
328   if (attr == NULL)
329     return 0;
330
331   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_UINT64, 0);
332
333   return attr->u.uint64;
334 }
335
336 /**
337  * g_file_attribute_value_get_int64:
338  * @attr: a #GFileAttributeValue.
339  * 
340  * Returns: 
341  **/
342 gint64
343 g_file_attribute_value_get_int64 (const GFileAttributeValue *attr)
344 {
345   if (attr == NULL)
346     return 0;
347
348   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_INT64, 0);
349
350   return attr->u.int64;
351 }
352
353 /**
354  * g_file_attribute_value_get_object:
355  * @attr: a #GFileAttributeValue.
356  * 
357  * Returns: 
358  **/
359 GObject *
360 g_file_attribute_value_get_object (const GFileAttributeValue *attr)
361 {
362   if (attr == NULL)
363     return NULL;
364
365   g_return_val_if_fail (attr->type == G_FILE_ATTRIBUTE_TYPE_OBJECT, NULL);
366
367   return attr->u.obj;
368 }
369   
370 /**
371  * g_file_attribute_value_set_string:
372  * @attr: a #GFileAttributeValue.
373  * @string:
374  * 
375  **/
376 void
377 g_file_attribute_value_set_string (GFileAttributeValue *attr,
378                                    const char          *string)
379 {
380   g_return_if_fail (attr != NULL);
381   g_return_if_fail (string != NULL);
382
383   g_file_attribute_value_clear (attr);
384   attr->type = G_FILE_ATTRIBUTE_TYPE_STRING;
385   attr->u.string = g_strdup (string);
386 }
387
388 /**
389  * g_file_attribute_value_set_byte_string:
390  * @attr: a #GFileAttributeValue.
391  * @string:
392  * 
393  **/
394 void
395 g_file_attribute_value_set_byte_string (GFileAttributeValue *attr,
396                                         const char          *string)
397 {
398   g_return_if_fail (attr != NULL);
399   g_return_if_fail (string != NULL);
400
401   g_file_attribute_value_clear (attr);
402   attr->type = G_FILE_ATTRIBUTE_TYPE_BYTE_STRING;
403   attr->u.string = g_strdup (string);
404 }
405
406 /**
407  * g_file_attribute_value_set_boolean:
408  * @attr: a #GFileAttributeValue.
409  * @value:
410  *  
411  **/
412 void
413 g_file_attribute_value_set_boolean (GFileAttributeValue *attr,
414                                     gboolean             value)
415 {
416   g_return_if_fail (attr != NULL);
417
418   g_file_attribute_value_clear (attr);
419   attr->type = G_FILE_ATTRIBUTE_TYPE_BOOLEAN;
420   attr->u.boolean = !!value;
421 }
422
423 /**
424  * g_file_attribute_value_set_uint32:
425  * @attr: a #GFileAttributeValue.
426  * @value:
427  * 
428  **/ 
429 void
430 g_file_attribute_value_set_uint32 (GFileAttributeValue *attr,
431                                    guint32              value)
432 {
433   g_return_if_fail (attr != NULL);
434
435   g_file_attribute_value_clear (attr);
436   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT32;
437   attr->u.uint32 = value;
438 }
439
440 /**
441  * g_file_attribute_value_set_int32:
442  * @attr: a #GFileAttributeValue.
443  * @value:
444  *  
445  **/
446 void
447 g_file_attribute_value_set_int32 (GFileAttributeValue *attr,
448                                   gint32               value)
449 {
450   g_return_if_fail (attr != NULL);
451
452   g_file_attribute_value_clear (attr);
453   attr->type = G_FILE_ATTRIBUTE_TYPE_INT32;
454   attr->u.int32 = value;
455 }
456
457 /**
458  * g_file_attribute_value_set_uint64:
459  * @attr: a #GFileAttributeValue.
460  * @value:
461  * 
462  **/
463 void
464 g_file_attribute_value_set_uint64 (GFileAttributeValue *attr,
465                                    guint64              value)
466 {
467   g_return_if_fail (attr != NULL);
468
469   g_file_attribute_value_clear (attr);
470   attr->type = G_FILE_ATTRIBUTE_TYPE_UINT64;
471   attr->u.uint64 = value;
472 }
473
474 /**
475  * g_file_attribute_value_set_int64:
476  * @attr: a #GFileAttributeValue.
477  * @value: a #gint64 to set the value to.
478  *  
479  **/
480 void
481 g_file_attribute_value_set_int64 (GFileAttributeValue *attr,
482                                   gint64               value)
483 {
484   g_return_if_fail (attr != NULL);
485
486   g_file_attribute_value_clear (attr);
487   attr->type = G_FILE_ATTRIBUTE_TYPE_INT64;
488   attr->u.int64 = value;
489 }
490
491 /**
492  * g_file_attribute_value_set_object:
493  * @attr: a #GFileAttributeValue.
494  * @obj: a #GObject.
495  *
496  * Sets the file attribute @attr to contain the value @obj.
497  * The @attr references the object internally.
498  * 
499  **/
500 void
501 g_file_attribute_value_set_object (GFileAttributeValue *attr,
502                                    GObject             *obj)
503 {
504   g_return_if_fail (attr != NULL);
505   g_return_if_fail (obj != NULL);
506
507   g_file_attribute_value_clear (attr);
508   attr->type = G_FILE_ATTRIBUTE_TYPE_OBJECT;
509   attr->u.obj = g_object_ref (obj);
510 }
511
512 typedef struct {
513   GFileAttributeInfoList public;
514   GArray *array;
515   int ref_count;
516 } GFileAttributeInfoListPriv;
517
518 static void
519 list_update_public (GFileAttributeInfoListPriv *priv)
520 {
521   priv->public.infos = (GFileAttributeInfo *)priv->array->data;
522   priv->public.n_infos = priv->array->len;
523 }
524
525 /**
526  * g_file_attribute_info_list_new:
527  * 
528  * Returns a new #GFileAttributeInfoList.
529  **/
530 GFileAttributeInfoList *
531 g_file_attribute_info_list_new (void)
532 {
533   GFileAttributeInfoListPriv *priv;
534
535   priv = g_new0 (GFileAttributeInfoListPriv, 1);
536   
537   priv->ref_count = 1;
538   priv->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
539   
540   list_update_public (priv);
541   
542   return (GFileAttributeInfoList *)priv;
543 }
544
545 /**
546  * g_file_attribute_info_list_dup:
547  * @list: a #GFileAttributeInfoList to duplicate.
548  * 
549  * Returns a duplicate of the given @list. 
550  **/
551 GFileAttributeInfoList *
552 g_file_attribute_info_list_dup (GFileAttributeInfoList *list)
553 {
554   GFileAttributeInfoListPriv *new;
555   int i;
556   
557   g_return_val_if_fail (list != NULL, NULL);
558
559   new = g_new0 (GFileAttributeInfoListPriv, 1);
560   new->ref_count = 1;
561   new->array = g_array_new (TRUE, FALSE, sizeof (GFileAttributeInfo));
562
563   g_array_set_size (new->array, list->n_infos);
564   list_update_public (new);
565   for (i = 0; i < list->n_infos; i++)
566     {
567       new->public.infos[i].name = g_strdup (list->infos[i].name);
568       new->public.infos[i].type = list->infos[i].type;
569       new->public.infos[i].flags = list->infos[i].flags;
570     }
571   
572   return (GFileAttributeInfoList *)new;
573 }
574
575 /**
576  * g_file_attribute_info_list_ref:
577  * @list: a #GFileAttributeInfoList to reference.
578  * 
579  * Returns: #GFileAttributeInfoList or %NULL on error.
580  **/
581 GFileAttributeInfoList *
582 g_file_attribute_info_list_ref (GFileAttributeInfoList *list)
583 {
584   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
585   
586   g_return_val_if_fail (list != NULL, NULL);
587   g_return_val_if_fail (priv->ref_count > 0, NULL);
588   
589   g_atomic_int_inc (&priv->ref_count);
590   
591   return list;
592 }
593
594 /**
595  * g_file_attribute_info_list_unref:
596  * @list: The #GFileAttributeInfoList to unreference.
597  * 
598  * Removes a reference from the given @list. If the reference count
599  * falls to zero, the @list is deleted.
600  **/
601 void
602 g_file_attribute_info_list_unref (GFileAttributeInfoList *list)
603 {
604   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
605   int i;
606   
607   g_return_if_fail (list != NULL);
608   g_return_if_fail (priv->ref_count > 0);
609   
610   if (g_atomic_int_dec_and_test (&priv->ref_count))
611     {
612       for (i = 0; i < list->n_infos; i++)
613         g_free (list->infos[i].name);
614       g_array_free (priv->array, TRUE);
615     }
616 }
617
618 static int
619 g_file_attribute_info_list_bsearch (GFileAttributeInfoList *list,
620                                     const char             *name)
621 {
622   int start, end, mid;
623   
624   start = 0;
625   end = list->n_infos;
626
627   while (start != end)
628     {
629       mid = start + (end - start) / 2;
630
631       if (strcmp (name, list->infos[mid].name) < 0)
632         end = mid;
633       else if (strcmp (name, list->infos[mid].name) > 0)
634         start = mid + 1;
635       else
636         return mid;
637     }
638   return start;
639 }
640
641 /**
642  * g_file_attribute_info_list_lookup:
643  * @list: a #GFileAttributeInfoList.
644  * @name: the name of the attribute to lookup.
645  * 
646  * Returns: a #GFileAttributeInfo for the @name, or %NULL if an 
647  * attribute isn't found.
648  **/
649 const GFileAttributeInfo *
650 g_file_attribute_info_list_lookup (GFileAttributeInfoList *list,
651                                    const char             *name)
652 {
653   int i;
654   
655   g_return_val_if_fail (list != NULL, NULL);
656   g_return_val_if_fail (name != NULL, NULL);
657   
658   i = g_file_attribute_info_list_bsearch (list, name);
659
660   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
661     return &list->infos[i];
662   
663   return NULL;
664 }
665
666 /**
667  * g_file_attribute_info_list_add:
668  * @list: a #GFileAttributeInfoList.
669  * @name: the name of the attribute to add.
670  * @type: the #GFileAttributeType for the attribute.
671  * @flags: #GFileAttributeFlags for the attribute.
672  * 
673  * Adds a new attribute with @name to the @list, setting
674  * its @type and @flags. 
675  * 
676  **/
677 void
678 g_file_attribute_info_list_add    (GFileAttributeInfoList *list,
679                                    const char             *name,
680                                    GFileAttributeType      type,
681                                    GFileAttributeFlags     flags)
682 {
683   GFileAttributeInfoListPriv *priv = (GFileAttributeInfoListPriv *)list;
684   GFileAttributeInfo info;
685   int i;
686   
687   g_return_if_fail (list != NULL);
688   g_return_if_fail (name != NULL);
689
690   i = g_file_attribute_info_list_bsearch (list, name);
691
692   if (i < list->n_infos && strcmp (list->infos[i].name, name) == 0)
693     {
694       list->infos[i].type = type;
695       return;
696     }
697
698   info.name = g_strdup (name);
699   info.type = type;
700   info.flags = flags;
701   g_array_insert_vals (priv->array, i, &info, 1);
702
703   list_update_public (priv);
704 }