[jscore] Release property names in signature detection
[browser-dbus-bridge.git] / jscorebus / jscorebus-signature.c
1 /**
2  * Browser D-Bus Bridge, JavaScriptCore version
3  *
4  * Copyright © 2008 Movial Creative Technologies Inc
5  *  Contact: Movial Creative Technologies Inc, <info@movial.com>
6  *  Authors: Kalle Vahlman, <kalle.vahlman@movial.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22
23 #include <glib.h>
24 #include <dbus/dbus.h>
25 #include <JavaScriptCore/JavaScript.h>
26
27 #include "jscorebus-classfactory.h"
28 #include "jscorebus-marshal.h"
29
30 gboolean jsvalue_typeof(JSContextRef context,
31                         JSValueRef jsvalue,
32                         const char *type)
33 {
34   const JSClassDefinition *jsclassdef;
35   JSClassRef jsclass;
36   
37   jsclassdef = jsclassdef_lookup(type);
38   if (G_UNLIKELY(jsclassdef == NULL))
39     return FALSE;
40   jsclass = jsclass_lookup(jsclassdef);
41
42   return JSValueIsObjectOfClass(context, jsvalue, jsclass);
43 }
44
45 gboolean jsvalue_instanceof(JSContextRef context,
46                             JSValueRef jsvalue,
47                             const char *constructor)
48 {
49   JSStringRef property;
50   JSObjectRef ctor;
51
52   property = JSStringCreateWithUTF8CString(constructor);
53   ctor = JSValueToObject(context,
54                          JSObjectGetProperty(context,
55                                              JSContextGetGlobalObject(context),
56                                              property,
57                                              NULL),
58                          NULL);
59   JSStringRelease(property);
60
61   return JSValueIsInstanceOfConstructor(context, jsvalue, ctor, NULL);
62 }
63
64 char *jsvalue_to_signature(JSContextRef context,
65                            JSValueRef jsvalue)
66 {
67   char *signature = NULL;
68   
69   switch (JSValueGetType(context, jsvalue))
70   {
71     case kJSTypeBoolean:
72       {
73         signature = g_strdup(DBUS_TYPE_BOOLEAN_AS_STRING);
74         break;
75       }
76     case kJSTypeNumber:
77       {
78         /* JavaScript numbers are always doubles */
79         signature = g_strdup(DBUS_TYPE_DOUBLE_AS_STRING);
80         break;
81       }
82     case kJSTypeString:
83       {
84         signature = g_strdup(DBUS_TYPE_STRING_AS_STRING);
85         break;
86       }
87     case kJSTypeObject:
88       {
89         int i;
90         char *dict_signature = NULL;
91         JSPropertyNameArrayRef propnames;
92
93         /* Check for number types */
94         for (i = 0; i < JSCOREBUS_N_NUMBER_CLASSES; i++)
95         {
96           if (jsvalue_typeof(context, jsvalue, jscorebus_number_class_names[i]))
97           {
98             switch (jscorebus_number_class_types[i])
99             {
100 #define NUMBER_SIGNATURE(t) \
101               case DBUS_TYPE_## t: \
102                 signature = g_strdup(DBUS_TYPE_## t ##_AS_STRING); \
103                 break;
104               NUMBER_SIGNATURE(UINT32)
105               NUMBER_SIGNATURE(INT32)
106               NUMBER_SIGNATURE(BYTE)
107               NUMBER_SIGNATURE(UINT64)
108               NUMBER_SIGNATURE(INT64)
109               NUMBER_SIGNATURE(UINT16)
110               NUMBER_SIGNATURE(INT16)
111
112               default:
113                 break;
114             }
115           }
116         }
117
118         /* Check for arrays */
119         if (jsvalue_instanceof(context, jsvalue, "Array"))
120         {
121           char *array_signature;
122
123           propnames = JSObjectCopyPropertyNames(context, (JSObjectRef)jsvalue);
124           if (!jsarray_get_signature(context, jsvalue, propnames, &array_signature))
125           { 
126             g_warning("Could not create array signature");
127             JSPropertyNameArrayRelease(propnames);
128             break;
129           }
130           signature = g_strdup_printf("a%s", array_signature);
131           g_free(array_signature);
132           JSPropertyNameArrayRelease(propnames);
133           break;
134         }
135
136         /* Check variants */
137         if (jsvalue_typeof(context, jsvalue, "DBusVariant"))
138         {
139           signature = g_strdup("v");
140           break;
141         }
142
143         if (jsvalue_typeof(context, jsvalue, "DBusObjectPath"))
144         {
145           signature = g_strdup(DBUS_TYPE_OBJECT_PATH_AS_STRING);
146           break;
147         }
148
149         if (jsvalue_typeof(context, jsvalue, "DBusSignature"))
150         {
151           signature = g_strdup(DBUS_TYPE_SIGNATURE_AS_STRING);
152           break;
153         }
154
155         /* Check structs */
156         if (jsvalue_typeof(context, jsvalue, "DBusStruct"))
157         {
158           JSObjectRef value = (JSObjectRef)JSObjectGetPrivate((JSObjectRef)jsvalue);
159           propnames = JSObjectCopyPropertyNames(context, value);
160           jsstruct_get_signature(context, value, propnames, &signature);
161           JSPropertyNameArrayRelease(propnames);
162           break;
163         }
164
165         /* Default conversion is to dict */
166         propnames = JSObjectCopyPropertyNames(context, (JSObjectRef)jsvalue);
167         jsdict_get_signature(context, jsvalue, propnames, &dict_signature);
168         if (dict_signature != NULL)
169         {
170           signature = g_strdup_printf("a%s", dict_signature);
171           g_free(dict_signature);
172         }
173         JSPropertyNameArrayRelease(propnames);
174         break;
175       }
176     case kJSTypeUndefined:
177     case kJSTypeNull:
178     default:
179       g_warning("Signature lookup failed for unsupported type %i", JSValueGetType(context, jsvalue));
180       break;
181   }
182   return signature;
183 }
184
185 gboolean
186 jsarray_get_signature(JSContextRef context,
187                       JSValueRef jsvalue,
188                       JSPropertyNameArrayRef propNames,
189                       char **signature)
190 {
191   int i, props;
192   
193   *signature = NULL;
194   props = JSPropertyNameArrayGetCount(propNames);
195   /* Arrays are restricted to single complete types so we only need to look
196    * at the first property
197    */
198   if (props > 0)
199   {
200     *signature = jsvalue_to_signature(context,
201       JSObjectGetPropertyAtIndex(context, (JSObjectRef)jsvalue, 0, NULL));
202   }
203   return *signature == NULL ? FALSE : TRUE;
204 }
205
206 gboolean
207 jsdict_get_signature(JSContextRef context,
208                      JSValueRef jsvalue,
209                      JSPropertyNameArrayRef propNames,
210                      char **signature)
211 {
212   int i, props;
213   
214   *signature = NULL;
215   props = JSPropertyNameArrayGetCount(propNames);
216   /* Dicts support only string keys currently, though numbers would be another
217    * possibility...
218    */
219   if (props > 0)
220   {
221     char **signatures = g_new0(char*, 5);
222     
223     signatures[0] = g_strdup(DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING);
224     signatures[1] = g_strdup(DBUS_TYPE_STRING_AS_STRING);
225     signatures[2] = jsvalue_to_signature(context,
226       JSObjectGetProperty(context, (JSObjectRef)jsvalue,
227         JSPropertyNameArrayGetNameAtIndex(propNames, 0), NULL));
228     signatures[3] = g_strdup(DBUS_DICT_ENTRY_END_CHAR_AS_STRING);
229
230     *signature = g_strjoinv(NULL, signatures);
231     g_strfreev(signatures);
232   }
233   return *signature == NULL ? FALSE : TRUE;
234 }
235
236 gboolean
237 jsstruct_get_signature(JSContextRef context,
238                        JSValueRef jsvalue,
239                        JSPropertyNameArrayRef propNames,
240                        char **signature)
241 {
242   int props;
243   
244   *signature = NULL;
245   props = JSPropertyNameArrayGetCount(propNames);
246   if (props > 0)
247   {
248     char **signatures = g_new0(char*, props + 2);
249     int i = 0;
250     signatures[i] = g_strdup(DBUS_STRUCT_BEGIN_CHAR_AS_STRING);
251     while (i < props)
252     {
253       signatures[i+1] = jsvalue_to_signature(context,
254         JSObjectGetProperty(context, (JSObjectRef)jsvalue,
255           JSPropertyNameArrayGetNameAtIndex(propNames, i++), NULL));
256     }
257     signatures[props + 1] = g_strdup(DBUS_STRUCT_END_CHAR_AS_STRING);
258
259     *signature = g_strjoinv(NULL, signatures);
260     g_strfreev(signatures);
261   }
262   return *signature == NULL ? FALSE : TRUE;
263 }
264