OSDN Git Service

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