libseed: Improve integral type conversions; mostly portability issues
[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       arg->v_long = seed_value_to_long (ctx, value, exception);
489       break;
490     case GI_TYPE_TAG_INT64:
491       arg->v_int64 = seed_value_to_int64 (ctx, value, exception);
492       break;
493     case GI_TYPE_TAG_ULONG:
494       arg->v_ulong = seed_value_to_ulong (ctx, value, exception);
495       break;
496     case GI_TYPE_TAG_UINT64:
497       arg->v_uint64 = seed_value_to_uint64 (ctx, value, exception);
498       break;
499     case GI_TYPE_TAG_INT:
500       arg->v_int = seed_value_to_int (ctx, value, exception);
501       break;
502     case GI_TYPE_TAG_UINT:
503       arg->v_uint = seed_value_to_uint (ctx, value, exception);
504       break;
505     case GI_TYPE_TAG_SIZE:
506       arg->v_size = seed_value_to_size (ctx, value, exception);
507       break;
508     case GI_TYPE_TAG_SSIZE:
509       arg->v_ssize = seed_value_to_ssize (ctx, value, exception);
510       break;
511     case GI_TYPE_TAG_FLOAT:
512       arg->v_float = seed_value_to_float (ctx, value, exception);
513       break;
514     case GI_TYPE_TAG_DOUBLE:
515       arg->v_double = seed_value_to_double (ctx, value, exception);
516       break;
517     case GI_TYPE_TAG_UTF8:
518       arg->v_string = seed_value_to_string (ctx, value, exception);
519       break;
520     case GI_TYPE_TAG_FILENAME:
521       arg->v_string = seed_value_to_filename (ctx, value, exception);
522       break;
523     case GI_TYPE_TAG_GTYPE:
524       arg->v_int = seed_value_to_int (ctx, value, exception);
525       break;
526     case GI_TYPE_TAG_TIME_T:
527       arg->v_long = seed_value_to_time_t (ctx, value, exception);
528       break;
529     case GI_TYPE_TAG_INTERFACE:
530       {
531         GIBaseInfo *interface;
532         GIInfoType interface_type;
533         GType required_gtype;
534         GObject *gobject;
535
536         interface = g_type_info_get_interface (type_info);
537         interface_type = g_base_info_get_type (interface);
538
539         arg->v_pointer = NULL;
540
541         if (interface_type == GI_INFO_TYPE_OBJECT
542             || interface_type == GI_INFO_TYPE_INTERFACE)
543           {
544             gobject = seed_value_to_object (ctx, value, exception);
545             required_gtype =
546               g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)
547                                                  interface);
548
549             // FIXME: Not clear if the g_type_is_a check is desired here.
550             // Possibly 'breaks things' when we don't have introspection
551             // data for some things in an interface hierarchy. Hasn't
552             // provided any problems so far.
553             if (!gobject
554                 || !g_type_is_a (G_OBJECT_TYPE (gobject), required_gtype))
555               {
556                 g_base_info_unref (interface);
557                 return FALSE;
558               }
559
560             arg->v_pointer = gobject;
561             g_base_info_unref (interface);
562             break;
563           }
564         else if (interface_type == GI_INFO_TYPE_ENUM ||
565                  interface_type == GI_INFO_TYPE_FLAGS)
566           {
567             arg->v_long = seed_value_to_long (ctx, value, exception);
568             if (!(interface_type == GI_INFO_TYPE_FLAGS)
569                 && !seed_validate_enum ((GIEnumInfo *) interface,
570                                         arg->v_long))
571               {
572                 seed_make_exception (ctx, exception, "EnumRange",
573                                      "Enum value: %ld is out of range",
574                                      arg->v_long);
575                 g_base_info_unref (interface);
576
577                 return FALSE;
578               }
579
580             g_base_info_unref (interface);
581             break;
582           }
583         else if (interface_type == GI_INFO_TYPE_STRUCT)
584           {
585             if (JSValueIsObjectOfClass (ctx, value, seed_struct_class))
586               arg->v_pointer = seed_pointer_get_pointer (ctx, value);
587             else
588               {
589                 GType type =
590                   g_registered_type_info_get_g_type ((GIRegisteredTypeInfo
591                                                       *) interface);
592                 if (!type)
593                   {
594                     g_base_info_unref (interface);
595                     return FALSE;
596                   }
597                 else if (type == G_TYPE_VALUE)
598                   {
599                     GValue *gval = g_slice_alloc0 (sizeof (GValue));
600                     seed_gvalue_from_seed_value (ctx,
601                                                  value,
602                                                  (GType) NULL,
603                                                  gval, exception);
604                     arg->v_pointer = gval;
605
606                     g_base_info_unref (interface);
607                     break;
608                   }
609                 // Automatically convert between functions and
610                 // GClosures where expected.
611                 else if (g_type_is_a (type, G_TYPE_CLOSURE))
612                   {
613                     if (JSObjectIsFunction (ctx, (JSObjectRef) value))
614                       {
615                         arg->v_pointer =
616                           seed_closure_new (ctx, (JSObjectRef) value, NULL,
617                                             NULL);
618                       }
619                   }
620                 else
621                   {
622                     JSObjectRef strukt =
623                       seed_construct_struct_type_with_parameters (ctx,
624                                                                   interface,
625                                                                   (JSObjectRef) value,
626                                                                   exception);
627                     arg->v_pointer = seed_pointer_get_pointer (ctx, strukt);
628                   }
629               }
630             g_base_info_unref (interface);
631             break;
632           }
633         else if (interface_type == GI_INFO_TYPE_CALLBACK)
634           {
635             if (JSValueIsNull (ctx, value))
636               {
637                 arg->v_pointer = NULL;
638                 g_base_info_unref (interface);
639                 break;
640               }
641             // Someone passes in a wrapper around a method where a
642             // callback is expected, i.e Clutter.sine_inc_func, as an alpha
643             // Have to dlsym the symbol to be able to do this.
644             // NOTE: Some cases where dlsym(NULL, symbol) doesn't work depending
645             // On how libseed is loaded.
646             else if (JSValueIsObjectOfClass (ctx,
647                                              value, gobject_method_class))
648               {
649                 GIFunctionInfo *info =
650                   JSObjectGetPrivate ((JSObjectRef) value);
651                 const gchar *symbol = g_function_info_get_symbol (info);
652                 gchar *error;
653                 void *fp;
654
655                 dlerror ();
656                 fp = (void *) dlsym (0, symbol);
657                 if ((error = dlerror ()) != NULL)
658                   {
659                     g_critical ("dlerror: %s \n", error);
660                   }
661                 else
662                   {
663                     arg->v_pointer = fp;
664                     g_base_info_unref (interface);
665                     break;
666                   }
667               }
668             // Somewhat deprecated from when it was necessary to manually
669             // create closure objects...
670             else if (JSValueIsObjectOfClass (ctx,
671                                              value,
672                                              seed_native_callback_class))
673               {
674                 SeedNativeClosure *privates =
675                   (SeedNativeClosure *)
676                   JSObjectGetPrivate ((JSObjectRef) value);
677                 arg->v_pointer = privates->closure;
678                 g_base_info_unref (interface);
679                 break;
680               }
681             // Automagically create closure around function passed in as
682             // callback.
683             else if (JSObjectIsFunction (ctx, (JSObjectRef) value))
684               {
685                 SeedNativeClosure *privates = seed_make_native_closure (ctx,
686                                                                         (GICallableInfo *) interface,
687                                                                         value);
688                 arg->v_pointer = privates->closure;
689                 g_base_info_unref (interface);
690                 break;
691               }
692
693           }
694       }
695     case GI_TYPE_TAG_ARRAY:
696       {
697         if (JSValueIsNull (ctx, value))
698           {
699             arg->v_pointer = NULL;
700             break;
701           }
702         else if (!JSValueIsObject (ctx, value))
703           {
704             // TODO: FIXME: Is this right?
705             return FALSE;
706           }
707         else
708           {
709             GITypeInfo *param_type;
710             //TODO: FIXME: Better array test like the cool one on reddit.
711             guint length =
712               seed_value_to_int (ctx, seed_object_get_property (ctx,
713                                                                 (JSObjectRef)
714                                                                 value,
715                                                                 "length"),
716                                  exception);
717             if (!length)
718               {
719                 arg->v_pointer = NULL;
720                 break;
721               }
722
723             param_type = g_type_info_get_param_type (type_info, 0);
724             if (!seed_gi_make_array (ctx, value, length, param_type,
725                                      &arg->v_pointer, exception))
726               {
727                 g_base_info_unref ((GIBaseInfo *) param_type);
728                 return FALSE;
729               }
730             g_base_info_unref ((GIBaseInfo *) param_type);
731             break;
732           }
733       }
734     default:
735       return FALSE;
736
737     }
738   return TRUE;
739
740 }
741
742 JSValueRef
743 seed_gi_argument_make_js (JSContextRef ctx,
744                           GArgument * arg, GITypeInfo * type_info,
745                           JSValueRef * exception)
746 {
747   GITypeTag gi_tag = g_type_info_get_tag (type_info);
748   switch (gi_tag)
749     {
750     case GI_TYPE_TAG_VOID:
751       return JSValueMakeUndefined (ctx);
752     case GI_TYPE_TAG_BOOLEAN:
753       return seed_value_from_boolean (ctx, arg->v_boolean, exception);
754     case GI_TYPE_TAG_INT8:
755       return seed_value_from_char (ctx, arg->v_int8, exception);
756     case GI_TYPE_TAG_UINT8:
757       return seed_value_from_uchar (ctx, arg->v_uint8, exception);
758     case GI_TYPE_TAG_INT16:
759       return seed_value_from_int (ctx, arg->v_int16, exception);
760     case GI_TYPE_TAG_UINT16:
761       return seed_value_from_uint (ctx, arg->v_uint16, exception);
762     case GI_TYPE_TAG_INT32:
763       return seed_value_from_int (ctx, arg->v_int32, exception);
764     case GI_TYPE_TAG_UINT32:
765       return seed_value_from_uint (ctx, arg->v_uint32, exception);
766     case GI_TYPE_TAG_LONG:
767       return seed_value_from_long (ctx, arg->v_long, exception);
768     case GI_TYPE_TAG_INT64:
769       return seed_value_from_int64 (ctx, arg->v_int64, exception);
770     case GI_TYPE_TAG_ULONG:
771       return seed_value_from_ulong (ctx, arg->v_ulong, exception);
772     case GI_TYPE_TAG_UINT64:
773       return seed_value_from_uint64 (ctx, arg->v_uint64, exception);
774     case GI_TYPE_TAG_INT:
775       return seed_value_from_int (ctx, arg->v_int32, exception);
776     case GI_TYPE_TAG_UINT:
777       return seed_value_from_uint (ctx, arg->v_uint32, exception);
778     case GI_TYPE_TAG_SSIZE:
779       return seed_value_from_ssize (ctx, arg->v_ssize, exception);
780     case GI_TYPE_TAG_SIZE:
781       return seed_value_from_size (ctx, arg->v_size, exception);
782     case GI_TYPE_TAG_FLOAT:
783       return seed_value_from_float (ctx, arg->v_float, exception);
784     case GI_TYPE_TAG_DOUBLE:
785       return seed_value_from_double (ctx, arg->v_double, exception);
786     case GI_TYPE_TAG_UTF8:
787       return seed_value_from_string (ctx, arg->v_string, exception);
788     case GI_TYPE_TAG_FILENAME:
789       return seed_value_from_filename (ctx, arg->v_string, exception);
790     case GI_TYPE_TAG_GTYPE:
791       return seed_value_from_int (ctx, arg->v_int, exception);
792     case GI_TYPE_TAG_TIME_T:
793       return seed_value_from_time_t (ctx, arg->v_long, exception);
794     case GI_TYPE_TAG_ARRAY:
795       {
796         GITypeInfo *param_type;
797         JSValueRef ret;
798
799         if (arg->v_pointer == NULL)
800           return JSValueMakeNull (ctx);
801         if (!g_type_info_is_zero_terminated (type_info))
802           break;
803
804         param_type = g_type_info_get_param_type (type_info, 0);
805
806         ret = seed_gi_make_jsarray (ctx, arg->v_pointer, param_type,
807                                     exception);
808
809         g_base_info_unref ((GIBaseInfo *) param_type);
810
811         return ret;
812       }
813     case GI_TYPE_TAG_INTERFACE:
814       {
815         GIBaseInfo *interface;
816         GIInfoType interface_type;
817
818         interface = g_type_info_get_interface (type_info);
819         interface_type = g_base_info_get_type (interface);
820
821         if (interface_type == GI_INFO_TYPE_OBJECT ||
822             interface_type == GI_INFO_TYPE_INTERFACE)
823           {
824             if (arg->v_pointer == 0)
825               {
826                 g_base_info_unref (interface);
827                 return JSValueMakeNull (ctx);
828               }
829             g_base_info_unref (interface);
830             return seed_value_from_object (ctx, arg->v_pointer, exception);
831           }
832         else if (interface_type == GI_INFO_TYPE_ENUM
833                  || interface_type == GI_INFO_TYPE_FLAGS)
834           {
835             g_base_info_unref (interface);
836             return seed_value_from_long (ctx, arg->v_long, exception);
837           }
838         else if (interface_type == GI_INFO_TYPE_STRUCT)
839           {
840             JSValueRef strukt;
841
842             strukt = seed_make_struct (ctx, arg->v_pointer, interface);
843             g_base_info_unref (interface);
844
845             return strukt;
846           }
847       }
848     case GI_TYPE_TAG_GLIST:
849       {
850         GITypeInfo *list_type;
851         JSObjectRef ret;
852         GArgument larg;
853         gint i = 0;
854         GList *list = arg->v_pointer;
855
856         ret = JSObjectMakeArray (ctx, 0, NULL, exception);
857         list_type = g_type_info_get_param_type (type_info, 0);
858
859         for (; list != NULL; list = list->next)
860           {
861             JSValueRef ival;
862
863             larg.v_pointer = list->data;
864             ival =
865               (JSValueRef) seed_gi_argument_make_js (ctx, &larg,
866                                                      list_type, exception);
867             if (!ival)
868               ival = JSValueMakeNull (ctx);
869             JSObjectSetPropertyAtIndex (ctx, ret, i, ival, NULL);
870             i++;
871           }
872         return ret;
873
874       }
875     case GI_TYPE_TAG_GSLIST:
876       {
877         GITypeInfo *list_type;
878         JSObjectRef ret;
879         JSValueRef ival;
880         GArgument larg;
881         guint i = 0;
882         GSList *list = arg->v_pointer;
883
884         ret = JSObjectMakeArray (ctx, 0, NULL, exception);
885         list_type = g_type_info_get_param_type (type_info, 0);
886
887         for (; list != NULL; list = list->next)
888           {
889             larg.v_pointer = list->data;
890             ival =
891               (JSValueRef) seed_gi_argument_make_js (ctx, &larg,
892                                                      list_type, exception);
893             if (!ival)
894               ival = JSValueMakeNull (ctx);
895             JSObjectSetPropertyAtIndex (ctx, ret, i, ival, NULL);
896             i++;
897           }
898         return ret;
899       }
900
901     default:
902       return FALSE;
903
904     }
905   return 0;
906 }
907
908 JSValueRef
909 seed_value_from_gvalue (JSContextRef ctx,
910                         GValue * gval, JSValueRef * exception)
911 {
912   if (!G_IS_VALUE (gval))
913     {
914       return false;
915     }
916   switch (G_VALUE_TYPE (gval))
917     {
918     case G_TYPE_BOOLEAN:
919       return seed_value_from_boolean (ctx,
920                                       g_value_get_boolean (gval), exception);
921     case G_TYPE_CHAR:
922       return seed_value_from_char (ctx, g_value_get_char (gval), exception);
923     case G_TYPE_UCHAR:
924       return seed_value_from_uchar (ctx, g_value_get_uchar (gval), exception);
925     case G_TYPE_INT:
926       return seed_value_from_int (ctx, g_value_get_int (gval), exception);
927     case G_TYPE_UINT:
928       return seed_value_from_uint (ctx, g_value_get_uint (gval), exception);
929     case G_TYPE_LONG:
930       return seed_value_from_long (ctx, g_value_get_long (gval), exception);
931     case G_TYPE_ULONG:
932       return seed_value_from_ulong (ctx, g_value_get_ulong (gval), exception);
933     case G_TYPE_INT64:
934       return seed_value_from_int64 (ctx, g_value_get_int64 (gval), exception);
935     case G_TYPE_UINT64:
936       return seed_value_from_uint64 (ctx, g_value_get_uint64 (gval),
937                                      exception);
938     case G_TYPE_FLOAT:
939       return seed_value_from_float (ctx, g_value_get_float (gval), exception);
940     case G_TYPE_DOUBLE:
941       return seed_value_from_double (ctx, g_value_get_double (gval),
942                                      exception);
943     case G_TYPE_STRING:
944       return seed_value_from_string (ctx, (gchar *)
945                                      g_value_get_string (gval), exception);
946     case G_TYPE_POINTER:
947       return seed_make_pointer (ctx, g_value_get_pointer (gval));
948     case G_TYPE_PARAM:
949       // Might need to dup and make a boxed.
950       return seed_make_pointer (ctx, g_value_get_param (gval));
951     }
952
953   if (g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_ENUM) ||
954       g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_FLAGS))
955     return seed_value_from_long (ctx, gval->data[0].v_long, exception);
956   else if (g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_ENUM))
957     return seed_value_from_long (ctx, gval->data[0].v_long, exception);
958   else if (g_type_is_a (G_VALUE_TYPE (gval), G_TYPE_OBJECT))
959     {
960       GObject *obj = g_value_get_object (gval);
961       return seed_value_from_object (ctx, obj, exception);
962     }
963   else
964     {
965       GIBaseInfo *info;
966       GIInfoType type;
967
968       info = g_irepository_find_by_gtype (0, G_VALUE_TYPE (gval));
969       if (!info)
970         return FALSE;
971       type = g_base_info_get_type (info);
972
973       if (type == GI_INFO_TYPE_UNION)
974         {
975           return seed_make_union (ctx, g_value_peek_pointer (gval), info);
976         }
977       else if (type == GI_INFO_TYPE_STRUCT)
978         {
979           return seed_make_struct (ctx, g_value_peek_pointer (gval), info);
980         }
981       else if (type == GI_INFO_TYPE_BOXED)
982         {
983           return seed_make_boxed (ctx, g_value_dup_boxed (gval), info);
984         }
985
986     }
987
988   return NULL;
989 }
990
991 gboolean
992 seed_gvalue_from_seed_value (JSContextRef ctx,
993                              JSValueRef val,
994                              GType type, GValue * ret, JSValueRef * exception)
995 {
996   if (G_IS_VALUE (ret))
997     g_value_unset (ret);
998
999  if (type == G_TYPE_STRV)
1000     {
1001       gchar **result;
1002       JSValueRef jslen;
1003       guint length, i;
1004       
1005       if (JSValueIsNull (ctx, val) || !JSValueIsObject (ctx, val))
1006         return FALSE;
1007       
1008       jslen = seed_object_get_property (ctx, (JSObjectRef) val, "length");
1009       length = seed_value_to_uint (ctx, jslen, exception);
1010       
1011       result = g_new0 (gchar *, length+1);
1012       
1013       for (i = 0; i < length; i++)
1014         {
1015           result[i] = seed_value_to_string (ctx,
1016                                             JSObjectGetPropertyAtIndex (ctx,
1017                                                                         (JSObjectRef)
1018                                                                         val,
1019                                                                         i,
1020                                                                         exception),
1021                                             exception);
1022           
1023         }
1024       result[i] = 0;
1025       
1026       g_value_init (ret, G_TYPE_STRV);
1027       g_value_take_boxed (ret, result);
1028       
1029         return TRUE;
1030     }
1031   else if (g_type_is_a (type, G_TYPE_ENUM) && JSValueIsNumber (ctx, val))
1032     {
1033       g_value_init (ret, type);
1034       g_value_set_enum (ret, seed_value_to_long (ctx, val, exception));
1035       return TRUE;
1036     }
1037   else if (g_type_is_a (type, G_TYPE_FLAGS) && JSValueIsNumber (ctx, val))
1038     {
1039       g_value_init (ret, type);
1040       g_value_set_flags (ret, seed_value_to_long (ctx, val, exception));
1041       return TRUE;
1042     }
1043   else if (g_type_is_a (type, G_TYPE_OBJECT)
1044            && (JSValueIsNull (ctx, val) || seed_value_is_gobject (ctx, val)))
1045     {
1046       GObject *o = seed_value_to_object (ctx,
1047                                          val, exception);
1048
1049       if (o == NULL || g_type_is_a (G_OBJECT_TYPE (o), type))
1050         {
1051           g_value_init (ret, G_TYPE_OBJECT);
1052           g_value_set_object (ret, o);
1053
1054           return TRUE;
1055         }
1056     }
1057   /* Boxed handling is broken. Will be fixed in struct overhall. */
1058   else if (g_type_is_a (type, G_TYPE_BOXED))
1059     {
1060       gpointer p = seed_pointer_get_pointer (ctx, val);
1061       if (p)
1062         {
1063           g_value_init (ret, type);
1064           g_value_set_boxed (ret, p);
1065           return TRUE;
1066         }
1067       else
1068         {
1069           if (JSValueIsObject (ctx, val))
1070             {
1071               GIBaseInfo *info = g_irepository_find_by_gtype (0, type);
1072               JSObjectRef new_struct;
1073               if (!info)
1074                 return FALSE;
1075
1076               new_struct =
1077                 seed_construct_struct_type_with_parameters (ctx,
1078                                                             info,
1079                                                             (JSObjectRef)
1080                                                             val, exception);
1081               p = seed_pointer_get_pointer (ctx, new_struct);
1082               if (p)
1083                 {
1084                   g_value_init (ret, type);
1085                   g_value_set_boxed (ret, p);
1086                   g_base_info_unref (info);
1087                   return TRUE;
1088                 }
1089               g_base_info_unref (info);
1090             }
1091         }
1092     }
1093
1094   switch (type)
1095     {
1096     case G_TYPE_BOOLEAN:
1097       {
1098         g_value_init (ret, G_TYPE_BOOLEAN);
1099         g_value_set_boolean (ret, seed_value_to_boolean (ctx,
1100                                                          val, exception));
1101         return TRUE;
1102       }
1103     case G_TYPE_INT:
1104     case G_TYPE_UINT:
1105       {
1106         g_value_init (ret, type);
1107         if (type == G_TYPE_INT)
1108           g_value_set_int (ret, seed_value_to_int (ctx, val, exception));
1109         else
1110           g_value_set_uint (ret, seed_value_to_uint (ctx, val, exception));
1111         return TRUE;
1112       }
1113     case G_TYPE_CHAR:
1114       {
1115         g_value_init (ret, G_TYPE_CHAR);
1116         g_value_set_char (ret, seed_value_to_char (ctx, val, exception));
1117         return TRUE;
1118       }
1119     case G_TYPE_UCHAR:
1120       {
1121         g_value_init (ret, G_TYPE_UCHAR);
1122         g_value_set_uchar (ret, seed_value_to_uchar (ctx, val, exception));
1123         return TRUE;
1124       }
1125     case G_TYPE_LONG:
1126     case G_TYPE_ULONG:
1127     case G_TYPE_INT64:
1128     case G_TYPE_UINT64:
1129     case G_TYPE_FLOAT:
1130     case G_TYPE_DOUBLE:
1131       {
1132         switch (type)
1133           {
1134           case G_TYPE_LONG:
1135             g_value_init (ret, G_TYPE_LONG);
1136             g_value_set_long (ret, seed_value_to_long (ctx, val, exception));
1137             break;
1138           case G_TYPE_ULONG:
1139             g_value_init (ret, G_TYPE_ULONG);
1140             g_value_set_ulong (ret, seed_value_to_ulong (ctx,
1141                                                          val, exception));
1142             break;
1143           case G_TYPE_INT64:
1144             g_value_init (ret, G_TYPE_INT64);
1145             g_value_set_int64 (ret, seed_value_to_int64 (ctx,
1146                                                          val, exception));
1147             break;
1148           case G_TYPE_UINT64:
1149             g_value_init (ret, G_TYPE_UINT64);
1150             g_value_set_uint64 (ret, seed_value_to_uint64 (ctx,
1151                                                            val, exception));
1152             break;
1153           case G_TYPE_FLOAT:
1154             g_value_init (ret, G_TYPE_FLOAT);
1155             g_value_set_float (ret, seed_value_to_float (ctx,
1156                                                          val, exception));
1157             break;
1158           case G_TYPE_DOUBLE:
1159             g_value_init (ret, G_TYPE_DOUBLE);
1160             g_value_set_double (ret, seed_value_to_double (ctx,
1161                                                            val, exception));
1162             break;
1163           }
1164         return TRUE;
1165       }
1166     case G_TYPE_STRING:
1167       {
1168         gchar *cval = seed_value_to_string (ctx, val, exception);
1169
1170         g_value_init (ret, G_TYPE_STRING);
1171         g_value_take_string (ret, cval);
1172
1173         return TRUE;
1174       }
1175     default:
1176       {
1177         // TODO: FIXME: This whole undefined type area
1178         // needs some heaaavy improvement.
1179
1180         // Support [GObject.TYPE_INT, 3]
1181         // TODO: FIXME: Might crash.
1182         if (type == 0 && JSValueIsObject (ctx, val))
1183           {
1184             // TODO: FIXME: Better array test like the cool one on reddit.
1185             guint length = seed_value_to_int (ctx,
1186                                               seed_object_get_property (ctx,
1187                                                                         (JSObjectRef) val,
1188                                                                         "length"),
1189                                               exception);
1190
1191             if (length)
1192               {
1193                 type =
1194                   seed_value_to_int (ctx,
1195                                      JSObjectGetPropertyAtIndex (ctx,
1196                                                                  (JSObjectRef)
1197                                                                  val, 0,
1198                                                                  exception),
1199                                      exception);
1200                 val =
1201                   JSObjectGetPropertyAtIndex (ctx, (JSObjectRef) val, 1,
1202                                               exception);
1203                 if (type)       // Prevents recursion.
1204                   {
1205                     return seed_gvalue_from_seed_value (ctx, val,
1206                                                         type, ret, exception);
1207                   }
1208                 // TODO: FIXME: Handle better?
1209                 else
1210                   g_assert_not_reached ();
1211               }
1212           }
1213         switch (JSValueGetType (ctx, val))
1214           {
1215           case kJSTypeBoolean:
1216             {
1217               g_value_init (ret, G_TYPE_BOOLEAN);
1218               g_value_set_boolean (ret,
1219                                    seed_value_to_boolean (ctx,
1220                                                           val, exception));
1221               return TRUE;
1222             }
1223           case kJSTypeNumber:
1224             {
1225               g_value_init (ret, G_TYPE_DOUBLE);
1226               g_value_set_double (ret,
1227                                   seed_value_to_double (ctx, val, exception));
1228               return TRUE;
1229             }
1230           case kJSTypeString:
1231             {
1232               gchar *cv = seed_value_to_string (ctx, val,
1233                                                 exception);
1234
1235               g_value_init (ret, G_TYPE_STRING);
1236               g_value_take_string (ret, cv);
1237               return TRUE;
1238             }
1239           default:
1240             break;
1241           }
1242         break;
1243       }
1244     }
1245
1246    return FALSE;
1247 }
1248
1249 /**
1250  * seed_object_get_property
1251  * @ctx: A #SeedContext
1252  * @object: A #SeedObject
1253  * @name: The property to get, should be a valid JavaScript identifier
1254  *
1255  * Returns: The value of the property or %NULL
1256  */
1257 JSValueRef
1258 seed_object_get_property (JSContextRef ctx,
1259                           JSObjectRef val, const gchar * name)
1260 {
1261
1262   JSStringRef jname = JSStringCreateWithUTF8CString (name);
1263   JSValueRef ret = JSObjectGetProperty (ctx,
1264                                         (JSObjectRef) val,
1265                                         jname, NULL);
1266
1267   JSStringRelease (jname);
1268
1269   return ret;
1270 }
1271
1272 /**
1273  * seed_object_set_property
1274  * @ctx: A #SeedContext
1275  * @object: A #SeedObject
1276  * @name: The property to set, should be a valid JavaScript identifier
1277  * @value: The value to set the property to.
1278  *
1279  * Returns: %TRUE on success, %FALSE otherwise.
1280  */
1281 gboolean
1282 seed_object_set_property (JSContextRef ctx, JSObjectRef object,
1283                           const gchar * name, JSValueRef value)
1284 {
1285   JSStringRef jname = JSStringCreateWithUTF8CString (name);
1286   JSValueRef exception = NULL;
1287
1288   if (value)
1289     {
1290       JSObjectSetProperty (ctx, (JSObjectRef) object, jname, value, 0,
1291                            &exception);
1292     }
1293
1294   JSStringRelease (jname);
1295
1296   return TRUE;
1297 }
1298
1299 /* TODO: Make some macros or something for making exceptions, code is littered
1300    with annoyingness right now */
1301
1302 /**
1303  * seed_value_to_boolean:
1304  * @ctx: A #SeedContext.
1305  * @val: The #SeedValue to convert.
1306  * @exception: A reference to a #SeedValue in which to store any exceptions.
1307  *             Pass %NULL to ignore exceptions.
1308  *
1309  * Converts the given #SeedValue into a #gboolean. Keep in mind that this will
1310  * not convert a JavaScript number type, only a boolean.
1311  *
1312  * Return value: The #gboolean represented by @val, or %NULL if an exception
1313  *               is raised during the conversion.
1314  *
1315  */
1316 gboolean
1317 seed_value_to_boolean (JSContextRef ctx,
1318                        JSValueRef val, JSValueRef * exception)
1319 {
1320   if (!JSValueIsBoolean (ctx, val) && !JSValueIsNumber (ctx, val))
1321     {
1322       if (!JSValueIsNull (ctx, val))
1323         {
1324           seed_make_exception (eng->context, exception, "ConversionError",
1325                                "Can not convert Javascript value to boolean");
1326           return FALSE;
1327         }
1328
1329       return FALSE;
1330     }
1331
1332   return JSValueToBoolean (ctx, val);
1333 }
1334
1335 /**
1336  * seed_value_from_boolean:
1337  * @ctx: A #SeedContext.
1338  * @val: The #gboolean to represent.
1339  * @exception: A reference to a #SeedValue in which to store any exceptions.
1340  *             Pass %NULL to ignore exceptions.
1341  *
1342  * Converts the given #gboolean into a #SeedValue.
1343  *
1344  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1345  *               is raised during the conversion.
1346  *
1347  */
1348 JSValueRef
1349 seed_value_from_boolean (JSContextRef ctx,
1350                          gboolean val, JSValueRef * exception)
1351 {
1352   return JSValueMakeBoolean (ctx, val);
1353 }
1354
1355 /**
1356  * seed_value_to_uint:
1357  * @ctx: A #SeedContext.
1358  * @val: The #SeedValue to convert.
1359  * @exception: A reference to a #SeedValue in which to store any exceptions.
1360  *             Pass %NULL to ignore exceptions.
1361  *
1362  * Converts the given #SeedValue into a #guint.
1363  *
1364  * Return value: The #guint represented by @val, or %NULL if an exception
1365  *               is raised during the conversion.
1366  *
1367  */
1368 guint
1369 seed_value_to_uint (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1370 {
1371   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1372     {
1373       if (!JSValueIsNull (ctx, val))
1374         {
1375           seed_make_exception (ctx, exception, "ConversionError",
1376                                "Can not convert Javascript value to"
1377                                " boolean");
1378         }
1379       return 0;
1380     }
1381
1382   return (guint) JSValueToNumber (ctx, val, NULL);
1383 }
1384
1385 /**
1386  * seed_value_from_uint:
1387  * @ctx: A #SeedContext.
1388  * @val: The #guint to represent.
1389  * @exception: A reference to a #SeedValue in which to store any exceptions.
1390  *             Pass %NULL to ignore exceptions.
1391  *
1392  * Converts the given #guint into a #SeedValue.
1393  *
1394  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1395  *               is raised during the conversion.
1396  *
1397  */
1398 JSValueRef
1399 seed_value_from_uint (JSContextRef ctx, guint val, JSValueRef * exception)
1400 {
1401   return JSValueMakeNumber (ctx, (gdouble) val);
1402 }
1403
1404 /**
1405  * seed_value_to_int:
1406  * @ctx: A #SeedContext.
1407  * @val: The #SeedValue to convert.
1408  * @exception: A reference to a #SeedValue in which to store any exceptions.
1409  *             Pass %NULL to ignore exceptions.
1410  *
1411  * Converts the given #SeedValue into a #gint.
1412  *
1413  * Return value: The #gint represented by @val, or %NULL if an exception
1414  *               is raised during the conversion.
1415  *
1416  */
1417 gint
1418 seed_value_to_int (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1419 {
1420   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1421     {
1422       if (!JSValueIsNull (ctx, val))
1423         seed_make_exception (ctx, exception, "ConversionError",
1424                              "Can not convert Javascript value to" " int");
1425       return 0;
1426     }
1427
1428   return (gint) JSValueToNumber (ctx, val, NULL);
1429 }
1430
1431 /**
1432  * seed_value_from_int:
1433  * @ctx: A #SeedContext.
1434  * @val: The #gint to represent.
1435  * @exception: A reference to a #SeedValue in which to store any exceptions.
1436  *             Pass %NULL to ignore exceptions.
1437  *
1438  * Converts the given #gint into a #SeedValue.
1439  *
1440  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1441  *               is raised during the conversion.
1442  *
1443  */
1444 JSValueRef
1445 seed_value_from_int (JSContextRef ctx, gint val, JSValueRef * exception)
1446 {
1447   return JSValueMakeNumber (ctx, (gdouble) val);
1448 }
1449
1450 /**
1451  * seed_value_to_char:
1452  * @ctx: A #SeedContext.
1453  * @val: The #SeedValue to convert.
1454  * @exception: A reference to a #SeedValue in which to store any exceptions.
1455  *             Pass %NULL to ignore exceptions.
1456  *
1457  * Converts the given #SeedValue into a #gchar.
1458  *
1459  * Return value: The #gchar represented by @val, or %NULL if an exception
1460  *               is raised during the conversion.
1461  *
1462  */
1463 gchar
1464 seed_value_to_char (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1465 {
1466   gint cv;
1467
1468   if (!JSValueIsNumber (ctx, val))
1469     {
1470       if (!JSValueIsNull (ctx, val))
1471         seed_make_exception (ctx, exception, "ConversionError",
1472                              "Can not convert Javascript value to" " gchar");
1473       return 0;
1474     }
1475
1476   cv = JSValueToNumber (ctx, val, NULL);
1477
1478   if (cv < G_MININT8 || cv > G_MAXINT8)
1479     {
1480       seed_make_exception (ctx, exception, "ConversionError",
1481                            "Javascript number out of range of gchar");
1482       return 0;
1483     }
1484
1485   return (gchar) cv;
1486 }
1487
1488 /**
1489  * seed_value_from_char:
1490  * @ctx: A #SeedContext.
1491  * @val: The #gchar to represent.
1492  * @exception: A reference to a #SeedValue in which to store any exceptions.
1493  *             Pass %NULL to ignore exceptions.
1494  *
1495  * Converts the given #gchar into a #SeedValue.
1496  *
1497  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1498  *               is raised during the conversion.
1499  *
1500  */
1501 JSValueRef
1502 seed_value_from_char (JSContextRef ctx, gchar val, JSValueRef * exception)
1503 {
1504   return JSValueMakeNumber (ctx, (gdouble) val);
1505 }
1506
1507 /**
1508  * seed_value_to_uchar:
1509  * @ctx: A #SeedContext.
1510  * @val: The #SeedValue to convert.
1511  * @exception: A reference to a #SeedValue in which to store any exceptions.
1512  *             Pass %NULL to ignore exceptions.
1513  *
1514  * Converts the given #SeedValue into a #guchar.
1515  *
1516  * Return value: The #guchar represented by @val, or %NULL if an exception
1517  *               is raised during the conversion.
1518  *
1519  */
1520 guchar
1521 seed_value_to_uchar (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1522 {
1523   guint cv;
1524
1525   if (!JSValueIsNumber (ctx, val))
1526     {
1527       if (!JSValueIsNull (ctx, val))
1528         seed_make_exception (ctx, exception, "ConversionError",
1529                              "Can not convert Javascript value to" " guchar");
1530       return 0;
1531     }
1532
1533   cv = JSValueToNumber (ctx, val, NULL);
1534
1535   if (cv > G_MAXUINT8)
1536     {
1537       seed_make_exception (ctx, exception, "ConversionError",
1538                            "Javascript number out of range of guchar");
1539       return 0;
1540     }
1541
1542   return (guchar) cv;
1543 }
1544
1545 /**
1546  * seed_value_from_uchar:
1547  * @ctx: A #SeedContext.
1548  * @val: The #guchar to represent.
1549  * @exception: A reference to a #SeedValue in which to store any exceptions.
1550  *             Pass %NULL to ignore exceptions.
1551  *
1552  * Converts the given #guchar into a #SeedValue.
1553  *
1554  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1555  *               is raised during the conversion.
1556  *
1557  */
1558 JSValueRef
1559 seed_value_from_uchar (JSContextRef ctx, guchar val, JSValueRef * exception)
1560 {
1561   return JSValueMakeNumber (ctx, (gdouble) val);
1562 }
1563
1564 /**
1565  * seed_value_to_short:
1566  * @ctx: A #SeedContext.
1567  * @val: The #SeedValue to convert.
1568  * @exception: A reference to a #SeedValue in which to store any exceptions.
1569  *             Pass %NULL to ignore exceptions.
1570  *
1571  * Converts the given #SeedValue into a #gshort.
1572  *
1573  * Return value: The #gshort represented by @val, or %NULL if an exception
1574  *               is raised during the conversion.
1575  *
1576  */
1577 gshort
1578 seed_value_to_short (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1579 {
1580   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1581     {
1582       if (!JSValueIsNull (ctx, val))
1583         seed_make_exception (ctx, exception, "ConversionError",
1584                              "Can not convert Javascript value to" " short");
1585       return 0;
1586     }
1587
1588   return (gshort) JSValueToNumber (ctx, val, NULL);
1589 }
1590
1591 /**
1592  * seed_value_from_short:
1593  * @ctx: A #SeedContext.
1594  * @val: The #gshort to represent.
1595  * @exception: A reference to a #SeedValue in which to store any exceptions.
1596  *             Pass %NULL to ignore exceptions.
1597  *
1598  * Converts the given #gshort into a #SeedValue.
1599  *
1600  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1601  *               is raised during the conversion.
1602  *
1603  */
1604 JSValueRef
1605 seed_value_from_short (JSContextRef ctx, gshort val, JSValueRef * exception)
1606 {
1607   return JSValueMakeNumber (ctx, (gdouble) val);
1608 }
1609
1610 /**
1611  * seed_value_to_ushort:
1612  * @ctx: A #SeedContext.
1613  * @val: The #SeedValue to convert.
1614  * @exception: A reference to a #SeedValue in which to store any exceptions.
1615  *             Pass %NULL to ignore exceptions.
1616  *
1617  * Converts the given #SeedValue into a #gushort.
1618  *
1619  * Return value: The #gushort represented by @val, or %NULL if an exception
1620  *               is raised during the conversion.
1621  *
1622  */
1623 gushort
1624 seed_value_to_ushort (JSContextRef ctx, JSValueRef val,
1625                       JSValueRef * exception)
1626 {
1627   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1628     {
1629       if (!JSValueIsNull (ctx, val))
1630         seed_make_exception (ctx, exception, "ConversionError",
1631                              "Can not convert Javascript value to" " ushort");
1632       return 0;
1633     }
1634
1635   return (gushort) JSValueToNumber (ctx, val, NULL);
1636 }
1637
1638 /**
1639  * seed_value_from_ushort:
1640  * @ctx: A #SeedContext.
1641  * @val: The #gushort to represent.
1642  * @exception: A reference to a #SeedValue in which to store any exceptions.
1643  *             Pass %NULL to ignore exceptions.
1644  *
1645  * Converts the given #gushort into a #SeedValue.
1646  *
1647  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1648  *               is raised during the conversion.
1649  *
1650  */
1651 JSValueRef
1652 seed_value_from_ushort (JSContextRef ctx, gushort val, JSValueRef * exception)
1653 {
1654   return JSValueMakeNumber (ctx, (gdouble) val);
1655 }
1656
1657 /**
1658  * seed_value_to_long:
1659  * @ctx: A #SeedContext.
1660  * @val: The #SeedValue to convert.
1661  * @exception: A reference to a #SeedValue in which to store any exceptions.
1662  *             Pass %NULL to ignore exceptions.
1663  *
1664  * Converts the given #SeedValue into a #glong.
1665  *
1666  * Return value: The #glong represented by @val, or %NULL if an exception
1667  *               is raised during the conversion.
1668  *
1669  */
1670 glong
1671 seed_value_to_long (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1672 {
1673   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1674     {
1675       if (!JSValueIsNull (ctx, val))
1676         seed_make_exception (ctx, exception, "ConversionError",
1677                              "Can not convert Javascript value to" " long");
1678       return 0;
1679     }
1680
1681   return (glong) JSValueToNumber (ctx, val, NULL);
1682 }
1683
1684  /**
1685  * seed_value_from_long:
1686  * @ctx: A #SeedContext.
1687  * @val: The #glong to represent.
1688  * @exception: A reference to a #SeedValue in which to store any exceptions.
1689  *             Pass %NULL to ignore exceptions.
1690  *
1691  * Converts the given #glong into a #SeedValue.
1692  *
1693  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1694  *               is raised during the conversion.
1695  *
1696  */
1697 JSValueRef
1698 seed_value_from_long (JSContextRef ctx, glong val, JSValueRef * exception)
1699 {
1700   return JSValueMakeNumber (ctx, (gdouble) val);
1701 }
1702
1703 /**
1704  * seed_value_to_ulong:
1705  * @ctx: A #SeedContext.
1706  * @val: The #SeedValue to convert.
1707  * @exception: A reference to a #SeedValue in which to store any exceptions.
1708  *             Pass %NULL to ignore exceptions.
1709  *
1710  * Converts the given #SeedValue into a #gulong.
1711  *
1712  * Return value: The #gulong represented by @val, or %NULL if an exception
1713  *               is raised during the conversion.
1714  *
1715  */
1716 gulong
1717 seed_value_to_ulong (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1718 {
1719   if (!JSValueIsNumber (ctx, val))
1720     {
1721       if (!JSValueIsNull (ctx, val))
1722         seed_make_exception (ctx, exception, "ConversionError",
1723                              "Can not convert Javascript value to" " ulong");
1724
1725       return 0;
1726     }
1727
1728   return (gulong) JSValueToNumber (ctx, val, NULL);
1729 }
1730
1731 /**
1732  * seed_value_from_ulong:
1733  * @ctx: A #SeedContext.
1734  * @val: The #gulong to represent.
1735  * @exception: A reference to a #SeedValue in which to store any exceptions.
1736  *             Pass %NULL to ignore exceptions.
1737  *
1738  * Converts the given #gulong into a #SeedValue.
1739  *
1740  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1741  *               is raised during the conversion.
1742  *
1743  */
1744 JSValueRef
1745 seed_value_from_ulong (JSContextRef ctx, gulong val, JSValueRef * exception)
1746 {
1747   return JSValueMakeNumber (ctx, (gdouble) val);
1748 }
1749
1750 /**
1751  * seed_value_to_int64:
1752  * @ctx: A #SeedContext.
1753  * @val: The #SeedValue to convert.
1754  * @exception: A reference to a #SeedValue in which to store any exceptions.
1755  *             Pass %NULL to ignore exceptions.
1756  *
1757  * Converts the given #SeedValue into a #gint64.
1758  *
1759  * Return value: The #gint64 represented by @val, or %NULL if an exception
1760  *               is raised during the conversion.
1761  *
1762  */
1763 gint64
1764 seed_value_to_int64 (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1765 {
1766   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1767     {
1768       if (!JSValueIsNull (ctx, val))
1769         seed_make_exception (ctx, exception, "ConversionError",
1770                              "Can not convert Javascript value to" " gint64");
1771
1772       return 0;
1773     }
1774
1775   return (gint64) JSValueToNumber (ctx, val, NULL);
1776 }
1777
1778 /**
1779  * seed_value_from_int64:
1780  * @ctx: A #SeedContext.
1781  * @val: The #gint64 to represent.
1782  * @exception: A reference to a #SeedValue in which to store any exceptions.
1783  *             Pass %NULL to ignore exceptions.
1784  *
1785  * Converts the given #gint64 into a #SeedValue.
1786  *
1787  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1788  *               is raised during the conversion.
1789  *
1790  */
1791 JSValueRef
1792 seed_value_from_int64 (JSContextRef ctx, gint64 val, JSValueRef * exception)
1793 {
1794   return JSValueMakeNumber (ctx, (gdouble) val);
1795 }
1796
1797 /**
1798  * seed_value_to_uint64:
1799  * @ctx: A #SeedContext.
1800  * @val: The #SeedValue to convert.
1801  * @exception: A reference to a #SeedValue in which to store any exceptions.
1802  *             Pass %NULL to ignore exceptions.
1803  *
1804  * Converts the given #SeedValue into a #guint64.
1805  *
1806  * Return value: The #guint64 represented by @val, or %NULL if an exception
1807  *               is raised during the conversion.
1808  *
1809  */
1810 guint64
1811 seed_value_to_uint64 (JSContextRef ctx,
1812                       JSValueRef val, JSValueRef * exception)
1813 {
1814   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1815     {
1816       if (!JSValueIsNull (ctx, val))
1817         seed_make_exception (ctx, exception, "ConversionError",
1818                              "Can not convert Javascript value to"
1819                              " guint64");
1820
1821       return 0;
1822     }
1823
1824   return (guint64) JSValueToNumber (ctx, val, NULL);
1825 }
1826
1827 /**
1828  * seed_value_from_uint64:
1829  * @ctx: A #SeedContext.
1830  * @val: The #guint64 to represent.
1831  * @exception: A reference to a #SeedValue in which to store any exceptions.
1832  *             Pass %NULL to ignore exceptions.
1833  *
1834  * Converts the given #guint64 into a #SeedValue.
1835  *
1836  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1837  *               is raised during the conversion.
1838  *
1839  */
1840 JSValueRef
1841 seed_value_from_uint64 (JSContextRef ctx, guint64 val, JSValueRef * exception)
1842 {
1843   return JSValueMakeNumber (ctx, (gdouble) val);
1844 }
1845
1846 /**
1847  * seed_value_to_float:
1848  * @ctx: A #SeedContext.
1849  * @val: The #SeedValue to convert.
1850  * @exception: A reference to a #SeedValue in which to store any exceptions.
1851  *             Pass %NULL to ignore exceptions.
1852  *
1853  * Converts the given #SeedValue into a #gfloat.
1854  *
1855  * Return value: The #gfloat represented by @val, or %NULL if an exception
1856  *               is raised during the conversion.
1857  *
1858  */
1859 gfloat
1860 seed_value_to_float (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1861 {
1862   if (!JSValueIsNumber (ctx, val))
1863     {
1864       if (!JSValueIsNull (ctx, val))
1865         seed_make_exception (ctx, exception, "ConversionError",
1866                              "Can not convert Javascript value to" " gfloat");
1867       return 0;
1868     }
1869
1870   return (gfloat) JSValueToNumber (ctx, val, NULL);
1871 }
1872
1873 /**
1874  * seed_value_from_float:
1875  * @ctx: A #SeedContext.
1876  * @val: The #gfloat to represent.
1877  * @exception: A reference to a #SeedValue in which to store any exceptions.
1878  *             Pass %NULL to ignore exceptions.
1879  *
1880  * Converts the given #gfloat into a #SeedValue.
1881  *
1882  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1883  *               is raised during the conversion.
1884  *
1885  */
1886 JSValueRef
1887 seed_value_from_float (JSContextRef ctx, gfloat val, JSValueRef * exception)
1888 {
1889   return JSValueMakeNumber (ctx, (gdouble) val);
1890 }
1891
1892 /**
1893  * seed_value_to_double:
1894  * @ctx: A #SeedContext.
1895  * @val: The #SeedValue to convert.
1896  * @exception: A reference to a #SeedValue in which to store any exceptions.
1897  *             Pass %NULL to ignore exceptions.
1898  *
1899  * Converts the given #SeedValue into a #gdouble.
1900  *
1901  * Return value: The #gdouble represented by @val, or %NULL if an exception
1902  *               is raised during the conversion.
1903  *
1904  */
1905 gdouble
1906 seed_value_to_double (JSContextRef ctx,
1907                       JSValueRef val, JSValueRef * exception)
1908 {
1909   if (!JSValueIsNumber (ctx, val))
1910     {
1911       if (!JSValueIsNull (ctx, val))
1912         seed_make_exception (ctx, exception, "ConversionError",
1913                              "Can not convert Javascript value to" " double");
1914       return 0;
1915     }
1916
1917   return (gdouble) JSValueToNumber (ctx, val, NULL);
1918 }
1919
1920 /**
1921  * seed_value_from_double:
1922  * @ctx: A #SeedContext.
1923  * @val: The #gdouble to represent.
1924  * @exception: A reference to a #SeedValue in which to store any exceptions.
1925  *             Pass %NULL to ignore exceptions.
1926  *
1927  * Converts the given #gdouble into a #SeedValue.
1928  *
1929  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1930  *               is raised during the conversion.
1931  *
1932  */
1933 JSValueRef
1934 seed_value_from_double (JSContextRef ctx, gdouble val, JSValueRef * exception)
1935 {
1936   return JSValueMakeNumber (ctx, (gdouble) val);
1937 }
1938
1939 /**
1940  * seed_value_to_size:
1941  * @ctx: A #SeedContext.
1942  * @val: The #SeedValue to convert.
1943  * @exception: A reference to a #SeedValue in which to store any exceptions.
1944  *             Pass %NULL to ignore exceptions.
1945  *
1946  * Converts the given #SeedValue into a #gsize.
1947  *
1948  * Return value: The #gsize represented by @val, or %NULL if an exception
1949  *               is raised during the conversion.
1950  *
1951  */
1952 gsize
1953 seed_value_to_size (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
1954 {
1955   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
1956     {
1957       if (!JSValueIsNull (ctx, val))
1958         seed_make_exception (ctx, exception, "ConversionError",
1959                              "Can not convert Javascript value to" " gsize");
1960       return 0;
1961     }
1962
1963   return (gsize) JSValueToNumber (ctx, val, NULL);
1964 }
1965
1966 /**
1967  * seed_value_from_size:
1968  * @ctx: A #SeedContext.
1969  * @val: The #gsize to represent.
1970  * @exception: A reference to a #SeedValue in which to store any exceptions.
1971  *             Pass %NULL to ignore exceptions.
1972  *
1973  * Converts the given #gsize into a #SeedValue.
1974  *
1975  * Return value: A #SeedValue which represents @val, or %NULL if an exception
1976  *               is raised during the conversion.
1977  *
1978  */
1979 JSValueRef
1980 seed_value_from_size (JSContextRef ctx, gsize val, JSValueRef * exception)
1981 {
1982   return JSValueMakeNumber (ctx, (gdouble) val);
1983 }
1984
1985 /**
1986  * seed_value_to_ssize:
1987  * @ctx: A #SeedContext.
1988  * @val: The #SeedValue to convert.
1989  * @exception: A reference to a #SeedValue in which to store any exceptions.
1990  *             Pass %NULL to ignore exceptions.
1991  *
1992  * Converts the given #SeedValue into a #gssize.
1993  *
1994  * Return value: The #gssize represented by @val, or %NULL if an exception
1995  *               is raised during the conversion.
1996  *
1997  */
1998 gssize
1999 seed_value_to_ssize (JSContextRef ctx, JSValueRef val, JSValueRef * exception)
2000 {
2001   if (!JSValueIsNumber (ctx, val) && !JSValueIsBoolean (ctx, val))
2002     {
2003       if (!JSValueIsNull (ctx, val))
2004         seed_make_exception (ctx, exception, "ConversionError",
2005                              "Can not convert Javascript value to" " gssize");
2006       return 0;
2007     }
2008
2009   return (gssize) JSValueToNumber (ctx, val, NULL);
2010 }
2011
2012 /**
2013  * seed_value_from_ssize:
2014  * @ctx: A #SeedContext.
2015  * @val: The #gssize to represent.
2016  * @exception: A reference to a #SeedValue in which to store any exceptions.
2017  *             Pass %NULL to ignore exceptions.
2018  *
2019  * Converts the given #gssize into a #SeedValue.
2020  *
2021  * Return value: A #SeedValue which represents @val, or %NULL if an exception
2022  *               is raised during the conversion.
2023  *
2024  */
2025 JSValueRef
2026 seed_value_from_ssize (JSContextRef ctx, gssize val, JSValueRef * exception)
2027 {
2028   return JSValueMakeNumber (ctx, (gdouble) val);
2029 }
2030
2031 /**
2032  * seed_value_to_string:
2033  * @ctx: A #SeedContext.
2034  * @val: The #SeedValue to convert.
2035  * @exception: A reference to a #SeedValue in which to store any exceptions.
2036  *             Pass %NULL to ignore exceptions.
2037  *
2038  * Converts the given #SeedValue into a #gchar* string. Keep in mind that it's
2039  * up to the caller to free the string.
2040  *
2041  * If the #SeedValue represents JavaScript's undefined value, this returns
2042  * "[undefined]"; if it represents JavaScript's null value, this returns
2043  * "[null]".
2044  *
2045  * If the #SeedValue is a number or a boolean, it is printed as a double, with 
2046  * the printf format string "%.15g".
2047  *
2048  * If the #SeedValue is an object, the string returned is that obtained by
2049  * calling .toString() on said object.
2050  *
2051  * Return value: The #gchar* represented by @val, or %NULL if an exception
2052  *               is raised during the conversion.
2053  *
2054  */
2055 gchar *
2056 seed_value_to_string (JSContextRef ctx,
2057                       JSValueRef val, JSValueRef * exception)
2058 {
2059   JSStringRef jsstr = NULL;
2060   JSValueRef func, str;
2061   gchar *buf = NULL;
2062   gint length;
2063
2064   if (val == NULL)
2065     return NULL;
2066   else if (JSValueIsUndefined (ctx, val))
2067     {
2068       buf = g_strdup ("[undefined]");
2069     }
2070   else if (JSValueIsNull (ctx, val))
2071     {
2072       buf = g_strdup ("[null]");
2073     }
2074   else if (JSValueIsBoolean (ctx, val) || JSValueIsNumber (ctx, val))
2075     {
2076       buf = g_strdup_printf ("%.15g", JSValueToNumber (ctx, val, NULL));
2077     }
2078   else
2079     {
2080       if (!JSValueIsString (ctx, val))  // In this case,
2081         // it's an object
2082         {
2083           func =
2084             seed_object_get_property (ctx, (JSObjectRef) val, "toString");
2085           if (!JSValueIsNull (ctx, func) &&
2086               JSValueIsObject (ctx, func) &&
2087               JSObjectIsFunction (ctx, (JSObjectRef) func))
2088             str =
2089               JSObjectCallAsFunction (ctx, (JSObjectRef) func,
2090                                       (JSObjectRef) val, 0, NULL, NULL);
2091         }
2092       
2093       jsstr = JSValueToStringCopy (ctx, val, NULL);
2094       length = JSStringGetMaximumUTF8CStringSize (jsstr);
2095       if (length > 0)
2096         {
2097           buf = g_malloc (length * sizeof (gchar));
2098           JSStringGetUTF8CString (jsstr, buf, length);
2099         }
2100       if (jsstr)
2101         JSStringRelease (jsstr);
2102     }
2103
2104   return buf;
2105 }
2106
2107 /**
2108  * seed_value_from_string:
2109  * @ctx: A #SeedContext.
2110  * @val: The #gchar* to represent.
2111  * @exception: A reference to a #SeedValue in which to store any exceptions.
2112  *             Pass %NULL to ignore exceptions.
2113  *
2114  * Converts the given #gchar* string into a #SeedValue.
2115  *
2116  * Return value: A #SeedValue which represents @val, or %NULL if an exception
2117  *               is raised during the conversion.
2118  *
2119  */
2120 JSValueRef
2121 seed_value_from_string (JSContextRef ctx,
2122                         const gchar * val, JSValueRef * exception)
2123 {
2124   if (val == NULL)
2125     return JSValueMakeNull (ctx);
2126   else
2127     {
2128       JSStringRef jsstr = JSStringCreateWithUTF8CString (val);
2129       JSValueRef valstr = JSValueMakeString (ctx, jsstr);
2130       JSStringRelease (jsstr);
2131
2132       return valstr;
2133     }
2134 }
2135
2136 /**
2137  * seed_value_from_binary_string:
2138  * @ctx: A #SeedContext.
2139  * @bytes: A string of bytes to represent as a string.
2140  * @n_bytes: The number of bytes from @bytes to convert.
2141  * @exception: A reference to a #SeedValue in which to store any exceptions.
2142  *             Pass %NULL to ignore exceptions.
2143  *
2144  * Converts a string representation of the given binary string
2145  * into a #SeedValue.
2146  *
2147  * Return value: A #SeedValue which represents @bytes as a string, or %NULL
2148  *               if an exception is raised during the conversion.
2149  *
2150  */
2151 JSValueRef
2152 seed_value_from_binary_string (JSContextRef ctx,
2153                                const gchar * bytes,
2154                                gint n_bytes, JSValueRef * exception)
2155 {
2156   JSValueRef ret;
2157
2158   gchar *nstr = g_alloca ((n_bytes + 1) * sizeof (gchar));
2159   g_strlcpy (nstr, bytes, n_bytes);
2160   nstr[n_bytes] = '\0';
2161
2162   ret = seed_value_from_string (ctx, nstr, exception);
2163
2164   return ret;
2165 }
2166
2167 /**
2168  * seed_value_to_filename:
2169  * @ctx: A #SeedContext.
2170  * @val: The #SeedValue to convert.
2171  * @exception: A reference to a #SeedValue in which to store any exceptions.
2172  *             Pass %NULL to ignore exceptions.
2173  *
2174  * Converts the given #SeedValue into a #gchar*, properly converting to the 
2175  * character set used for filenames on the local machine.
2176  *
2177  * Return value: The #gchar* represented by @val, or %NULL if an exception
2178  *               is raised during the conversion.
2179  *
2180  */
2181 gchar *
2182 seed_value_to_filename (JSContextRef ctx,
2183                         JSValueRef val, JSValueRef * exception)
2184 {
2185   GError *e = NULL;
2186   gchar *utf8 = seed_value_to_string (ctx, val, exception);
2187   gchar *filename;
2188
2189   filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, &e);
2190   g_free (utf8);
2191   if (e)
2192     {
2193       seed_make_exception_from_gerror (ctx, exception, e);
2194       g_error_free (e);
2195       return NULL;
2196     }
2197
2198   return filename;
2199 }
2200
2201 /**
2202  * seed_value_from_filename:
2203  * @ctx: A #SeedContext.
2204  * @val: The #gchar* filename to represent.
2205  * @exception: A reference to a #SeedValue in which to store any exceptions.
2206  *             Pass %NULL to ignore exceptions.
2207  *
2208  * Converts the given #gchar* filename into a #SeedValue, respecting the 
2209  * character set used for filenames on the local machine.
2210  *
2211  * Return value: A #SeedValue which represents @val, or %NULL if an exception
2212  *               is raised during the conversion.
2213  *
2214  */
2215 JSValueRef
2216 seed_value_from_filename (JSContextRef ctx,
2217                           const gchar * val, JSValueRef * exception)
2218 {
2219   GError *e = NULL;
2220   gchar *utf8;
2221   
2222   if (val == NULL)
2223     return JSValueMakeNull (ctx);
2224   else
2225     {
2226       utf8 = g_filename_to_utf8 (val, -1, NULL, NULL, &e);
2227
2228       if (e)
2229         {
2230           seed_make_exception_from_gerror (ctx, exception, e);
2231           g_error_free (e);
2232           return JSValueMakeNull (ctx);
2233         }
2234
2235       JSValueRef valstr = seed_value_from_string (ctx, utf8, exception);
2236
2237       g_free (utf8);
2238
2239       return valstr;
2240     }
2241 }
2242
2243 /**
2244  * seed_value_to_object:
2245  * @ctx: A #SeedContext.
2246  * @val: The #SeedValue to unwrap.
2247  * @exception: A reference to a #SeedValue in which to store any exceptions.
2248  *             Pass %NULL to ignore exceptions.
2249  *
2250  * Given a #SeedValue which is wrapping a #GObject, retrieve the wrapped
2251  * #GObject.
2252  *
2253  * Return value: The #GObject wrapped within @val, or %NULL if an exception
2254  *               is raised during the conversion.
2255  *
2256  */
2257 GObject *
2258 seed_value_to_object (JSContextRef ctx,
2259                       JSValueRef val, JSValueRef * exception)
2260 {
2261   GObject *gobject;
2262
2263   /*
2264    * Worth investigating if this is the best way to handle null. Some of
2265    * the existing code depends on null Objects not throwing an exception
2266    * however, needs testing at higher level if value can be null
2267    * (through GI)
2268    */
2269
2270   if (JSValueIsNull (ctx, val))
2271     return NULL;
2272   if (!seed_value_is_gobject (ctx, val))
2273     {
2274       seed_make_exception (ctx, exception, "ConversionError",
2275                            "Attempt to convert from"
2276                            " non GObject to GObject");
2277       return NULL;
2278     }
2279
2280   gobject = (GObject *) JSObjectGetPrivate ((JSObjectRef) val);
2281   g_assert (G_IS_OBJECT (gobject));
2282
2283   return gobject;
2284 }
2285
2286 /**
2287  * seed_value_from_object:
2288  * @ctx: A #SeedContext.
2289  * @val: The #GObject to wrap.
2290  * @exception: A reference to a #SeedValue in which to store any exceptions.
2291  *             Pass %NULL to ignore exceptions.
2292  *
2293  * Wraps @val in a #SeedValue.
2294  *
2295  * Return value: A #SeedValue which wraps @val, or %NULL if an exception
2296  *               is raised during the conversion.
2297  *
2298  */
2299 JSValueRef
2300 seed_value_from_object (JSContextRef ctx,
2301                         GObject * val, JSValueRef * exception)
2302 {
2303   if (val == NULL)
2304     return JSValueMakeNull (ctx);
2305   else
2306     return seed_wrap_object (ctx, val);
2307 }
2308
2309 gboolean
2310 seed_validate_enum (GIEnumInfo * info, long val)
2311 {
2312   gint n, i;
2313   GIValueInfo *value_info;
2314   glong value;
2315
2316   n = g_enum_info_get_n_values (info);
2317   for (i = 0; i < n; i++)
2318     {
2319       value_info = g_enum_info_get_value (info, i);
2320       value = g_value_info_get_value (value_info);
2321
2322       g_base_info_unref ((GIBaseInfo *) value_info);
2323       if (value == val)
2324         return TRUE;
2325     }
2326
2327   return FALSE;
2328 }
2329
2330 JSValueRef
2331 seed_value_from_time_t (JSContextRef ctx, time_t time, JSValueRef * exception)
2332 {
2333   JSValueRef args[1];
2334
2335   args[0] = seed_value_from_double (ctx, ((gdouble) time) * 1000, exception);
2336   return JSObjectMakeDate (ctx, 1, args, exception);
2337 }
2338
2339 time_t
2340 seed_value_to_time_t (JSContextRef ctx,
2341                       JSValueRef value, JSValueRef * exception)
2342 {
2343   JSValueRef get_time_method;
2344   JSValueRef jstime;
2345   gdouble time;
2346
2347
2348   if (JSValueIsNumber (ctx, value))
2349     {
2350       return (unsigned long) seed_value_to_long (ctx, value, exception);
2351     }
2352   else if (JSValueIsObject (ctx, value))
2353     {
2354       get_time_method = seed_object_get_property (ctx, (JSObjectRef) value,
2355                                                   "getTime");
2356       if (JSValueIsNull (ctx, get_time_method) ||
2357           !JSValueIsObject (ctx, get_time_method))
2358         {
2359           goto out;
2360         }
2361       jstime = JSObjectCallAsFunction (ctx,
2362                                        (JSObjectRef) get_time_method,
2363                                        (JSObjectRef) value,
2364                                        0, NULL, exception);
2365       time = seed_value_to_double (ctx, jstime, exception);
2366       return (unsigned long) (time / 1000);
2367     }
2368
2369 out:
2370   seed_make_exception (ctx, exception,
2371                        "TypeError",
2372                        "Unable to convert JavaScript value to time_t");
2373   return 0;
2374 }