Remove arg_info param from seed_gi_make_argument().
[gnome.seed] / libseed / seed-types.c
1 /* -*- mode: C; indent-tabs-mode: t; tab-width: 8; c-basic-offset: 2; -*- */
2
3 /*
4  * This file is part of Seed, the GObject Introspection<->Javascript bindings.
5  *
6  * Seed is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation, either version 3 of
9  * the License, or (at your option) any later version.
10  * Seed 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
13  * GNU Lesser General Public License for more details.
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with Seed.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Copyright (C) Robert Carr 2009 <carrr@rpi.edu>
18  */
19
20 #include "seed-private.h"
21 #include <dlfcn.h>
22
23 JSClassRef gobject_class;
24 JSClassRef gobject_method_class;
25 JSClassRef gobject_constructor_class;
26 JSClassRef seed_callback_class;
27 JSClassRef gobject_init_method_class;
28 SeedEngine *eng;
29
30 static gboolean
31 seed_value_is_gobject (JSContextRef ctx, JSValueRef value)
32 {
33   if (!JSValueIsObject (ctx, value) || JSValueIsNull (ctx, value))
34     return FALSE;
35
36   return JSValueIsObjectOfClass (ctx, value, gobject_class);
37 }
38
39 void
40 seed_toggle_ref (gpointer data, GObject * object, gboolean is_last_ref)
41 {
42   JSValueRef wrapper;
43
44   wrapper = (JSValueRef) data;
45
46   if (is_last_ref)
47     {
48       JSValueUnprotect (eng->context, wrapper);
49     }
50   else
51     {
52       JSValueProtect (eng->context, wrapper);
53     }
54 }
55
56 static void
57 seed_gobject_destroyed (gpointer object)
58 {
59   JSValueUnprotect (eng->context, (JSValueRef) object);
60   JSObjectSetPrivate ((JSObjectRef) object, 0);
61 }
62
63 JSObjectRef
64 seed_make_wrapper_for_type (JSContextRef ctx, GType type)
65 {
66   JSClassRef class;
67   JSObjectRef ret;
68   JSValueRef prototype;
69
70   class = seed_gobject_get_class_for_gtype (ctx, type);
71
72   while (!class && (type = g_type_parent (type)))
73     class = seed_gobject_get_class_for_gtype (ctx, type);
74
75   prototype = seed_gobject_get_prototype_for_gtype (type);
76   ret = JSObjectMake (ctx, class, NULL);
77   if (prototype)
78     JSObjectSetPrototype (ctx, ret, prototype);
79   else
80     g_assert_not_reached ();
81
82   return ret;
83 }
84
85 static JSValueRef
86 seed_wrap_object (JSContextRef ctx, GObject * object)
87 {
88   JSValueRef user_data;
89   JSObjectRef js_ref;
90   GType type;
91
92   type = G_OBJECT_TYPE (object);
93
94   user_data = (JSValueRef) g_object_get_qdata (object, js_ref_quark);
95
96   if (user_data)
97     return user_data;
98
99   if (seed_next_gobject_wrapper)
100     js_ref = seed_next_gobject_wrapper;
101   else
102     js_ref = seed_make_wrapper_for_type (ctx, type);
103
104   JSObjectSetPrivate (js_ref, object);
105
106   g_object_set_qdata_full (object, js_ref_quark, (gpointer) js_ref,
107                            seed_gobject_destroyed);
108
109   JSValueProtect (eng->context, js_ref);
110   g_object_add_toggle_ref (object, seed_toggle_ref, (gpointer) js_ref);
111
112   seed_add_signals_to_object (ctx, js_ref, object);
113
114   seed_next_gobject_wrapper = NULL;
115
116   return js_ref;
117 }
118
119 static gboolean
120 seed_release_arg (GITransfer transfer,
121                   GITypeInfo * type_info, GITypeTag type_tag, GArgument * arg)
122 {
123   GType gtype;
124   GITypeInfo *param_type;
125   GIBaseInfo *interface_info;
126   GValue *gval;
127
128   switch (type_tag)
129     {
130     case GI_TYPE_TAG_UTF8:
131     case GI_TYPE_TAG_FILENAME:
132       g_free (arg->v_string);
133       break;
134     case GI_TYPE_TAG_ARRAY:
135       if (arg->v_pointer)
136         {
137           param_type = g_type_info_get_param_type (type_info, 0);
138
139           switch (g_type_info_get_tag (param_type))
140             {
141             case GI_TYPE_TAG_UTF8:
142               if (transfer == GI_TRANSFER_EVERYTHING)
143                 g_strfreev (arg->v_pointer);
144               else if (transfer == GI_TRANSFER_CONTAINER)
145                 g_free (arg->v_pointer);
146               break;
147             case GI_TYPE_TAG_GTYPE:
148             case GI_TYPE_TAG_FLOAT:
149             case GI_TYPE_TAG_UINT8:
150               g_free (arg->v_pointer);
151               break;
152             case GI_TYPE_TAG_INTERFACE:
153               break;
154             default:
155               g_assert_not_reached ();
156             }
157
158           g_base_info_unref ((GIBaseInfo *) param_type);
159         }
160       break;
161     case GI_TYPE_TAG_INTERFACE:
162       {
163         if (arg->v_pointer)
164           {
165             interface_info = g_type_info_get_interface (type_info);
166
167             gtype =
168               g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)
169                                                  interface_info);
170
171             if (g_type_is_a (gtype, G_TYPE_OBJECT)
172                 || g_type_is_a (gtype, G_TYPE_INTERFACE))
173               {
174                 SEED_NOTE (MISC,
175                            "Unreffing object of type: %s in"
176                            "argument release. Reference count: %d\n",
177                            g_type_name (G_OBJECT_TYPE
178                                         (G_OBJECT (arg->v_pointer))),
179                            G_OBJECT (arg->v_pointer)->ref_count);
180                 g_object_unref (G_OBJECT (arg->v_pointer));
181               }
182             else if (g_type_is_a (gtype, G_TYPE_VALUE))
183               {
184                 gval = (GValue *) arg->v_pointer;
185                 // Free/unref the GValue's contents.
186                 g_value_unset (gval);
187                 // Free the GValue.
188                 g_slice_free1 (sizeof (GValue), gval);
189               }
190             else if (g_type_is_a (gtype, G_TYPE_CLOSURE))
191               {
192                 g_closure_unref (arg->v_pointer);
193               }
194
195             g_base_info_unref (interface_info);
196           }
197         break;
198       }
199     default:
200       break;
201
202     }
203
204   return TRUE;
205 }
206
207 gboolean
208 seed_gi_release_arg (GITransfer transfer,
209                      GITypeInfo * type_info, GArgument * arg)
210 {
211   GITypeTag type_tag;
212
213   if (transfer == GI_TRANSFER_NOTHING)
214     return TRUE;
215
216   type_tag = g_type_info_get_tag ((GITypeInfo *) type_info);
217
218   return seed_release_arg (transfer, type_info, type_tag, arg);
219 }
220
221 gboolean
222 seed_gi_release_in_arg (GITransfer transfer,
223                         GITypeInfo * type_info, GArgument * arg)
224 {
225   GITypeTag type_tag;
226
227   if (transfer == GI_TRANSFER_EVERYTHING)
228     return TRUE;
229
230   type_tag = g_type_info_get_tag ((GITypeInfo *) type_info);
231
232   switch (type_tag)
233     {
234       // TODO: FIXME: Leaaaks?
235     case GI_TYPE_TAG_INTERFACE:
236       {
237         // TODO: FIXME: Need some safe way to look for GClosure.
238         break;
239       }
240     case GI_TYPE_TAG_UTF8:
241     case GI_TYPE_TAG_FILENAME:
242     case GI_TYPE_TAG_ARRAY:
243       return seed_release_arg (GI_TRANSFER_EVERYTHING,
244                                type_info, type_tag, arg);
245     default:
246       break;
247     }
248
249   return TRUE;
250 }
251
252 static JSValueRef
253 seed_gi_make_jsarray (JSContextRef ctx,
254                       void *array,
255                       GITypeInfo * param_type, JSValueRef * exception)
256 {
257   GITypeTag element_type;
258   JSValueRef *elements;
259   guint length, i;
260   gchar **str_array = (gchar **) array;
261   JSValueRef ret = JSValueMakeNull (ctx);
262
263   element_type = g_type_info_get_tag (param_type);
264
265   if (element_type == GI_TYPE_TAG_UTF8)
266     {
267
268       length = g_strv_length (str_array);
269       if (!length)
270         return ret;
271
272       elements = g_alloca (sizeof (JSValueRef) * length);
273       for (i = 0; i < length; ++i)
274         {
275           elements[i] = seed_value_from_string (ctx, str_array[i], exception);
276         }
277
278       ret = (JSValueRef) JSObjectMakeArray (ctx, length, elements, exception);
279     }
280
281   return ret;
282 }
283
284 static gboolean
285 seed_gi_make_array (JSContextRef ctx,
286                     JSValueRef array,
287                     guint length,
288                     GITypeInfo * param_type,
289                     void **array_p, JSValueRef * exception)
290 {
291   GITypeTag element_type;
292   JSValueRef elem;
293   guint i;
294
295   element_type = g_type_info_get_tag (param_type);
296
297   switch (element_type)
298     {
299     case GI_TYPE_TAG_UTF8:
300       {
301         gchar **strresult = g_new0 (gchar *, length + 1);
302
303         for (i = 0; i < length; i++)
304           {
305             elem = JSObjectGetPropertyAtIndex (ctx,
306                                                (JSObjectRef) array,
307                                                i, exception);
308             strresult[i] = seed_value_to_string (ctx, elem, exception);
309           }
310
311         *array_p = strresult;
312       }
313       break;
314     case GI_TYPE_TAG_GTYPE:
315       {
316         GType *typeresult;
317
318         typeresult = g_new0 (GType, length + 1);
319
320         for (i = 0; i < length; i++)
321           {
322             elem = JSObjectGetPropertyAtIndex (ctx,
323                                                (JSObjectRef) array,
324                                                i, exception);
325             typeresult[i] = seed_value_to_int (ctx, elem, exception);
326           }
327
328         *array_p = typeresult;
329       }
330       break;
331     case GI_TYPE_TAG_FLOAT:
332       {
333         gfloat *floatresult;
334
335         floatresult = g_new0 (gfloat, length + 1);
336
337         for (i = 0; i < length; i++)
338           {
339             elem = JSObjectGetPropertyAtIndex (ctx,
340                                                (JSObjectRef) array,
341                                                i, exception);
342             floatresult[i] = seed_value_to_float (ctx, elem, exception);
343           }
344
345         *array_p = floatresult;
346       }
347       break;
348     case GI_TYPE_TAG_DOUBLE:
349       {
350         gdouble *dblresult;
351
352         dblresult = g_new0 (gdouble, length + 1);
353
354         for (i = 0; i < length; i++)
355           {
356             elem = JSObjectGetPropertyAtIndex (ctx,
357                                                (JSObjectRef) array,
358                                                i, exception);
359             dblresult[i] = seed_value_to_double (ctx, elem, exception);
360           }
361
362         *array_p = dblresult;
363       }
364       break;
365     case GI_TYPE_TAG_INT:
366       {
367         gint *intresult;
368
369         intresult = g_new0 (gint, length + 1);
370
371         for (i = 0; i < length; i++)
372           {
373             elem = JSObjectGetPropertyAtIndex (ctx,
374                                                (JSObjectRef) array,
375                                                i, exception);
376             intresult[i] = seed_value_to_int (ctx, elem, exception);
377           }
378
379         *array_p = intresult;
380       }
381       break;
382     case GI_TYPE_TAG_UINT8:
383       {
384         guint8 *guint8result;
385
386         guint8result = g_new0 (guint8, length + 1);
387
388         for (i = 0; i < length; i++)
389           {
390             elem = JSObjectGetPropertyAtIndex (ctx,
391                                                (JSObjectRef) array,
392                                                i, exception);
393             guint8result[i] = seed_value_to_uchar (ctx, elem, exception);
394           }
395
396         *array_p = guint8result;
397       }
398       break;
399     case GI_TYPE_TAG_INTERFACE:
400       {
401         GIBaseInfo *interface = g_type_info_get_interface (param_type);
402         GIInfoType interface_type = g_base_info_get_type (interface);
403         if (interface_type == GI_INFO_TYPE_OBJECT
404             || interface_type == GI_INFO_TYPE_INTERFACE
405             || interface_type == GI_INFO_TYPE_STRUCT)
406           {
407             GType type =
408               g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)
409                                                  interface);
410             if (g_type_is_a (type, G_TYPE_VALUE))
411               {
412                 GValue *gvalresult;
413
414                 // TODO:FIXME: Robb. Valgrind thinks there's a leak here,
415                 //             at least while running Same Seed.
416                 gvalresult = g_new0 (GValue, length + 1);
417
418                 for (i = 0; i < length; i++)
419                   {
420                     elem = JSObjectGetPropertyAtIndex (ctx,
421                                                        (JSObjectRef) array,
422                                                        i, exception);
423                     seed_gvalue_from_seed_value (ctx, elem,
424                                                  (GType) 0,
425                                                  &gvalresult[i], exception);
426                   }
427                 *array_p = gvalresult;
428
429                 g_base_info_unref (interface);
430                 break;
431               }
432           }
433
434         g_base_info_unref (interface);
435       }
436     default:
437       seed_make_exception (ctx, exception, "ArgumentError",
438                            "Unhandled array element type");
439       return FALSE;
440     }
441
442   return TRUE;
443 }
444
445 gboolean
446 seed_gi_make_argument (JSContextRef ctx,
447                        JSValueRef value,
448                        GITypeInfo * type_info,
449                        GArgument * arg,
450                        JSValueRef * exception)
451 {
452   GITypeTag gi_tag = g_type_info_get_tag (type_info);
453
454   // FIXME: Some types are not "nullable", also need to check if argument
455   // can be null before doing this.
456   if (!value || JSValueIsNull (ctx, value))
457     {
458       arg->v_pointer = 0;
459       return 1;
460     }
461
462   switch (gi_tag)
463     {
464     case GI_TYPE_TAG_VOID:
465       break;
466     case GI_TYPE_TAG_BOOLEAN:
467       arg->v_boolean = seed_value_to_boolean (ctx, value, exception);
468       break;
469     case GI_TYPE_TAG_INT8:
470       arg->v_int8 = seed_value_to_char (ctx, value, exception);
471       break;
472     case GI_TYPE_TAG_UINT8:
473       arg->v_uint8 = seed_value_to_uchar (ctx, value, exception);
474       break;
475     case GI_TYPE_TAG_INT16:
476       arg->v_int16 = seed_value_to_int (ctx, value, exception);
477       break;
478     case GI_TYPE_TAG_UINT16:
479       arg->v_uint16 = seed_value_to_uint (ctx, value, exception);
480       break;
481     case GI_TYPE_TAG_INT32:
482       arg->v_int32 = seed_value_to_int (ctx, value, exception);
483       break;
484     case GI_TYPE_TAG_UINT32:
485       arg->v_uint32 = seed_value_to_uint (ctx, value, exception);
486       break;
487     case GI_TYPE_TAG_LONG:
488     case GI_TYPE_TAG_INT64:
489       arg->v_int64 = seed_value_to_long (ctx, value, exception);
490       break;
491     case GI_TYPE_TAG_ULONG:
492     case GI_TYPE_TAG_UINT64:
493       arg->v_uint64 = seed_value_to_ulong (ctx, value, exception);
494       break;
495     case GI_TYPE_TAG_INT:
496       arg->v_int = seed_value_to_int (ctx, value, exception);
497       break;
498     case GI_TYPE_TAG_UINT:
499       arg->v_uint = seed_value_to_uint (ctx, value, exception);
500       break;
501     case GI_TYPE_TAG_SIZE:
502     case GI_TYPE_TAG_SSIZE:
503       arg->v_int = seed_value_to_int (ctx, value, exception);
504       break;
505     case GI_TYPE_TAG_FLOAT:
506       arg->v_float = seed_value_to_float (ctx, value, exception);
507       break;
508     case GI_TYPE_TAG_DOUBLE:
509       arg->v_double = seed_value_to_double (ctx, value, exception);
510       break;
511     case GI_TYPE_TAG_UTF8:
512       arg->v_string = seed_value_to_string (ctx, value, exception);
513       break;
514     case GI_TYPE_TAG_FILENAME:
515       arg->v_string = seed_value_to_filename (ctx, value, exception);
516       break;
517     case GI_TYPE_TAG_GTYPE:
518       arg->v_int = seed_value_to_int (ctx, value, exception);
519       break;
520     case GI_TYPE_TAG_TIME_T:
521       arg->v_long = seed_value_to_time_t (ctx, value, exception);
522       break;
523     case GI_TYPE_TAG_INTERFACE:
524       {
525         GIBaseInfo *interface;
526         GIInfoType interface_type;
527         GType required_gtype;
528         GObject *gobject;
529
530         interface = g_type_info_get_interface (type_info);
531         interface_type = g_base_info_get_type (interface);
532
533         arg->v_pointer = NULL;
534
535         if (interface_type == GI_INFO_TYPE_OBJECT
536             || interface_type == GI_INFO_TYPE_INTERFACE)
537           {
538             gobject = seed_value_to_object (ctx, value, exception);
539             required_gtype =
540               g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)
541                                                  interface);
542
543             // FIXME: Not clear if the g_type_is_a check is desired here.
544             // Possibly 'breaks things' when we don't have introspection
545             // data for some things in an interface hierarchy. Hasn't
546             // provided any problems so far.
547             if (!gobject
548                 || !g_type_is_a (G_OBJECT_TYPE (gobject), required_gtype))
549               {
550                 g_base_info_unref (interface);
551                 return FALSE;
552               }
553
554             arg->v_pointer = gobject;
555             g_base_info_unref (interface);
556             break;
557           }
558         else if (interface_type == GI_INFO_TYPE_ENUM ||
559                  interface_type == GI_INFO_TYPE_FLAGS)
560           {
561             arg->v_long = seed_value_to_long (ctx, value, exception);
562             if (!(interface_type == GI_INFO_TYPE_FLAGS)
563                 && !seed_validate_enum ((GIEnumInfo *) interface,
564                                         arg->v_long))
565               {
566                 seed_make_exception (ctx, exception, "EnumRange",
567                                      "Enum value: %ld is out of range",
568                                      arg->v_long);
569                 g_base_info_unref (interface);
570
571                 return FALSE;
572               }
573
574             g_base_info_unref (interface);
575             break;
576           }
577         else if (interface_type == GI_INFO_TYPE_STRUCT)
578           {
579             if (JSValueIsObjectOfClass (ctx, value, seed_struct_class))
580               arg->v_pointer = seed_pointer_get_pointer (ctx, value);
581             else
582               {
583                 GType type =
584                   g_registered_type_info_get_g_type ((GIRegisteredTypeInfo
585                                                       *) interface);
586                 if (!type)
587                   {
588                     g_base_info_unref (interface);
589                     return FALSE;
590                   }
591                 else if (type == G_TYPE_VALUE)
592                   {
593                     GValue *gval = g_slice_alloc0 (sizeof (GValue));
594                     seed_gvalue_from_seed_value (ctx,
595                                                  value,
596                                                  (GType) NULL,
597                                                  gval, exception);
598                     arg->v_pointer = gval;
599
600                     g_base_info_unref (interface);
601                     break;
602                   }
603                 // Automatically convert between functions and
604                 // GClosures where expected.
605                 else if (g_type_is_a (type, G_TYPE_CLOSURE))
606                   {
607                     if (JSObjectIsFunction (ctx, (JSObjectRef) value))
608                       {
609                         arg->v_pointer =
610                           seed_closure_new (ctx, (JSObjectRef) value, NULL,
611                                             NULL);
612                       }
613                   }
614                 else
615                   {
616                     JSObjectRef strukt =
617                       seed_construct_struct_type_with_parameters (ctx,
618                                                                   interface,
619                                                                   (JSObjectRef) value,
620                                                                   exception);
621                     arg->v_pointer = seed_pointer_get_pointer (ctx, strukt);
622                   }
623               }
624             g_base_info_unref (interface);
625             break;
626           }
627         else if (interface_type == GI_INFO_TYPE_CALLBACK)
628           {
629             if (JSValueIsNull (ctx, value))
630               {
631                 arg->v_pointer = NULL;
632                 g_base_info_unref (interface);
633                 break;
634               }
635             // Someone passes in a wrapper around a method where a
636             // callback is expected, i.e Clutter.sine_inc_func, as an alpha
637             // Have to dlsym the symbol to be able to do this.
638             // NOTE: Some cases where dlsym(NULL, symbol) doesn't work depending
639             // On how libseed is loaded.
640             else if (JSValueIsObjectOfClass (ctx,
641                                              value, gobject_method_class))
642               {
643                 GIFunctionInfo *info =
644                   JSObjectGetPrivate ((JSObjectRef) value);
645                 const gchar *symbol = g_function_info_get_symbol (info);
646                 gchar *error;
647                 void *fp;
648
649                 dlerror ();
650                 fp = (void *) dlsym (0, symbol);
651                 if ((error = dlerror ()) != NULL)
652                   {
653                     g_critical ("dlerror: %s \n", error);
654                   }
655                 else
656                   {
657                     arg->v_pointer = fp;
658                     g_base_info_unref (interface);
659                     break;
660                   }
661               }
662             // Somewhat deprecated from when it was necessary to manually
663             // create closure objects...
664             else if (JSValueIsObjectOfClass (ctx,
665                                              value,
666                                              seed_native_callback_class))
667               {
668                 SeedNativeClosure *privates =
669                   (SeedNativeClosure *)
670                   JSObjectGetPrivate ((JSObjectRef) value);
671                 arg->v_pointer = privates->closure;
672                 g_base_info_unref (interface);
673                 break;
674               }
675             // Automagically create closure around function passed in as
676             // callback.
677             else if (JSObjectIsFunction (ctx, (JSObjectRef) value))
678               {
679                 SeedNativeClosure *privates = seed_make_native_closure (ctx,
680                                                                         (GICallableInfo *) interface,
681                                                                         arg_info,
682                                                                         value);
683                 arg->v_pointer = privates->closure;
684                 g_base_info_unref (interface);
685                 break;
686               }
687
688           }
689       }
690     case GI_TYPE_TAG_ARRAY:
691       {
692         if (JSValueIsNull (ctx, value))
693           {
694             arg->v_pointer = NULL;
695             break;
696           }
697         else if (!JSValueIsObject (ctx, value))
698           {
699             // TODO: FIXME: Is this right?
700             return FALSE;
701           }
702         else
703           {
704             GITypeInfo *param_type;
705             //TODO: FIXME: Better array test like the cool one on reddit.
706             guint length =
707               seed_value_to_int (ctx, seed_object_get_property (ctx,
708                                                                 (JSObjectRef)
709                                                                 value,
710                                                                 "length"),
711                                  exception);
712             if (!length)
713               {
714                 arg->v_pointer = NULL;
715                 break;
716               }
717
718             param_type = g_type_info_get_param_type (type_info, 0);
719             if (!seed_gi_make_array (ctx, value, length, param_type,
720                                      &arg->v_pointer, exception))
721               {
722                 g_base_info_unref ((GIBaseInfo *) param_type);
723                 return FALSE;
724               }
725             g_base_info_unref ((GIBaseInfo *) param_type);
726             break;
727           }
728       }
729     default:
730       return FALSE;
731
732     }
733   return TRUE;
734
735 }
736
737 JSValueRef
738 seed_gi_argument_make_js (JSContextRef ctx,
739                           GArgument * arg, GITypeInfo * type_info,
740                           JSValueRef * exception)
741 {
742   GITypeTag gi_tag = g_type_info_get_tag (type_info);
743   switch (gi_tag)
744     {
745     case GI_TYPE_TAG_VOID:
746       return JSValueMakeUndefined (ctx);
747     case GI_TYPE_TAG_BOOLEAN:
748       return seed_value_from_boolean (ctx, arg->v_boolean, exception);
749     case GI_TYPE_TAG_INT8:
750       return seed_value_from_char (ctx, arg->v_int8, exception);
751     case GI_TYPE_TAG_UINT8:
752       return seed_value_from_uchar (ctx, arg->v_uint8, exception);
753     case GI_TYPE_TAG_INT16:
754       return seed_value_from_int (ctx, arg->v_int16, exception);
755     case GI_TYPE_TAG_UINT16:
756       return seed_value_from_uint (ctx, arg->v_uint16, exception);
757     case GI_TYPE_TAG_INT32:
758       return seed_value_from_int (ctx, arg->v_int32, exception);
759     case GI_TYPE_TAG_UINT32:
760       return seed_value_from_uint (ctx, arg->v_uint32, exception);
761     case GI_TYPE_TAG_LONG:
762     case GI_TYPE_TAG_INT64:
763       return seed_value_from_long (ctx, arg->v_int64, exception);
764     case GI_TYPE_TAG_ULONG:
765     case GI_TYPE_TAG_UINT64:
766       return seed_value_from_ulong (ctx, arg->v_uint64, exception);
767     case GI_TYPE_TAG_INT:
768       return seed_value_from_int (ctx, arg->v_int32, exception);
769     case GI_TYPE_TAG_UINT:
770       return seed_value_from_uint (ctx, arg->v_uint32, exception);
771     case GI_TYPE_TAG_SSIZE:
772     case GI_TYPE_TAG_SIZE:
773       return seed_value_from_int (ctx, arg->v_int, exception);
774     case GI_TYPE_TAG_FLOAT:
775       return seed_value_from_float (ctx, arg->v_float, exception);
776     case GI_TYPE_TAG_DOUBLE:
777       return seed_value_from_double (ctx, arg->v_double, exception);
778     case GI_TYPE_TAG_UTF8:
779       return seed_value_from_string (ctx, arg->v_string, exception);
780     case GI_TYPE_TAG_FILENAME:
781       return seed_value_from_filename (ctx, arg->v_string, exception);
782     case GI_TYPE_TAG_GTYPE:
783       return seed_value_from_int (ctx, arg->v_int, exception);
784     case GI_TYPE_TAG_TIME_T:
785       return seed_value_from_time_t (ctx, arg->v_long, exception);
786     case GI_TYPE_TAG_ARRAY:
787       {
788         GITypeInfo *param_type;
789         JSValueRef ret;
790
791         if (arg->v_pointer == NULL)
792           return JSValueMakeNull (ctx);
793         if (!g_type_info_is_zero_terminated (type_info))
794           break;
795
796         param_type = g_type_info_get_param_type (type_info, 0);
797
798         ret = seed_gi_make_jsarray (ctx, arg->v_pointer, param_type,
799                                     exception);
800
801         g_base_info_unref ((GIBaseInfo *) param_type);
802
803         return ret;
804       }
805     case GI_TYPE_TAG_INTERFACE:
806       {
807         GIBaseInfo *interface;
808         GIInfoType interface_type;
809
810         interface = g_type_info_get_interface (type_info);
811         interface_type = g_base_info_get_type (interface);
812
813         if (interface_type == GI_INFO_TYPE_OBJECT ||
814             interface_type == GI_INFO_TYPE_INTERFACE)
815           {
816             if (arg->v_pointer == 0)
817               {
818                 g_base_info_unref (interface);
819                 return JSValueMakeNull (ctx);
820               }
821             g_base_info_unref (interface);
822             return seed_value_from_object (ctx, arg->v_pointer, exception);
823           }
824         else if (interface_type == GI_INFO_TYPE_ENUM
825                  || interface_type == GI_INFO_TYPE_FLAGS)
826           {
827             g_base_info_unref (interface);
828             return seed_value_from_long (ctx, arg->v_long, exception);
829           }
830         else if (interface_type == GI_INFO_TYPE_STRUCT)
831           {
832             JSValueRef strukt;
833
834             strukt = seed_make_struct (ctx, arg->v_pointer, interface);
835             g_base_info_unref (interface);
836
837             return strukt;
838           }
839       }
840     case GI_TYPE_TAG_GLIST:
841       {
842         GITypeInfo *list_type;
843         JSObjectRef ret;
844         GArgument larg;
845         gint i = 0;
846         GList *list = arg->v_pointer;
847
848         ret = JSObjectMakeArray (ctx, 0, NULL, exception);
849         list_type = g_type_info_get_param_type (type_info, 0);
850
851         for (; list != NULL; list = list->next)
852           {
853             JSValueRef ival;
854
855             larg.v_pointer = list->data;
856             ival =
857               (JSValueRef) seed_gi_argument_make_js (ctx, &larg,
858                                                      list_type, exception);
859             if (!ival)
860               ival = JSValueMakeNull (ctx);
861             JSObjectSetPropertyAtIndex (ctx, ret, i, ival, NULL);
862             i++;
863           }
864         return ret;
865
866       }
867     case GI_TYPE_TAG_GSLIST:
868       {
869         GITypeInfo *list_type;
870         JSObjectRef ret;
871         JSValueRef ival;
872         GArgument larg;
873         guint i = 0;
874         GSList *list = arg->v_pointer;
875
876         ret = JSObjectMakeArray (ctx, 0, NULL, exception);
877         list_type = g_type_info_get_param_type (type_info, 0);
878
879         for (; list != NULL; list = list->next)
880           {
881             larg.v_pointer = list->data;
882             ival =
883               (JSValueRef) seed_gi_argument_make_js (ctx, &larg,
884                                                      list_type, exception);
885             if (!ival)
886               ival = JSValueMakeNull (ctx);
887             JSObjectSetPropertyAtIndex (ctx, ret, i, ival, NULL);
888             i++;
889           }
890         return ret;
891       }
892
893     default:
894       return FALSE;
895
896     }
897   return 0;
898 }
899
900 JSValueRef
901 seed_value_from_gvalue (JSContextRef ctx,
902                         GValue * gval, JSValueRef * exception)
903 {
904   if (!G_IS_VALUE (gval))
905     {
906       return false;
907     }
908   switch (G_VALUE_TYPE (gval))
909     {
910     case G_TYPE_BOOLEAN:
911       return seed_value_from_boolean (ctx,
912                                       g_value_get_boolean (gval), exception);
913     case G_TYPE_CHAR:
914       return seed_value_from_char (ctx, g_value_get_char (gval), exception);
915     case G_TYPE_UCHAR:
916       return seed_value_from_uchar (ctx, g_value_get_uchar (gval), exception);
917     case G_TYPE_INT:
918       return seed_value_from_int (ctx, g_value_get_int (gval), exception);
919     case G_TYPE_UINT:
920       return seed_value_from_uint (ctx, g_value_get_uint (gval), exception);
921     case G_TYPE_LONG:
922       return seed_value_from_long (ctx, g_value_get_long (gval), exception);
923     case G_TYPE_ULONG:
924       return seed_value_from_ulong (ctx, g_value_get_ulong (gval), exception);
925     case G_TYPE_INT64:
926       return seed_value_from_int64 (ctx, g_value_get_int64 (gval), exception);
927     case G_TYPE_UINT64:
928       return seed_value_from_uint64 (ctx, g_value_get_uint64 (gval),
929                                      exception);
930     case G_TYPE_FLOAT:
931       return seed_value_from_float (ctx, g_value_get_float (gval), exception);
932     case G_TYPE_DOUBLE:
933       return seed_value_from_double (ctx, g_value_get_double (gval),
934                                      exception);
935     case G_TYPE_STRING:
936       return seed_value_from_string (ctx, (gchar *)
937                                      g_value_get_string (gval), exception);
938     case G_TYPE_POINTER:
939       return seed_make_pointer (ctx, g_value_get_pointer (gval));
940     case G_TYPE_PARAM:
941       // Might need to dup and make a boxed.
942       return seed_make_pointer (ctx, g_value_get_param (gval));
943     }
944
945   if (g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_ENUM) ||
946       g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_FLAGS))
947     return seed_value_from_long (ctx, gval->data[0].v_long, exception);
948   else if (g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_ENUM))
949     return seed_value_from_long (ctx, gval->data[0].v_long, exception);
950   else if (g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_OBJECT))
951     {
952       GObject *obj = g_value_get_object (gval);
953       return seed_value_from_object (ctx, obj, exception);
954     }
955   else
956     {
957       GIBaseInfo *info;
958       GIInfoType type;
959
960       info = g_irepository_find_by_gtype (0, G_VALUE_TYPE (gval));
961       if (!info)
962         return FALSE;
963       type = g_base_info_get_type (info);
964
965       if (type == GI_INFO_TYPE_UNION)
966         {
967           return seed_make_union (ctx, g_value_peek_pointer (gval), info);
968         }
969       else if (type == GI_INFO_TYPE_STRUCT)
970         {
971           return seed_make_struct (ctx, g_value_peek_pointer (gval), info);
972         }
973       else if (type == GI_INFO_TYPE_BOXED)
974         {
975           return seed_make_boxed (ctx, g_value_dup_boxed (gval), info);
976         }
977
978     }
979
980   return NULL;
981 }
982
983 gboolean
984 seed_gvalue_from_seed_value (JSContextRef ctx,
985                              JSValueRef val,
986                              GType type, GValue * ret, JSValueRef * exception)
987 {
988   if (G_IS_VALUE (ret))
989     g_value_unset (ret);
990
991  if (type == G_TYPE_STRV)
992     {
993       gchar **result;
994       JSValueRef jslen;
995       guint length, i;
996       
997       if (JSValueIsNull (ctx, val) || !JSValueIsObject (ctx, val))
998         return FALSE;
999       
1000       jslen = seed_object_get_property (ctx, (JSObjectRef) val, "length");
1001       length = seed_value_to_uint (ctx, jslen, exception);
1002       
1003       result = g_new0 (gchar *, length+1);
1004       
1005       for (i = 0; i < length; i++)
1006         {
1007           result[i] = seed_value_to_string (ctx,
1008                                             JSObjectGetPropertyAtIndex (ctx,
1009                                                                         (JSObjectRef)
1010                                                                         val,
1011                                                                         i,
1012                                                                         exception),
1013                                             exception);
1014           
1015         }
1016       result[i] = 0;
1017       
1018       g_value_init (ret, G_TYPE_STRV);
1019       g_value_take_boxed (ret, result);
1020       
1021         return TRUE;
1022     }
1023   else if (g_type_is_a (type, G_TYPE_ENUM) && JSValueIsNumber (ctx, val))
1024     {
1025       g_value_init (ret, type);
1026       g_value_set_enum (ret, seed_value_to_long (ctx, val, exception));
1027       return TRUE;
1028     }
1029   else if (g_type_is_a (type, G_TYPE_FLAGS) && JSValueIsNumber (ctx, val))
1030     {
1031       g_value_init (ret, type);
1032       g_value_set_flags (ret, seed_value_to_long (ctx, val, exception));
1033       return TRUE;
1034     }
1035   else if (g_type_is_a (type, G_TYPE_OBJECT)
1036            && (JSValueIsNull (ctx, val) || seed_value_is_gobject (ctx, val)))
1037     {
1038       GObject *o = seed_value_to_object (ctx,
1039                                          val, exception);
1040
1041       if (o == NULL || g_type_is_a (G_OBJECT_TYPE (o), type))
1042         {
1043           g_value_init (ret, G_TYPE_OBJECT);
1044           g_value_set_object (ret, o);
1045
1046           return TRUE;
1047         }
1048     }
1049   /* Boxed handling is broken. Will be fixed in struct overhall. */
1050   else if (g_type_is_a (type, G_TYPE_BOXED))
1051     {
1052       gpointer p = seed_pointer_get_pointer (ctx, val);
1053       if (p)
1054         {
1055           g_value_init (ret, type);
1056           g_value_set_boxed (ret, p);
1057           return TRUE;
1058         }
1059       else
1060         {
1061           if (JSValueIsObject (ctx, val))
1062             {
1063               GIBaseInfo *info = g_irepository_find_by_gtype (0, type);
1064               JSObjectRef new_struct;
1065               if (!info)
1066                 return FALSE;
1067
1068               new_struct =
1069                 seed_construct_struct_type_with_parameters (ctx,
1070                                                             info,
1071                                                             (JSObjectRef)
1072                                                             val, exception);
1073               p = seed_pointer_get_pointer (ctx, new_struct);
1074               if (p)
1075                 {
1076                   g_value_init (ret, type);
1077                   g_value_set_boxed (ret, p);
1078                   g_base_info_unref (info);
1079                   return TRUE;
1080                 }
1081               g_base_info_unref (info);
1082             }
1083         }
1084     }
1085
1086   switch (type)
1087     {
1088     case G_TYPE_BOOLEAN:
1089       {
1090         g_value_init (ret, G_TYPE_BOOLEAN);
1091         g_value_set_boolean (ret, seed_value_to_boolean (ctx,
1092                                                          val, exception));
1093         return TRUE;
1094       }
1095     case G_TYPE_INT:
1096     case G_TYPE_UINT:
1097       {
1098         g_value_init (ret, type);
1099         if (type == G_TYPE_INT)
1100           g_value_set_int (ret, seed_value_to_int (ctx, val, exception));
1101         else
1102           g_value_set_uint (ret, seed_value_to_uint (ctx, val, exception));
1103         return TRUE;
1104       }
1105     case G_TYPE_CHAR:
1106       {
1107         g_value_init (ret, G_TYPE_CHAR);
1108         g_value_set_char (ret, seed_value_to_char (ctx, val, exception));
1109         return TRUE;
1110       }
1111     case G_TYPE_UCHAR:
1112       {
1113         g_value_init (ret, G_TYPE_UCHAR);
1114         g_value_set_uchar (ret, seed_value_to_uchar (ctx, val, exception));
1115         return TRUE;
1116       }
1117     case G_TYPE_LONG:
1118     case G_TYPE_ULONG:
1119     case G_TYPE_INT64:
1120     case G_TYPE_UINT64:
1121     case G_TYPE_FLOAT:
1122     case G_TYPE_DOUBLE:
1123       {
1124         switch (type)
1125           {
1126           case G_TYPE_LONG:
1127             g_value_init (ret, G_TYPE_LONG);
1128             g_value_set_long (ret, seed_value_to_long (ctx, val, exception));
1129             break;
1130           case G_TYPE_ULONG:
1131             g_value_init (ret, G_TYPE_ULONG);
1132             g_value_set_ulong (ret, seed_value_to_ulong (ctx,
1133                                                          val, exception));
1134             break;
1135           case G_TYPE_INT64:
1136             g_value_init (ret, G_TYPE_INT64);
1137             g_value_set_int64 (ret, seed_value_to_int64 (ctx,
1138                                                          val, exception));
1139             break;
1140           case G_TYPE_UINT64:
1141             g_value_init (ret, G_TYPE_UINT64);
1142             g_value_set_uint64 (ret, seed_value_to_uint64 (ctx,
1143                                                            val, exception));
1144             break;
1145           case G_TYPE_FLOAT:
1146             g_value_init (ret, G_TYPE_FLOAT);
1147             g_value_set_float (ret, seed_value_to_float (ctx,
1148                                                          val, exception));
1149             break;
1150           case G_TYPE_DOUBLE:
1151             g_value_init (ret, G_TYPE_DOUBLE);
1152             g_value_set_double (ret, seed_value_to_double (ctx,
1153                                                            val, exception));
1154             break;
1155           }
1156         return TRUE;
1157       }
1158     case G_TYPE_STRING:
1159       {
1160         gchar *cval = seed_value_to_string (ctx, val, exception);
1161
1162         g_value_init (ret, G_TYPE_STRING);
1163         g_value_take_string (ret, cval);
1164
1165         return TRUE;
1166       }
1167     default:
1168       {
1169         // TODO: FIXME: This whole undefined type area
1170         // needs some heaaavy improvement.
1171
1172         // Support [GObject.TYPE_INT, 3]
1173         // TODO: FIXME: Might crash.
1174         if (type == 0 && JSValueIsObject (ctx, val))
1175           {
1176             // TODO: FIXME: Better array test like the cool one on reddit.
1177             guint length = seed_value_to_int (ctx,
1178                                               seed_object_get_property (ctx,
1179                                                                         (JSObjectRef) val,
1180                                                                         "length"),
1181                                               exception);
1182
1183             if (length)
1184               {
1185                 type =
1186                   seed_value_to_int (ctx,
1187                                      JSObjectGetPropertyAtIndex (ctx,
1188                                                                  (JSObjectRef)
1189                                                                  val, 0,
1190                                                                  exception),
1191                                      exception);
1192                 val =
1193                   JSObjectGetPropertyAtIndex (ctx, (JSObjectRef) val, 1,
1194                                               exception);
1195                 if (type)       // Prevents recursion.
1196                   {
1197                     return seed_gvalue_from_seed_value (ctx, val,
1198                                                         type, ret, exception);
1199                   }
1200                 // TODO: FIXME: Handle better?
1201                 else
1202                   g_assert_not_reached ();
1203               }
1204           }
1205         switch (JSValueGetType (ctx, val))
1206           {
1207           case kJSTypeBoolean:
1208             {
1209               g_value_init (ret, G_TYPE_BOOLEAN);
1210               g_value_set_boolean (ret,
1211                                    seed_value_to_boolean (ctx,
1212                                                           val, exception));
1213               return TRUE;
1214             }
1215           case kJSTypeNumber:
1216             {
1217               g_value_init (ret, G_TYPE_DOUBLE);
1218               g_value_set_double (ret,
1219                                   seed_value_to_double (ctx, val, exception));
1220               return TRUE;
1221             }
1222           case kJSTypeString:
1223             {
1224               gchar *cv = seed_value_to_string (ctx, val,
1225                                                 exception);
1226
1227               g_value_init (ret, G_TYPE_STRING);
1228               g_value_take_string (ret, cv);
1229               return TRUE;
1230             }
1231           default:
1232             break;
1233           }
1234         break;
1235       }
1236     }
1237
1238    return FALSE;
1239 }
1240
1241 /**
1242  * seed_object_get_property
1243  * @ctx: A #SeedContext
1244  * @object: A #SeedObject
1245  * @name: The property to get, should be a valid JavaScript identifier
1246  *
1247  * Returns: The value of the property or %NULL
1248  */
1249 JSValueRef
1250 seed_object_get_property (JSContextRef ctx,
1251                           JSObjectRef val, const gchar * name)
1252 {
1253
1254   JSStringRef jname = JSStringCreateWithUTF8CString (name);
1255   JSValueRef ret = JSObjectGetProperty (ctx,
1256                                         (JSObjectRef) val,
1257                                         jname, NULL);
1258
1259   JSStringRelease (jname);
1260
1261   return ret;
1262 }
1263
1264 /**
1265  * seed_object_set_property
1266  * @ctx: A #SeedContext
1267  * @object: A #SeedObject
1268  * @name: The property to set, should be a valid JavaScript identifier
1269  * @value: The value to set the property to.
1270  *
1271  * Returns: %TRUE on success, %FALSE otherwise.
1272  */
1273 gboolean
1274 seed_object_set_property (JSContextRef ctx, JSObjectRef object,
1275                           const gchar * name, JSValueRef value)
1276 {
1277   JSStringRef jname = JSStringCreateWithUTF8CString (name);
1278   JSValueRef exception = NULL;
1279
1280   if (value)
1281     {
1282       JSObjectSetProperty (ctx, (JSObjectRef) object, jname, value, 0,
1283                            &exception);
1284     }
1285
1286   JSStringRelease (jname);
1287
1288   return TRUE;
1289 }
1290
1291 /* TODO: Make some macros or something for making exceptions, code is littered
1292    with annoyingness right now */
1293
1294 /**
1295  * seed_value_to_boolean:
1296  * @ctx: A #SeedContext.
1297  * @val: The #SeedValue to convert.
1298  * @exception: A reference to a #SeedValue in which to store any exceptions.
1299  *             Pass %NULL to ignore exceptions.
1300  *
1301  * Converts the given #SeedValue into a #gboolean. Keep in mind that this will
1302  * not convert a JavaScript number type, only a boolean.
1303  *
1304  * Return value: The #gboolean represented by @val, or %NULL if an exception
1305  *               is raised during the conversion.
1306  *
1307  */
1308 gboolean
1309 seed_value_to_boolean (JSContextRef ctx,
1310                        JSValueRef val, JSValueRef * exception)
1311 {
1312   if (!JSValueIsBoolean (ctx, val) && !JSValueIsNumber (ctx, val))
1313     {
1314       if (!JSValueIsNull (ctx, val))
1315         {
1316           seed_make_exception (eng->context, exception, "ConversionError",
1317                                "Can not convert Javascript value to boolean");
1318           return FALSE;
1319         }
1320
1321       return FALSE;
1322     }
1323
1324   return JSValueToBoolean (ctx, val);
1325 }
1326
1327 /**
1328  * seed_value_from_boolean:
1329  * @ctx: A #SeedContext.
1330  * @val: The #gboolean to represent.
1331  * @exception: A reference to a #SeedValue in which to store any exceptions.
1332  *             Pass %NULL to ignore exceptions.
1333  *
1334  * Converts the given #gboolean into a #SeedValue.
1335  *
1336  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1337  *               is raised during the conversion.
1338  *
1339  */
1340 JSValueRef
1341 seed_value_from_boolean (JSContextRef ctx,
1342                          gboolean val, JSValueRef * exception)
1343 {
1344   return JSValueMakeBoolean (ctx, val);
1345 }
1346
1347 /**
1348  * seed_value_to_uint:
1349  * @ctx: A #SeedContext.
1350  * @val: The #SeedValue to convert.
1351  * @exception: A reference to a #SeedValue in which to store any exceptions.
1352  *             Pass %NULL to ignore exceptions.
1353  *
1354  * Converts the given #SeedValue into a #guint.
1355  *
1356  * Return value: The #guint represented by @val, or %NULL if an exception
1357  *               is raised during the conversion.
1358  *
1359  */
1360 guint
1361 seed_value_to_uint (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1362 {
1363   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1364     {
1365       if (!JSValueIsNull (ctx, val))
1366         {
1367           seed_make_exception (ctx, exception, "ConversionError",
1368                                "Can not convert Javascript value to"
1369                                " boolean");
1370         }
1371       return 0;
1372     }
1373
1374   return (guint) JSValueToNumber (ctx, val, NULL);
1375 }
1376
1377 /**
1378  * seed_value_from_uint:
1379  * @ctx: A #SeedContext.
1380  * @val: The #guint to represent.
1381  * @exception: A reference to a #SeedValue in which to store any exceptions.
1382  *             Pass %NULL to ignore exceptions.
1383  *
1384  * Converts the given #guint into a #SeedValue.
1385  *
1386  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1387  *               is raised during the conversion.
1388  *
1389  */
1390 JSValueRef
1391 seed_value_from_uint (JSContextRef ctx, guint val, JSValueRef * exception)
1392 {
1393   return JSValueMakeNumber (ctx, (gdouble) val);
1394 }
1395
1396 /**
1397  * seed_value_to_int:
1398  * @ctx: A #SeedContext.
1399  * @val: The #SeedValue to convert.
1400  * @exception: A reference to a #SeedValue in which to store any exceptions.
1401  *             Pass %NULL to ignore exceptions.
1402  *
1403  * Converts the given #SeedValue into a #gint.
1404  *
1405  * Return value: The #gint represented by @val, or %NULL if an exception
1406  *               is raised during the conversion.
1407  *
1408  */
1409 gint
1410 seed_value_to_int (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1411 {
1412   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1413     {
1414       if (!JSValueIsNull (ctx, val))
1415         seed_make_exception (ctx, exception, "ConversionError",
1416                              "Can not convert Javascript value to" " int");
1417       return 0;
1418     }
1419
1420   return (gint) JSValueToNumber (ctx, val, NULL);
1421 }
1422
1423 /**
1424  * seed_value_from_int:
1425  * @ctx: A #SeedContext.
1426  * @val: The #gint to represent.
1427  * @exception: A reference to a #SeedValue in which to store any exceptions.
1428  *             Pass %NULL to ignore exceptions.
1429  *
1430  * Converts the given #gint into a #SeedValue.
1431  *
1432  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1433  *               is raised during the conversion.
1434  *
1435  */
1436 JSValueRef
1437 seed_value_from_int (JSContextRef ctx, gint val, JSValueRef * exception)
1438 {
1439   return JSValueMakeNumber (ctx, (gdouble) val);
1440 }
1441
1442 /**
1443  * seed_value_to_char:
1444  * @ctx: A #SeedContext.
1445  * @val: The #SeedValue to convert.
1446  * @exception: A reference to a #SeedValue in which to store any exceptions.
1447  *             Pass %NULL to ignore exceptions.
1448  *
1449  * Converts the given #SeedValue into a #gchar.
1450  *
1451  * Return value: The #gchar represented by @val, or %NULL if an exception
1452  *               is raised during the conversion.
1453  *
1454  */
1455 gchar
1456 seed_value_to_char (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1457 {
1458   gint cv;
1459
1460   if (!JSValueIsNumber (ctx, val))
1461     {
1462       if (!JSValueIsNull (ctx, val))
1463         seed_make_exception (ctx, exception, "ConversionError",
1464                              "Can not convert Javascript value to" " gchar");
1465       return 0;
1466     }
1467
1468   cv = JSValueToNumber (ctx, val, NULL);
1469
1470   if (cv < G_MININT8 || cv > G_MAXINT8)
1471     {
1472       seed_make_exception (ctx, exception, "ConversionError",
1473                            "Javascript number out of range of gchar");
1474       return 0;
1475     }
1476
1477   return (gchar) cv;
1478 }
1479
1480 /**
1481  * seed_value_from_char:
1482  * @ctx: A #SeedContext.
1483  * @val: The #gchar to represent.
1484  * @exception: A reference to a #SeedValue in which to store any exceptions.
1485  *             Pass %NULL to ignore exceptions.
1486  *
1487  * Converts the given #gchar into a #SeedValue.
1488  *
1489  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1490  *               is raised during the conversion.
1491  *
1492  */
1493 JSValueRef
1494 seed_value_from_char (JSContextRef ctx, gchar val, JSValueRef * exception)
1495 {
1496   return JSValueMakeNumber (ctx, (gdouble) val);
1497 }
1498
1499 /**
1500  * seed_value_to_uchar:
1501  * @ctx: A #SeedContext.
1502  * @val: The #SeedValue to convert.
1503  * @exception: A reference to a #SeedValue in which to store any exceptions.
1504  *             Pass %NULL to ignore exceptions.
1505  *
1506  * Converts the given #SeedValue into a #guchar.
1507  *
1508  * Return value: The #guchar represented by @val, or %NULL if an exception
1509  *               is raised during the conversion.
1510  *
1511  */
1512 guchar
1513 seed_value_to_uchar (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1514 {
1515   guint cv;
1516
1517   if (!JSValueIsNumber (ctx, val))
1518     {
1519       if (!JSValueIsNull (ctx, val))
1520         seed_make_exception (ctx, exception, "ConversionError",
1521                              "Can not convert Javascript value to" " guchar");
1522       return 0;
1523     }
1524
1525   cv = JSValueToNumber (ctx, val, NULL);
1526
1527   if (cv > G_MAXUINT8)
1528     {
1529       seed_make_exception (ctx, exception, "ConversionError",
1530                            "Javascript number out of range of guchar");
1531       return 0;
1532     }
1533
1534   return (guchar) cv;
1535 }
1536
1537 /**
1538  * seed_value_from_uchar:
1539  * @ctx: A #SeedContext.
1540  * @val: The #guchar to represent.
1541  * @exception: A reference to a #SeedValue in which to store any exceptions.
1542  *             Pass %NULL to ignore exceptions.
1543  *
1544  * Converts the given #guchar into a #SeedValue.
1545  *
1546  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1547  *               is raised during the conversion.
1548  *
1549  */
1550 JSValueRef
1551 seed_value_from_uchar (JSContextRef ctx, guchar val, JSValueRef * exception)
1552 {
1553   return JSValueMakeNumber (ctx, (gdouble) val);
1554 }
1555
1556 /**
1557  * seed_value_to_short:
1558  * @ctx: A #SeedContext.
1559  * @val: The #SeedValue to convert.
1560  * @exception: A reference to a #SeedValue in which to store any exceptions.
1561  *             Pass %NULL to ignore exceptions.
1562  *
1563  * Converts the given #SeedValue into a #gshort.
1564  *
1565  * Return value: The #gshort represented by @val, or %NULL if an exception
1566  *               is raised during the conversion.
1567  *
1568  */
1569 gshort
1570 seed_value_to_short (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1571 {
1572   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1573     {
1574       if (!JSValueIsNull (ctx, val))
1575         seed_make_exception (ctx, exception, "ConversionError",
1576                              "Can not convert Javascript value to" " short");
1577       return 0;
1578     }
1579
1580   return (gshort) JSValueToNumber (ctx, val, NULL);
1581 }
1582
1583 /**
1584  * seed_value_from_short:
1585  * @ctx: A #SeedContext.
1586  * @val: The #gshort to represent.
1587  * @exception: A reference to a #SeedValue in which to store any exceptions.
1588  *             Pass %NULL to ignore exceptions.
1589  *
1590  * Converts the given #gshort into a #SeedValue.
1591  *
1592  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1593  *               is raised during the conversion.
1594  *
1595  */
1596 JSValueRef
1597 seed_value_from_short (JSContextRef ctx, gshort val, JSValueRef * exception)
1598 {
1599   return JSValueMakeNumber (ctx, (gdouble) val);
1600 }
1601
1602 /**
1603  * seed_value_to_ushort:
1604  * @ctx: A #SeedContext.
1605  * @val: The #SeedValue to convert.
1606  * @exception: A reference to a #SeedValue in which to store any exceptions.
1607  *             Pass %NULL to ignore exceptions.
1608  *
1609  * Converts the given #SeedValue into a #gushort.
1610  *
1611  * Return value: The #gushort represented by @val, or %NULL if an exception
1612  *               is raised during the conversion.
1613  *
1614  */
1615 gushort
1616 seed_value_to_ushort (JSContextRef ctx, JSValueRef val,
1617                       JSValueRef * exception)
1618 {
1619   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1620     {
1621       if (!JSValueIsNull (ctx, val))
1622         seed_make_exception (ctx, exception, "ConversionError",
1623                              "Can not convert Javascript value to" " ushort");
1624       return 0;
1625     }
1626
1627   return (gushort) JSValueToNumber (ctx, val, NULL);
1628 }
1629
1630 /**
1631  * seed_value_from_ushort:
1632  * @ctx: A #SeedContext.
1633  * @val: The #gushort to represent.
1634  * @exception: A reference to a #SeedValue in which to store any exceptions.
1635  *             Pass %NULL to ignore exceptions.
1636  *
1637  * Converts the given #gushort into a #SeedValue.
1638  *
1639  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1640  *               is raised during the conversion.
1641  *
1642  */
1643 JSValueRef
1644 seed_value_from_ushort (JSContextRef ctx, gushort val, JSValueRef * exception)
1645 {
1646   return JSValueMakeNumber (ctx, (gdouble) val);
1647 }
1648
1649 /**
1650  * seed_value_to_long:
1651  * @ctx: A #SeedContext.
1652  * @val: The #SeedValue to convert.
1653  * @exception: A reference to a #SeedValue in which to store any exceptions.
1654  *             Pass %NULL to ignore exceptions.
1655  *
1656  * Converts the given #SeedValue into a #glong.
1657  *
1658  * Return value: The #glong represented by @val, or %NULL if an exception
1659  *               is raised during the conversion.
1660  *
1661  */
1662 glong
1663 seed_value_to_long (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1664 {
1665   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1666     {
1667       if (!JSValueIsNull (ctx, val))
1668         seed_make_exception (ctx, exception, "ConversionError",
1669                              "Can not convert Javascript value to" " long");
1670       return 0;
1671     }
1672
1673   return (glong) JSValueToNumber (ctx, val, NULL);
1674 }
1675
1676  /**
1677  * seed_value_from_long:
1678  * @ctx: A #SeedContext.
1679  * @val: The #glong to represent.
1680  * @exception: A reference to a #SeedValue in which to store any exceptions.
1681  *             Pass %NULL to ignore exceptions.
1682  *
1683  * Converts the given #glong into a #SeedValue.
1684  *
1685  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1686  *               is raised during the conversion.
1687  *
1688  */
1689 JSValueRef
1690 seed_value_from_long (JSContextRef ctx, glong val, JSValueRef * exception)
1691 {
1692   return JSValueMakeNumber (ctx, (gdouble) val);
1693 }
1694
1695 /**
1696  * seed_value_to_ulong:
1697  * @ctx: A #SeedContext.
1698  * @val: The #SeedValue to convert.
1699  * @exception: A reference to a #SeedValue in which to store any exceptions.
1700  *             Pass %NULL to ignore exceptions.
1701  *
1702  * Converts the given #SeedValue into a #gulong.
1703  *
1704  * Return value: The #gulong represented by @val, or %NULL if an exception
1705  *               is raised during the conversion.
1706  *
1707  */
1708 gulong
1709 seed_value_to_ulong (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1710 {
1711   if (!JSValueIsNumber (ctx, val))
1712     {
1713       if (!JSValueIsNull (ctx, val))
1714         seed_make_exception (ctx, exception, "ConversionError",
1715                              "Can not convert Javascript value to" " ulong");
1716
1717       return 0;
1718     }
1719
1720   return (gulong) JSValueToNumber (ctx, val, NULL);
1721 }
1722
1723 /**
1724  * seed_value_from_ulong:
1725  * @ctx: A #SeedContext.
1726  * @val: The #gulong to represent.
1727  * @exception: A reference to a #SeedValue in which to store any exceptions.
1728  *             Pass %NULL to ignore exceptions.
1729  *
1730  * Converts the given #gulong into a #SeedValue.
1731  *
1732  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1733  *               is raised during the conversion.
1734  *
1735  */
1736 JSValueRef
1737 seed_value_from_ulong (JSContextRef ctx, gulong val, JSValueRef * exception)
1738 {
1739   return JSValueMakeNumber (ctx, (gdouble) val);
1740 }
1741
1742 /**
1743  * seed_value_to_int64:
1744  * @ctx: A #SeedContext.
1745  * @val: The #SeedValue to convert.
1746  * @exception: A reference to a #SeedValue in which to store any exceptions.
1747  *             Pass %NULL to ignore exceptions.
1748  *
1749  * Converts the given #SeedValue into a #gint64.
1750  *
1751  * Return value: The #gint64 represented by @val, or %NULL if an exception
1752  *               is raised during the conversion.
1753  *
1754  */
1755 gint64
1756 seed_value_to_int64 (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1757 {
1758   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1759     {
1760       if (!JSValueIsNull (ctx, val))
1761         seed_make_exception (ctx, exception, "ConversionError",
1762                              "Can not convert Javascript value to" " gint64");
1763
1764       return 0;
1765     }
1766
1767   return (gint64) JSValueToNumber (ctx, val, NULL);
1768 }
1769
1770 /**
1771  * seed_value_from_int64:
1772  * @ctx: A #SeedContext.
1773  * @val: The #gint64 to represent.
1774  * @exception: A reference to a #SeedValue in which to store any exceptions.
1775  *             Pass %NULL to ignore exceptions.
1776  *
1777  * Converts the given #gint64 into a #SeedValue.
1778  *
1779  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1780  *               is raised during the conversion.
1781  *
1782  */
1783 JSValueRef
1784 seed_value_from_int64 (JSContextRef ctx, gint64 val, JSValueRef * exception)
1785 {
1786   return JSValueMakeNumber (ctx, (gdouble) val);
1787 }
1788
1789 /**
1790  * seed_value_to_uint64:
1791  * @ctx: A #SeedContext.
1792  * @val: The #SeedValue to convert.
1793  * @exception: A reference to a #SeedValue in which to store any exceptions.
1794  *             Pass %NULL to ignore exceptions.
1795  *
1796  * Converts the given #SeedValue into a #guint64.
1797  *
1798  * Return value: The #guint64 represented by @val, or %NULL if an exception
1799  *               is raised during the conversion.
1800  *
1801  */
1802 guint64
1803 seed_value_to_uint64 (JSContextRef ctx,
1804                       JSValueRef val, JSValueRef * exception)
1805 {
1806   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1807     {
1808       if (!JSValueIsNull (ctx, val))
1809         seed_make_exception (ctx, exception, "ConversionError",
1810                              "Can not convert Javascript value to"
1811                              " guint64");
1812
1813       return 0;
1814     }
1815
1816   return (guint64) JSValueToNumber (ctx, val, NULL);
1817 }
1818
1819 /**
1820  * seed_value_from_uint64:
1821  * @ctx: A #SeedContext.
1822  * @val: The #guint64 to represent.
1823  * @exception: A reference to a #SeedValue in which to store any exceptions.
1824  *             Pass %NULL to ignore exceptions.
1825  *
1826  * Converts the given #guint64 into a #SeedValue.
1827  *
1828  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1829  *               is raised during the conversion.
1830  *
1831  */
1832 JSValueRef
1833 seed_value_from_uint64 (JSContextRef ctx, guint64 val, JSValueRef * exception)
1834 {
1835   return JSValueMakeNumber (ctx, (gdouble) val);
1836 }
1837
1838 /**
1839  * seed_value_to_float:
1840  * @ctx: A #SeedContext.
1841  * @val: The #SeedValue to convert.
1842  * @exception: A reference to a #SeedValue in which to store any exceptions.
1843  *             Pass %NULL to ignore exceptions.
1844  *
1845  * Converts the given #SeedValue into a #gfloat.
1846  *
1847  * Return value: The #gfloat represented by @val, or %NULL if an exception
1848  *               is raised during the conversion.
1849  *
1850  */
1851 gfloat
1852 seed_value_to_float (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1853 {
1854   if (!JSValueIsNumber (ctx, val))
1855     {
1856       if (!JSValueIsNull (ctx, val))
1857         seed_make_exception (ctx, exception, "ConversionError",
1858                              "Can not convert Javascript value to" " gfloat");
1859       return 0;
1860     }
1861
1862   return (gfloat) JSValueToNumber (ctx, val, NULL);
1863 }
1864
1865 /**
1866  * seed_value_from_float:
1867  * @ctx: A #SeedContext.
1868  * @val: The #gfloat to represent.
1869  * @exception: A reference to a #SeedValue in which to store any exceptions.
1870  *             Pass %NULL to ignore exceptions.
1871  *
1872  * Converts the given #gfloat into a #SeedValue.
1873  *
1874  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1875  *               is raised during the conversion.
1876  *
1877  */
1878 JSValueRef
1879 seed_value_from_float (JSContextRef ctx, gfloat val, JSValueRef * exception)
1880 {
1881   return JSValueMakeNumber (ctx, (gdouble) val);
1882 }
1883
1884 /**
1885  * seed_value_to_double:
1886  * @ctx: A #SeedContext.
1887  * @val: The #SeedValue to convert.
1888  * @exception: A reference to a #SeedValue in which to store any exceptions.
1889  *             Pass %NULL to ignore exceptions.
1890  *
1891  * Converts the given #SeedValue into a #gdouble.
1892  *
1893  * Return value: The #gdouble represented by @val, or %NULL if an exception
1894  *               is raised during the conversion.
1895  *
1896  */
1897 gdouble
1898 seed_value_to_double (JSContextRef ctx,
1899                       JSValueRef val, JSValueRef * exception)
1900 {
1901   if (!JSValueIsNumber (ctx, val))
1902     {
1903       if (!JSValueIsNull (ctx, val))
1904         seed_make_exception (ctx, exception, "ConversionError",
1905                              "Can not convert Javascript value to" " double");
1906       return 0;
1907     }
1908
1909   return (gdouble) JSValueToNumber (ctx, val, NULL);
1910 }
1911
1912 /**
1913  * seed_value_from_double:
1914  * @ctx: A #SeedContext.
1915  * @val: The #gdouble to represent.
1916  * @exception: A reference to a #SeedValue in which to store any exceptions.
1917  *             Pass %NULL to ignore exceptions.
1918  *
1919  * Converts the given #gdouble into a #SeedValue.
1920  *
1921  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1922  *               is raised during the conversion.
1923  *
1924  */
1925 JSValueRef
1926 seed_value_from_double (JSContextRef ctx, gdouble val, JSValueRef * exception)
1927 {
1928   return JSValueMakeNumber (ctx, (gdouble) val);
1929 }
1930
1931 /**
1932  * seed_value_to_string:
1933  * @ctx: A #SeedContext.
1934  * @val: The #SeedValue to convert.
1935  * @exception: A reference to a #SeedValue in which to store any exceptions.
1936  *             Pass %NULL to ignore exceptions.
1937  *
1938  * Converts the given #SeedValue into a #gchar* string. Keep in mind that it's
1939  * up to the caller to free the string.
1940  *
1941  * If the #SeedValue represents JavaScript's undefined value, this returns
1942  * "[undefined]"; if it represents JavaScript's null value, this returns
1943  * "[null]".
1944  *
1945  * If the #SeedValue is a number or a boolean, it is printed as a double, with 
1946  * the printf format string "%.15g".
1947  *
1948  * If the #SeedValue is an object, the string returned is that obtained by
1949  * calling .toString() on said object.
1950  *
1951  * Return value: The #gchar* represented by @val, or %NULL if an exception
1952  *               is raised during the conversion.
1953  *
1954  */
1955 gchar *
1956 seed_value_to_string (JSContextRef ctx,
1957                       JSValueRef val, JSValueRef * exception)
1958 {
1959   JSStringRef jsstr = NULL;
1960   JSValueRef func, str;
1961   gchar *buf = NULL;
1962   gint length;
1963
1964   if (val == NULL)
1965     return NULL;
1966   else if (JSValueIsUndefined (ctx, val))
1967     {
1968       buf = g_strdup ("[undefined]");
1969     }
1970   else if (JSValueIsNull (ctx, val))
1971     {
1972       buf = g_strdup ("[null]");
1973     }
1974   else if (JSValueIsBoolean (ctx, val) || JSValueIsNumber (ctx, val))
1975     {
1976       buf = g_strdup_printf ("%.15g", JSValueToNumber (ctx, val, NULL));
1977     }
1978   else
1979     {
1980       if (!JSValueIsString (ctx, val))  // In this case,
1981         // it's an object
1982         {
1983           func =
1984             seed_object_get_property (ctx, (JSObjectRef) val, "toString");
1985           if (!JSValueIsNull (ctx, func) &&
1986               JSValueIsObject (ctx, func) &&
1987               JSObjectIsFunction (ctx, (JSObjectRef) func))
1988             str =
1989               JSObjectCallAsFunction (ctx, (JSObjectRef) func,
1990                                       (JSObjectRef) val, 0, NULL, NULL);
1991         }
1992       
1993       jsstr = JSValueToStringCopy (ctx, val, NULL);
1994       length = JSStringGetMaximumUTF8CStringSize (jsstr);
1995       if (length > 0)
1996         {
1997           buf = g_malloc (length * sizeof (gchar));
1998           JSStringGetUTF8CString (jsstr, buf, length);
1999         }
2000       if (jsstr)
2001         JSStringRelease (jsstr);
2002     }
2003
2004   return buf;
2005 }
2006
2007 /**
2008  * seed_value_from_string:
2009  * @ctx: A #SeedContext.
2010  * @val: The #gchar* to represent.
2011  * @exception: A reference to a #SeedValue in which to store any exceptions.
2012  *             Pass %NULL to ignore exceptions.
2013  *
2014  * Converts the given #gchar* string into a #SeedValue.
2015  *
2016  * Return value: A #SeedValue which represents @val, or %NULL if an exception
2017  *               is raised during the conversion.
2018  *
2019  */
2020 JSValueRef
2021 seed_value_from_string (JSContextRef ctx,
2022                         const gchar * val, JSValueRef * exception)
2023 {
2024   if (val == NULL)
2025     return JSValueMakeNull (ctx);
2026   else
2027     {
2028       JSStringRef jsstr = JSStringCreateWithUTF8CString (val);
2029       JSValueRef valstr = JSValueMakeString (ctx, jsstr);
2030       JSStringRelease (jsstr);
2031
2032       return valstr;
2033     }
2034 }
2035
2036 /**
2037  * seed_value_from_binary_string:
2038  * @ctx: A #SeedContext.
2039  * @bytes: A string of bytes to represent as a string.
2040  * @n_bytes: The number of bytes from @bytes to convert.
2041  * @exception: A reference to a #SeedValue in which to store any exceptions.
2042  *             Pass %NULL to ignore exceptions.
2043  *
2044  * Converts a string representation of the given binary string
2045  * into a #SeedValue.
2046  *
2047  * Return value: A #SeedValue which represents @bytes as a string, or %NULL
2048  *               if an exception is raised during the conversion.
2049  *
2050  */
2051 JSValueRef
2052 seed_value_from_binary_string (JSContextRef ctx,
2053                                const gchar * bytes,
2054                                gint n_bytes, JSValueRef * exception)
2055 {
2056   JSValueRef ret;
2057
2058   gchar *nstr = g_alloca ((n_bytes + 1) * sizeof (gchar));
2059   g_strlcpy (nstr, bytes, n_bytes);
2060   nstr[n_bytes] = '\0';
2061
2062   ret = seed_value_from_string (ctx, nstr, exception);
2063
2064   return ret;
2065 }
2066
2067 /**
2068  * seed_value_to_filename:
2069  * @ctx: A #SeedContext.
2070  * @val: The #SeedValue to convert.
2071  * @exception: A reference to a #SeedValue in which to store any exceptions.
2072  *             Pass %NULL to ignore exceptions.
2073  *
2074  * Converts the given #SeedValue into a #gchar*, properly converting to the 
2075  * character set used for filenames on the local machine.
2076  *
2077  * Return value: The #gchar* represented by @val, or %NULL if an exception
2078  *               is raised during the conversion.
2079  *
2080  */
2081 gchar *
2082 seed_value_to_filename (JSContextRef ctx,
2083                         JSValueRef val, JSValueRef * exception)
2084 {
2085   GError *e = NULL;
2086   gchar *utf8 = seed_value_to_string (ctx, val, exception);
2087   gchar *filename;
2088
2089   filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, &e);
2090   g_free (utf8);
2091   if (e)
2092     {
2093       seed_make_exception_from_gerror (ctx, exception, e);
2094       g_error_free (e);
2095       return NULL;
2096     }
2097
2098   return filename;
2099 }
2100
2101 /**
2102  * seed_value_from_filename:
2103  * @ctx: A #SeedContext.
2104  * @val: The #gchar* filename to represent.
2105  * @exception: A reference to a #SeedValue in which to store any exceptions.
2106  *             Pass %NULL to ignore exceptions.
2107  *
2108  * Converts the given #gchar* filename into a #SeedValue, respecting the 
2109  * character set used for filenames on the local machine.
2110  *
2111  * Return value: A #SeedValue which represents @val, or %NULL if an exception
2112  *               is raised during the conversion.
2113  *
2114  */
2115 JSValueRef
2116 seed_value_from_filename (JSContextRef ctx,
2117                           const gchar * val, JSValueRef * exception)
2118 {
2119   GError *e = NULL;
2120   gchar *utf8;
2121   
2122   if (val == NULL)
2123     return JSValueMakeNull (ctx);
2124   else
2125     {
2126       utf8 = g_filename_to_utf8 (val, -1, NULL, NULL, &e);
2127
2128       if (e)
2129         {
2130           seed_make_exception_from_gerror (ctx, exception, e);
2131           g_error_free (e);
2132           return JSValueMakeNull (ctx);
2133         }
2134
2135       JSValueRef valstr = seed_value_from_string (ctx, utf8, exception);
2136
2137       g_free (utf8);
2138
2139       return valstr;
2140     }
2141 }
2142
2143 /**
2144  * seed_value_to_object:
2145  * @ctx: A #SeedContext.
2146  * @val: The #SeedValue to unwrap.
2147  * @exception: A reference to a #SeedValue in which to store any exceptions.
2148  *             Pass %NULL to ignore exceptions.
2149  *
2150  * Given a #SeedValue which is wrapping a #GObject, retrieve the wrapped
2151  * #GObject.
2152  *
2153  * Return value: The #GObject wrapped within @val, or %NULL if an exception
2154  *               is raised during the conversion.
2155  *
2156  */
2157 GObject *
2158 seed_value_to_object (JSContextRef ctx,
2159                       JSValueRef val, JSValueRef * exception)
2160 {
2161   GObject *gobject;
2162
2163   /*
2164    * Worth investigating if this is the best way to handle null. Some of
2165    * the existing code depends on null Objects not throwing an exception
2166    * however, needs testing at higher level if value can be null
2167    * (through GI)
2168    */
2169
2170   if (JSValueIsNull (ctx, val))
2171     return NULL;
2172   if (!seed_value_is_gobject (ctx, val))
2173     {
2174       seed_make_exception (ctx, exception, "ConversionError",
2175                            "Attempt to convert from"
2176                            " non GObject to GObject");
2177       return NULL;
2178     }
2179
2180   gobject = (GObject *) JSObjectGetPrivate ((JSObjectRef) val);
2181   g_assert (G_IS_OBJECT (gobject));
2182
2183   return gobject;
2184 }
2185
2186 /**
2187  * seed_value_from_object:
2188  * @ctx: A #SeedContext.
2189  * @val: The #GObject to wrap.
2190  * @exception: A reference to a #SeedValue in which to store any exceptions.
2191  *             Pass %NULL to ignore exceptions.
2192  *
2193  * Wraps @val in a #SeedValue.
2194  *
2195  * Return value: A #SeedValue which wraps @val, or %NULL if an exception
2196  *               is raised during the conversion.
2197  *
2198  */
2199 JSValueRef
2200 seed_value_from_object (JSContextRef ctx,
2201                         GObject * val, JSValueRef * exception)
2202 {
2203   if (val == NULL)
2204     return JSValueMakeNull (ctx);
2205   else
2206     return seed_wrap_object (ctx, val);
2207 }
2208
2209 gboolean
2210 seed_validate_enum (GIEnumInfo * info, long val)
2211 {
2212   gint n, i;
2213   GIValueInfo *value_info;
2214   glong value;
2215
2216   n = g_enum_info_get_n_values (info);
2217   for (i = 0; i < n; i++)
2218     {
2219       value_info = g_enum_info_get_value (info, i);
2220       value = g_value_info_get_value (value_info);
2221
2222       g_base_info_unref ((GIBaseInfo *) value_info);
2223       if (value == val)
2224         return TRUE;
2225     }
2226
2227   return FALSE;
2228 }
2229
2230 JSValueRef
2231 seed_value_from_time_t (JSContextRef ctx, time_t time, JSValueRef * exception)
2232 {
2233   JSValueRef args[1];
2234
2235   args[0] = seed_value_from_double (ctx, ((gdouble) time) * 1000, exception);
2236   return JSObjectMakeDate (ctx, 1, args, exception);
2237 }
2238
2239 time_t
2240 seed_value_to_time_t (JSContextRef ctx,
2241                       JSValueRef value, JSValueRef * exception)
2242 {
2243   JSValueRef get_time_method;
2244   JSValueRef jstime;
2245   gdouble time;
2246
2247
2248   if (JSValueIsNumber (ctx, value))
2249     {
2250       return (unsigned long) seed_value_to_long (ctx, value, exception);
2251     }
2252   else if (JSValueIsObject (ctx, value))
2253     {
2254       get_time_method = seed_object_get_property (ctx, (JSObjectRef) value,
2255                                                   "getTime");
2256       if (JSValueIsNull (ctx, get_time_method) ||
2257           !JSValueIsObject (ctx, get_time_method))
2258         {
2259           goto out;
2260         }
2261       jstime = JSObjectCallAsFunction (ctx,
2262                                        (JSObjectRef) get_time_method,
2263                                        (JSObjectRef) value,
2264                                        0, NULL, exception);
2265       time = seed_value_to_double (ctx, jstime, exception);
2266       return (unsigned long) (time / 1000);
2267     }
2268
2269 out:
2270   seed_make_exception (ctx, exception,
2271                        "TypeError",
2272                        "Unable to convert JavaScript value to time_t");
2273   return 0;
2274 }