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