Rubber stamped by Maciej.
[WebKit-https.git] / JavaScriptGlue / JavaScriptGlue.cpp
1 /*
2     JSGlue.cpp
3 */
4
5 #include "JavaScriptGlue.h"
6 #include "JSUtils.h"
7 #include "JSBase.h"
8 #include "JSObject.h"
9 #include "JSRun.h"
10
11 static CFTypeRef sJSCFNullRef = 0;
12
13 static void CFJSObjectDispose(void *data);
14 static JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName);
15 static void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue);
16 static CFTypeRef CFJSObjectCopyCFValue(void *data);
17 static UInt8 CFJSObjectEqual(void *data1, void *data2);
18 static CFArrayRef CFJSObjectCopyPropertyNames(void *data);
19
20 void *JSCFRetain(CFAllocatorRef allocator, const void *value);
21 void JSCFRelease(CFAllocatorRef allocator, const void *value);
22
23
24 void JSSetCFNull(CFTypeRef nullRef)
25 {
26     ReleaseCFType(sJSCFNullRef);
27     sJSCFNullRef = RetainCFType(nullRef);
28 }
29
30 CFTypeRef JSGetCFNull(void)
31 {
32     return sJSCFNullRef;
33 }
34
35 /*
36     JSRetain
37 */
38 JSTypeRef JSRetain(JSTypeRef ref)
39 {
40     if (ref)
41     {
42         JSBase* ptr = (JSBase*)ref;
43         ptr->Retain();
44     }
45     return ref;
46 }
47
48 /*
49     JSRelease
50 */
51 void JSRelease(JSTypeRef ref)
52 {
53     if (ref)
54     {
55         JSBase* ptr = (JSBase*)ref;
56         ptr->Release();
57     }
58 }
59
60 /*
61     JSCopyDescription
62 */
63 CFStringRef JSCopyDescription(JSTypeRef ref)
64 {
65     CFStringRef result = 0;
66     if (ref)
67     {
68         JSBase* ptr = (JSBase*)ref;
69         ptr->CopyDescription();
70     }
71     return result;
72 }
73
74 /*
75     JSEqual
76 */
77 UInt8 JSEqual(JSTypeRef ref1, JSTypeRef ref2)
78 {
79     UInt8 result = false;
80     if (ref1 && ref2)
81     {
82         JSBase* ptr = (JSBase*)ref1;
83         result = ptr->Equal((JSBase*)ref2);
84     }
85     return result;
86 }
87
88
89 /*
90     JSGetTypeID
91 */
92 JSTypeID JSGetTypeID(JSTypeRef ref)
93 {
94     JSTypeID result = kJSInvalidTypeID;
95     if (ref)
96     {
97         JSBase* ptr = (JSBase*)ref;
98         result = ptr->GetTypeID();
99     }
100     return result;
101 }
102
103
104 /*
105     JSGetRetainCount
106 */
107 CFIndex JSGetRetainCount(JSTypeRef ref)
108 {
109     CFIndex result = -1;
110     if (ref)
111     {
112         JSBase* ptr = (JSBase*)ref;
113         result = ptr->RetainCount();
114     }
115     return result;
116 }
117
118
119
120 /*
121     JSObjectCreate
122 */
123 JSObjectRef JSObjectCreate(void *data, JSObjectCallBacksPtr callBacks)
124 {
125     JSObjectRef result = JSObjectCreateInternal(data, callBacks, 0, kJSUserObjectDataTypeUnknown);
126     return result;
127 }
128
129 /*
130     JSObjectCreateInternal
131 */
132 JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int type)
133 {
134     JSObjectRef result = 0;
135     JSUserObject* ptr = new JSUserObject(callBacks, markProc, data, type);
136     result = (JSObjectRef)ptr;
137     return result;
138 }
139
140 /*
141     JSObjectCopyCFValue
142 */
143 CFTypeRef JSObjectCopyCFValue(JSObjectRef ref)
144 {
145     CFTypeRef result = 0;
146     JSUserObject* ptr = (JSUserObject*)ref;
147     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
148     {
149         result = ptr->CopyCFValue();
150     }
151     return result;
152 }
153
154 /*
155     JSObjectGetData
156 */
157 void *JSObjectGetData(JSObjectRef ref)
158 {
159     void *result = 0;
160     JSUserObject* ptr = (JSUserObject*)ref;
161     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
162     {
163         result = ptr->GetData();
164     }
165     return result;
166 }
167
168
169 /*
170     JSObjectCopyProperty
171 */
172 JSObjectRef JSObjectCopyProperty(JSObjectRef ref, CFStringRef propertyName)
173 {
174     JSObjectRef result = 0;
175     JSUserObject* ptr = (JSUserObject*)ref;
176     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
177     {
178         result = (JSObjectRef)ptr->CopyProperty(propertyName);
179     }
180     return result;
181 }
182
183
184 /*
185     JSObjectSetProperty
186 */
187 void JSObjectSetProperty(JSObjectRef ref, CFStringRef propertyName, JSObjectRef value)
188 {
189     JSUserObject* ptr = (JSUserObject*)ref;
190     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
191     {
192         ptr->SetProperty(propertyName, (JSUserObject*)value);
193     }
194 }
195
196
197 /*
198     JSObjectCallFunction
199 */
200 JSObjectRef JSObjectCallFunction(JSObjectRef ref, JSObjectRef thisObj, CFArrayRef args)
201 {
202     JSObjectRef result = 0;
203     JSUserObject* ptr = (JSUserObject*)ref;
204     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
205     {
206         result = (JSObjectRef)ptr->CallFunction((JSUserObject*)thisObj, args);
207     }
208     return result;
209 }
210
211
212 /*
213     JSRunCreate
214 */
215 JSRunRef JSRunCreate(CFStringRef jsSource, JSFlags inFlags)
216 {
217     JSRunRef result = 0;
218     if (jsSource)
219     {
220         JSLock lock;
221         result = (JSRunRef) new JSRun(jsSource, inFlags);
222     }
223     return result;
224 }
225
226 /*
227     JSRunCopySource
228 */
229 CFStringRef JSRunCopySource(JSRunRef ref)
230 {
231     CFStringRef result = 0;
232     JSRun* ptr = (JSRun*)ref;
233     if (ptr)
234     {
235         result = UStringToCFString(ptr->GetSource());
236     }
237     return result;
238 }
239
240
241 /*
242     JSRunCopyGlobalObject
243 */
244 JSObjectRef JSRunCopyGlobalObject(JSRunRef ref)
245 {
246     JSObjectRef result = 0;
247     JSRun* ptr = (JSRun*)ref;
248     if (ptr)
249     {
250         JSObject *globalObject = ptr->GlobalObject();
251         result = (JSObjectRef)KJSValueToJSObject(globalObject, ptr->GetInterpreter()->globalExec());
252     }
253     return result;
254 }
255
256 /*
257     JSRunEvaluate
258 */
259 JSObjectRef JSRunEvaluate(JSRunRef ref)
260 {
261     JSObjectRef result = 0;
262     JSRun* ptr = (JSRun*)ref;
263     if (ptr)
264     {
265         Completion completion = ptr->Evaluate();
266         if (completion.isValueCompletion())
267         {
268             result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GetInterpreter()->globalExec());
269         }
270
271         if (completion.complType() == Throw)
272         {
273             JSFlags flags = ptr->Flags();
274             if (flags & kJSFlagDebug)
275             {
276                 CFTypeRef error = JSObjectCopyCFValue(result);
277                 if (error)
278                 {
279                     CFShow(error);
280                     CFRelease(error);
281                 }
282             }
283         }
284     }
285     return result;
286 }
287
288 /*
289     JSRunCheckSyntax
290     Return true if no syntax error
291 */
292 bool JSRunCheckSyntax(JSRunRef ref)
293 {
294     bool result = false;
295     JSRun* ptr = (JSRun*)ref;
296     if (ptr)
297     {
298             JSLockInterpreter();
299             result = ptr->CheckSyntax();
300             JSUnlockInterpreter();
301     }
302     return result;
303 }
304
305 /*
306     JSCollect - trigger garbage collection
307 */
308 void JSCollect(void)
309 {
310     JSLock lock;
311     Collector::collect();
312 }
313
314 /*
315     JSTypeGetCFArrayCallBacks
316 */
317 void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks)
318 {
319     if (outCallBacks)
320     {
321         outCallBacks->version = 1;
322         outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain;
323         outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease;
324         outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription;
325         outCallBacks->equal = (CFArrayEqualCallBack)JSEqual;
326     }
327 }
328
329
330 /*
331     JSCFRetain
332 */
333 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
334 {
335     JSRetain((JSTypeRef)value);
336     return (void*)value;
337 }
338
339 /*
340     JSCFRelease
341 */
342 void JSCFRelease(CFAllocatorRef allocator, const void *value)
343 {
344     JSRelease((JSTypeRef)value);
345 }
346
347
348 /*
349     JSObjectCreateWithCFType
350 */
351 JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef)
352 {
353     JSObjectCallBacks callBacks;
354     JSObjectRef cfJSObject = nil;
355     if (inRef)
356     {
357         callBacks.dispose = CFJSObjectDispose;
358         callBacks.equal = CFJSObjectEqual;
359         callBacks.copyCFValue = CFJSObjectCopyCFValue;
360         callBacks.copyProperty = CFJSObjectCopyProperty;
361         callBacks.setProperty = CFJSObjectSetProperty;
362         callBacks.callFunction = 0;
363         callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames;
364         cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, 0, kJSUserObjectDataTypeCFType );
365     }
366     return cfJSObject;
367 }
368
369 /*
370     CFJSObjectDispose
371 */
372 void CFJSObjectDispose(void *data)
373 {
374     if (data)
375     {
376         CFRelease((JSTypeRef)data);
377     }
378 }
379
380 CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref)
381 {
382     CFArrayRef result = 0;
383     JSUserObject* ptr = (JSUserObject*)ref;
384     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
385     {
386         result = ptr->CopyPropertyNames();
387     }
388     return result;
389 }
390 /*
391     CFJSObjectCopyProperty
392 */
393 JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName)
394 {
395     JSObjectRef result = 0;
396     if (data && propertyName)
397     {
398         CFTypeRef cfResult = 0;
399         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
400         {
401             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
402             {
403                 int len = CFDictionaryGetCount((CFDictionaryRef)data);
404                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
405             }
406             else
407             {
408                 cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName));
409             }
410         }
411         else if (CFGetTypeID(data) == CFArrayGetTypeID())
412         {
413             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
414             {
415                 int len = CFArrayGetCount((CFArrayRef)data);
416                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
417             }
418             else
419             {
420                 SInt32 index = CFStringGetIntValue(propertyName);
421                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
422                 if (index >= 0 && index < arrayCount)
423                 {
424                     cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index));
425                 }
426             }
427         }
428         else if (CFGetTypeID(data) == CFStringGetTypeID())
429         {
430             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
431             {
432                 int len = CFStringGetLength((CFStringRef)data);
433                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
434             }
435         }
436         if (cfResult)
437         {
438             result = JSObjectCreateWithCFType(cfResult);
439             CFRelease(cfResult);
440         }
441     }
442     return result;
443 }
444
445
446 /*
447     CFJSObjectSetProperty
448 */
449 void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue)
450 {
451     if (data && propertyName)
452     {
453         CFTypeRef cfValue = JSObjectCopyCFValue(jsValue);
454
455         if (cfValue)
456         {
457             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
458             {
459                 CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue);
460             }
461             else if (CFGetTypeID(data) == CFArrayGetTypeID())
462             {
463                 SInt32 index = CFStringGetIntValue(propertyName);
464                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
465                 if (index >= 0)
466                 {
467                     for (; arrayCount < index; arrayCount++)
468                     {
469                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
470                     }
471                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue);
472                 }
473             }
474             CFRelease(cfValue);
475         }
476         else
477         {
478             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
479             {
480                 CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName);
481             }
482             else if (CFGetTypeID(data) == CFArrayGetTypeID())
483             {
484                 SInt32 index = CFStringGetIntValue(propertyName);
485                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
486                 if (index >= 0)
487                 {
488                     for (; arrayCount < index; arrayCount++)
489                     {
490                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
491                     }
492                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull());
493                 }
494             }
495         }
496     }
497 }
498
499
500 /*
501     CFJSObjectCopyCFValue
502 */
503 CFTypeRef CFJSObjectCopyCFValue(void *data)
504 {
505     CFTypeRef result = 0;
506     if (data)
507     {
508         result = (CFTypeRef)CFRetain(data);
509     }
510     return result;
511 }
512
513 /*
514     CFJSObjectCopyCFValue
515 */
516 UInt8 CFJSObjectEqual(void *data1, void *data2)
517 {
518     UInt8 result = false;
519     if (data1 && data2)
520     {
521         CFEqual((CFTypeRef)data1, (CFTypeRef)data2);
522     }
523     return result;
524 }
525
526
527 /*
528     CFJSObjectCopyPropertyNames
529 */
530 CFArrayRef CFJSObjectCopyPropertyNames(void *data)
531 {
532     CFMutableArrayRef result = 0;
533     if (data)
534     {
535         CFTypeID cfType = CFGetTypeID(data);
536         if (cfType == CFDictionaryGetTypeID())
537         {
538             CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data);
539             if (count)
540             {
541                 CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count);
542                 if (keys)
543                 {
544                     int i;
545                     CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, 0);
546                     for (i = 0; i < count; i++)
547                     {
548                         CFStringRef key = (CFStringRef)keys[i];
549                         if (CFGetTypeID(key) != CFStringGetTypeID()) continue;
550
551                         if (!result) result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
552                         if (!result) continue;
553
554                         CFArrayAppendValue(result, key);
555                     }
556                     free(keys);
557                 }
558             }
559         }
560     }
561     return result;
562 }
563
564
565
566
567 CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array)
568 {
569     CFIndex count = array ? CFArrayGetCount(array) : 0;
570     CFMutableArrayRef cfArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
571     CFIndex i;
572
573     for (i = 0; cfArray && i <  count; i++)
574     {
575         JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i);
576         CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue);
577         if (cfvalue)
578         {
579             CFArrayAppendValue(cfArray, cfvalue);
580             CFRelease(cfvalue);
581         }
582         else
583         {
584             CFArrayAppendValue(cfArray, GetCFNull());
585         }
586     }
587     return cfArray;
588 }
589
590 CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array)
591 {
592     CFIndex count = array ? CFArrayGetCount(array) : 0;
593     CFArrayCallBacks arrayCallbacks;
594     CFMutableArrayRef jsArray;
595     CFIndex i;
596
597     JSTypeGetCFArrayCallBacks(&arrayCallbacks);
598     jsArray = CFArrayCreateMutable(0, 0, &arrayCallbacks);
599
600     for (i = 0; array && i <  count; i++)
601     {
602         CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i);
603         JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue);
604
605         if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull());
606         if (jsValue)
607         {
608             CFArrayAppendValue(jsArray, jsValue);
609             JSRelease(jsValue);
610         }
611     }
612     return jsArray;
613 }
614
615
616 void JSLockInterpreter()
617 {
618     JSLock::lock();
619 }
620
621
622 void JSUnlockInterpreter()
623 {
624     JSLock::unlock();
625 }