OSDN Git Service

import 0.9.3
[handbrake-jp/handbrake-jp.git] / gtk / src / values.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * presets.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * presets.c is free software.
7  * 
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  * 
13  */
14
15 #include <glib.h>
16 #include <glib-object.h>
17 #include <string.h>
18 #include "values.h"
19
20 static void dict_delete_key(gpointer data);
21 static void dict_delete_value(gpointer data);
22
23 GValue*
24 ghb_value_new(GType gtype)
25 {
26         GValue *gval = g_malloc0(sizeof(GValue));
27         g_value_init(gval, gtype);
28         return gval;
29 }
30
31 void
32 ghb_value_free(GValue *gval)
33 {
34         if (gval == NULL) return;
35         g_value_unset(gval);
36         g_free(gval);
37 }
38
39 GValue*
40 ghb_value_dup(const GValue *val)
41 {
42         if (val == NULL) return NULL;
43         GValue *copy = ghb_value_new(G_VALUE_TYPE(val));
44         g_value_copy(val, copy);
45         return copy;
46 }
47
48 void
49 debug_show_type(GType tp)
50 {
51         const gchar *str = "unknown";
52         if (tp == G_TYPE_STRING)
53         {
54                 str ="string";
55         }
56         else if (tp == G_TYPE_INT)
57         {
58                 str ="int";
59         }
60         else if (tp == G_TYPE_INT64)
61         {
62                 str ="int64";
63         }
64         else if (tp == G_TYPE_DOUBLE)
65         {
66                 str ="double";
67         }
68         else if (tp == G_TYPE_BOOLEAN)
69         {
70                 str ="bool";
71         }
72         else if (tp == ghb_array_get_type())
73         {
74                 str ="array";
75         }
76         else if (tp == ghb_dict_get_type())
77         {
78                 str ="dict";
79         }
80         g_debug("%s", str);
81 }
82
83 gint
84 ghb_value_int(const GValue *val)
85 {
86         gint result;
87
88         if (val == NULL) return 0;
89         GValue xform = {0,};
90         if (G_VALUE_TYPE(val) != G_TYPE_INT)
91         {
92                 g_value_init(&xform, G_TYPE_INT);
93                 if (!g_value_transform(val, &xform))
94                 {
95                         debug_show_type(G_VALUE_TYPE(val));
96                         g_warning("int can't transform");
97                         return 0;
98                 }
99                 result = g_value_get_int(&xform);
100                 g_value_unset(&xform);
101         }
102         else
103         {
104                 result = g_value_get_int(val);
105         }
106         return result;
107 }
108
109 gint64
110 ghb_value_int64(const GValue *val)
111 {
112         gint64 result;
113
114         if (val == NULL) return 0;
115         GValue xform = {0,};
116         if (G_VALUE_TYPE(val) != G_TYPE_INT64)
117         {
118                 g_value_init(&xform, G_TYPE_INT64);
119                 if (!g_value_transform(val, &xform))
120                 {
121                         debug_show_type(G_VALUE_TYPE(val));
122                         g_warning("int64 can't transform");
123                         return 0;
124                 }
125                 result = g_value_get_int64(&xform);
126                 g_value_unset(&xform);
127         }
128         else
129         {
130                 result = g_value_get_int64(val);
131         }
132         return result;
133 }
134
135 gdouble
136 ghb_value_double(const GValue *val)
137 {
138         gdouble result;
139
140         if (val == NULL) return 0;
141         GValue xform = {0,};
142         if (G_VALUE_TYPE(val) != G_TYPE_DOUBLE)
143         {
144                 g_value_init(&xform, G_TYPE_DOUBLE);
145                 if (!g_value_transform(val, &xform))
146                 {
147                         debug_show_type(G_VALUE_TYPE(val));
148                         g_warning("double can't transform");
149                         return 0;
150                 }
151                 result = g_value_get_double(&xform);
152                 g_value_unset(&xform);
153         }
154         else
155         {
156                 result = g_value_get_double(val);
157         }
158         return result;
159 }
160
161 gchar*
162 ghb_value_string(const GValue *val)
163 {
164         gchar *result;
165
166         if (val == NULL) return 0;
167         GValue xform = {0,};
168         if (G_VALUE_TYPE(val) != G_TYPE_STRING)
169         {
170                 g_value_init(&xform, G_TYPE_STRING);
171                 if (!g_value_transform(val, &xform))
172                 {
173                         debug_show_type(G_VALUE_TYPE(val));
174                         g_warning("string can't transform");
175                         return NULL;
176                 }
177                 result = g_strdup(g_value_get_string(&xform));
178                 g_value_unset(&xform);
179         }
180         else
181         {
182                 result = g_strdup(g_value_get_string(val));
183         }
184         return result;
185 }
186
187 gboolean
188 ghb_value_boolean(const GValue *val)
189 {
190         gboolean result;
191
192         if (val == NULL) return FALSE;
193         GValue xform = {0,};
194         if (G_VALUE_TYPE(val) != G_TYPE_BOOLEAN)
195         {
196                 g_value_init(&xform, G_TYPE_BOOLEAN);
197                 if (!g_value_transform(val, &xform))
198                 {
199                         debug_show_type(G_VALUE_TYPE(val));
200                         g_warning("boolean can't transform");
201                         return FALSE;
202                 }
203                 result = g_value_get_boolean(&xform);
204                 g_value_unset(&xform);
205         }
206         else
207         {
208                 result = g_value_get_boolean(val);
209         }
210         return result;
211 }
212
213 gint
214 ghb_value_cmp(const GValue *vala, const GValue *valb)
215 {
216         GType typa;
217         GType typb;
218
219         typa = G_VALUE_TYPE(vala);
220         typb = G_VALUE_TYPE(valb);
221         if (typa != typb)
222         {
223                 return 1;
224         }
225         
226         if (typa == G_TYPE_STRING)
227         {
228                 char *stra, *strb;
229                 gint res;
230                 stra = ghb_value_string(vala);
231                 strb = ghb_value_string(valb);
232                 if (stra == NULL && strb == NULL)
233                         return 0;
234                 if (stra == NULL)
235                 {
236                         g_free(strb);
237                         return -1;
238                 }
239                 if (strb == NULL)
240                 {
241                         g_free(stra);
242                         return 1;
243                 }
244                 res =  strcmp(stra, strb);
245                 g_free(stra);
246                 g_free(strb);
247                 return res;
248         }
249         else if (typa == G_TYPE_INT64 || typa == G_TYPE_INT || 
250                         typa == G_TYPE_BOOLEAN)
251         {
252                 return ghb_value_int64(vala) - ghb_value_int64(valb);
253         }
254         else if (typa == G_TYPE_DOUBLE || typa == G_TYPE_FLOAT)
255         {
256                 return ghb_value_double(vala) - ghb_value_double(valb);
257         }
258         else if (typa == ghb_array_get_type())
259         {
260                 // Cheating here.  Just assume they are different.
261                 // Maybe later I'll recurse through these
262                 return 1;
263         }
264         else if (typa == ghb_dict_get_type())
265         {
266                 // Cheating here.  Just assume they are different.
267                 // Maybe later I'll recurse through these
268                 return 1;
269         }
270         else
271         {
272                 g_warning("ghb_value_cmp: unrecognized type");
273                 return 1;
274         }
275         return 0;
276 }
277
278 GValue*
279 ghb_string_value(const gchar *str)
280 {
281         static GValue gval = {0,};
282         if (!G_IS_VALUE(&gval))
283                 g_value_init(&gval, G_TYPE_STRING);
284         g_value_set_string(&gval, str);
285         return &gval;
286 }
287
288 GValue*
289 ghb_int64_value(gint64 ival)
290 {
291         static GValue gval = {0,};
292         if (!G_IS_VALUE(&gval))
293                 g_value_init(&gval, G_TYPE_INT64);
294         g_value_set_int64(&gval, ival);
295         return &gval;
296 }
297
298 GValue*
299 ghb_int_value(gint ival)
300 {
301         static GValue gval = {0,};
302         if (!G_IS_VALUE(&gval))
303                 g_value_init(&gval, G_TYPE_INT64);
304         g_value_set_int64(&gval, (gint64)ival);
305         return &gval;
306 }
307
308 GValue*
309 ghb_double_value(gdouble dval)
310 {
311         static GValue gval = {0,};
312         if (!G_IS_VALUE(&gval))
313                 g_value_init(&gval, G_TYPE_DOUBLE);
314         g_value_set_double(&gval, dval);
315         return &gval;
316 }
317
318 GValue*
319 ghb_boolean_value(gboolean bval)
320 {
321         static GValue gval = {0,};
322         if (!G_IS_VALUE(&gval))
323                 g_value_init(&gval, G_TYPE_BOOLEAN);
324         g_value_set_boolean(&gval, bval);
325         return &gval;
326 }
327
328 GValue*
329 ghb_string_value_new(const gchar *str)
330 {
331         if (str == NULL) str = "";
332         GValue *gval = ghb_value_new(G_TYPE_STRING);
333         g_value_set_string(gval, str);
334         return gval;
335 }
336
337 GValue*
338 ghb_int64_value_new(gint64 ival)
339 {
340         GValue *gval = ghb_value_new(G_TYPE_INT64);
341         g_value_set_int64(gval, ival);
342         return gval;
343 }
344
345 GValue*
346 ghb_int_value_new(gint ival)
347 {
348         GValue *gval = ghb_value_new(G_TYPE_INT64);
349         g_value_set_int64(gval, ival);
350         return gval;
351 }
352
353 GValue*
354 ghb_double_value_new(gdouble dval)
355 {
356         GValue *gval = ghb_value_new(G_TYPE_DOUBLE);
357         g_value_set_double(gval, dval);
358         return gval;
359 }
360
361 GValue*
362 ghb_boolean_value_new(gboolean bval)
363 {
364         GValue *gval = ghb_value_new(G_TYPE_BOOLEAN);
365         g_value_set_boolean(gval, bval);
366         return gval;
367 }
368
369 GValue*
370 ghb_dict_value_new()
371 {
372         GHashTable *dict;
373         GValue *gval = ghb_value_new(ghb_dict_get_type());
374         dict = g_hash_table_new_full(g_str_hash, g_str_equal,
375                                                                 dict_delete_key, dict_delete_value);
376         g_value_take_boxed(gval, dict);
377         return gval;
378 }
379
380 GValue*
381 ghb_array_value_new(guint size)
382 {
383         GValue *gval = ghb_value_new(ghb_array_get_type());
384         GArray *array;
385
386         array = g_array_sized_new(FALSE, FALSE, sizeof(GValue*), size);
387         g_value_take_boxed(gval, array);
388         return gval;
389 }
390
391 void
392 ghb_array_value_reset(GValue *gval, guint size)
393 {
394         GArray *array;
395         g_value_reset(gval);
396         array = g_array_sized_new(FALSE, FALSE, sizeof(GValue*), size);
397         g_value_take_boxed(gval, array);
398 }
399
400 GValue* 
401 ghb_date_value_new(GDate *date)
402 {
403         GValue *gval = ghb_value_new(g_date_get_type());
404         g_value_set_boxed(gval, date);
405         return gval;
406 }
407
408 GValue* 
409 ghb_rawdata_value_new(ghb_rawdata_t *data)
410 {
411         GValue *gval = ghb_value_new(ghb_rawdata_get_type());
412         g_value_take_boxed(gval, data);
413         return gval;
414 }
415
416 static gpointer
417 rawdata_copy(gpointer boxed)
418 {
419         const ghb_rawdata_t *data = (const ghb_rawdata_t*)boxed;
420         ghb_rawdata_t *copy = g_malloc(sizeof(ghb_rawdata_t));
421         copy->size = data->size;
422         if (data->data)
423         {
424                 copy->data = g_malloc(data->size);
425                 memcpy(copy->data, data->data, data->size);
426         }
427         else
428         {
429                 copy->data = NULL;
430                 copy->size = 0;
431         }
432         return copy;
433 }
434
435 static void
436 rawdata_free(gpointer boxed)
437 {
438         ghb_rawdata_t *data = (ghb_rawdata_t*)boxed;
439         if (data->data) g_free(data->data);
440         g_free(data);
441 }
442
443
444 GType
445 ghb_rawdata_get_type(void)
446 {
447         static GType type_id = 0;
448         if (!type_id)
449                 type_id = g_boxed_type_register_static(g_intern_static_string("GHBData"),
450                         (GBoxedCopyFunc) rawdata_copy,
451                         (GBoxedFreeFunc) rawdata_free);
452         return type_id;
453 }
454
455 static void
456 dict_delete_key(gpointer data)
457 {
458         if (data == NULL)
459         {
460                 g_warning("dict frees null key");
461                 return;
462         }
463         g_free(data);
464 }
465
466 static void
467 dict_delete_value(gpointer data)
468 {
469         GValue *gval = (GValue*)data;
470         if (gval == NULL)
471         {
472                 g_warning("dict frees null value");
473                 return;
474         }
475         ghb_value_free(gval);
476 }
477
478 static gpointer
479 dict_copy(gpointer boxed)
480 {
481         GHashTable *dict = (GHashTable*)boxed;
482         GHashTable *copy;
483         GHashTableIter iter;
484         gchar *key;
485         GValue *gval;
486
487         copy = g_hash_table_new_full(g_str_hash, g_str_equal,
488                                                                 dict_delete_key, dict_delete_value);
489
490         g_hash_table_iter_init(&iter, dict);
491         // middle (void*) cast prevents gcc warning "defreferencing type-punned
492         // pointer will break strict-aliasing rules"
493         while (g_hash_table_iter_next(
494                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
495         {
496                 g_hash_table_insert(copy, g_strdup(key), ghb_value_dup(gval));
497         }
498         return copy;
499 }
500
501 static void
502 dict_free(gpointer boxed)
503 {
504         GHashTable *dict = (GHashTable*)boxed;
505         g_hash_table_destroy(dict);
506 }
507
508
509 GType
510 ghb_dict_get_type(void)
511 {
512         static GType type_id = 0;
513         if (!type_id)
514                 type_id = g_boxed_type_register_static(
515                                                 g_intern_static_string("GHBDict"),
516                                                 (GBoxedCopyFunc) dict_copy,
517                                                 (GBoxedFreeFunc) dict_free);
518         return type_id;
519 }
520
521 void
522 ghb_dict_insert(GValue *gval, gchar *key, GValue *val)
523 {
524         GHashTable *dict = g_value_get_boxed(gval);
525         g_hash_table_insert(dict, key, val);
526 }
527
528 void
529 ghb_dict_iter_init(GHashTableIter *iter, GValue *gval)
530 {
531         GHashTable *dict = g_value_get_boxed(gval);
532         g_hash_table_iter_init(iter, dict);
533 }
534
535 GValue*
536 ghb_dict_lookup(GValue *gval, const gchar *key)
537 {
538         GHashTable *dict = g_value_get_boxed(gval);
539         return g_hash_table_lookup(dict, key);
540 }
541
542 gboolean
543 ghb_dict_remove(GValue *gval, const gchar *key)
544 {
545         GHashTable *dict = g_value_get_boxed(gval);
546         return g_hash_table_remove(dict, key);
547 }
548
549 static gpointer
550 array_copy(gpointer boxed)
551 {
552         const GArray *array = (const GArray*)boxed;
553         GArray *copy = g_array_new(FALSE, FALSE, sizeof(GValue*));
554
555         GValue *gval, *gval_copy;
556         gint ii;
557
558         for (ii = 0; ii < array->len; ii++)
559         {
560                 gval = g_array_index(array, GValue*, ii);
561                 if (gval)
562                 {
563                         gval_copy = ghb_value_dup(gval);
564                         g_array_append_val(copy, gval_copy);
565                 }
566         }
567         return copy;
568 }
569
570 static void
571 array_free(gpointer boxed)
572 {
573         GArray *array = (GArray*)boxed;
574         GValue *gval;
575         gint ii;
576
577         for (ii = 0; ii < array->len; ii++)
578         {
579                 gval = g_array_index(array, GValue*, ii);
580                 if (gval)
581                 {
582                         ghb_value_free(gval);
583                 }
584         }
585         g_array_free(array, TRUE);
586 }
587
588
589 GType
590 ghb_array_get_type(void)
591 {
592         static GType type_id = 0;
593         if (!type_id)
594                 type_id = g_boxed_type_register_static(
595                                                 g_intern_static_string("GHBArray"),
596                                                 (GBoxedCopyFunc) array_copy,
597                                                 (GBoxedFreeFunc) array_free);
598         return type_id;
599 }
600
601 GValue*
602 ghb_array_get_nth(const GValue *gval, gint ii)
603 {
604         GArray *arr = g_value_get_boxed(gval);
605         return g_array_index(arr, GValue*, ii);
606 }
607
608 void
609 ghb_array_insert(GValue *gval, guint ii, GValue *val)
610 {
611         GArray *arr = g_value_get_boxed(gval);
612         // A little nastyness here.  The array pointer
613         // can change when the array changes size.  So
614         // I must re-box it in the GValue each time.
615         arr = g_array_insert_val(arr, ii, val);
616         memset(gval, 0, sizeof(GValue));
617         g_value_init(gval, ghb_array_get_type());
618         g_value_take_boxed(gval, arr);
619 }
620
621 void
622 ghb_array_append(GValue *gval, GValue *val)
623 {
624         GArray *arr = g_value_get_boxed(gval);
625         // A little nastyness here.  The array pointer
626         // can change when the array changes size.  So
627         // I must re-box it in the GValue each time.
628         arr = g_array_append_val(arr, val);
629         memset(gval, 0, sizeof(GValue));
630         g_value_init(gval, ghb_array_get_type());
631         g_value_take_boxed(gval, arr);
632 }
633
634 void
635 ghb_array_remove(GValue *gval, guint ii)
636 {
637         GArray *arr = g_value_get_boxed(gval);
638         // A little nastyness here.  The array pointer
639         // can change when the array changes size.  So
640         // I must re-box it in the GValue each time.
641         arr = g_array_remove_index(arr, ii);
642         memset(gval, 0, sizeof(GValue));
643         g_value_init(gval, ghb_array_get_type());
644         g_value_take_boxed(gval, arr);
645 }
646
647 void
648 ghb_array_replace(GValue *gval, guint ii, GValue *val)
649 {
650         GArray *arr = g_value_get_boxed(gval);
651         // A little nastyness here.  The array pointer
652         // can change when the array changes size.  So
653         // I must re-box it in the GValue each time.
654         if (ii >= arr->len) return;
655         ghb_value_free(((GValue**)arr->data)[ii]);
656         ((GValue**)arr->data)[ii] = val;
657 }
658
659 void
660 ghb_array_copy(GValue *arr1, GValue *arr2, gint count)
661 {
662         gint len, ii;
663
664         // empty the first array if it is not already empty
665         len = ghb_array_len(arr1);
666         for (ii = 0; ii < len; ii++)
667                 ghb_array_remove(arr1, 0);
668
669         len = ghb_array_len(arr2);
670         count = MIN(count, len);
671         for (ii = 0; ii < count; ii++)
672                 ghb_array_append(arr1, ghb_value_dup(ghb_array_get_nth(arr2, ii)));
673 }
674
675 gint
676 ghb_array_len(const GValue *gval)
677 {
678         if (gval == NULL) return 0;
679         GArray *arr = g_value_get_boxed(gval);
680         return arr->len;
681 }
682
683 static void
684 xform_string_int(const GValue *sval, GValue *ival)
685 {
686         gchar *end;
687
688         const gchar *str = g_value_get_string(sval);
689         gint val = g_strtod(str, &end);
690         if (*end)
691                 val = (guint)(~0)>>1;
692         g_value_set_int(ival, val);
693 }
694
695 static void
696 xform_string_int64(const GValue *sval, GValue *ival)
697 {
698         gchar *end;
699         const gchar *str = g_value_get_string(sval);
700         gint64 val = g_strtod(str, &end);
701         if (*end)
702                 val = (guint64)(~0L)>>1;
703         g_value_set_int64(ival, val);
704 }
705
706 static void
707 xform_string_double(const GValue *sval, GValue *dval)
708 {
709         const gchar *str = g_value_get_string(sval);
710         double val = g_strtod(str, NULL);
711         g_value_set_double(dval, val);
712 }
713
714 static void
715 xform_boolean_double(const GValue *bval, GValue *dval)
716 {
717         gboolean b = g_value_get_boolean(bval);
718         double val = b;
719         g_value_set_double(dval, val);
720 }
721
722 void
723 ghb_register_transforms()
724 {
725         g_value_register_transform_func(G_TYPE_STRING, G_TYPE_INT64, 
726                                                                 xform_string_int64);
727         g_value_register_transform_func(G_TYPE_STRING, G_TYPE_INT, 
728                                                                 xform_string_int);
729         g_value_register_transform_func(G_TYPE_STRING, G_TYPE_DOUBLE, 
730                                                                 xform_string_double);
731         g_value_register_transform_func(G_TYPE_BOOLEAN, G_TYPE_DOUBLE, 
732                                                                 xform_boolean_double);
733 }