OSDN Git Service

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