top level:
[WebKit-https.git] / JavaScriptGlue / JSUtils.cpp
1 //
2 // JSUtils.cpp
3 //
4
5 #include "JSUtils.h"
6 #include "JSBase.h"
7 #include "JSObject.h"
8 #include "JSRun.h"
9 #include "UserObjectImp.h"
10 #include "JSValueWrapper.h"
11 #include "JSObject.h"
12 #include "JavaScriptCore/IdentifierSequencedSet.h"
13
14 struct ObjectImpList {
15         ObjectImp* imp;
16         ObjectImpList* next;
17         CFTypeRef data;
18 };
19
20 static CFTypeRef KJSValueToCFTypeInternal(ValueImp *inValue, ExecState *exec, ObjectImpList* inImps);
21
22
23 //--------------------------------------------------------------------------
24 //      CFStringToUString
25 //--------------------------------------------------------------------------
26
27 UString CFStringToUString(CFStringRef inCFString)
28 {
29     InterpreterLock lock;
30
31     UString result;
32     if (inCFString) {
33         CFIndex len = CFStringGetLength(inCFString);
34         UniChar* buffer = (UniChar*)malloc(sizeof(UniChar) * len);
35         if (buffer)
36         {
37             CFStringGetCharacters(inCFString, CFRangeMake(0, len), buffer);
38             result = UString((const UChar *)buffer, len);
39             free(buffer);
40         }
41     }
42     return result;
43 }
44
45
46 //--------------------------------------------------------------------------
47 //      UStringToCFString
48 //--------------------------------------------------------------------------
49 // Caller is responsible for releasing the returned CFStringRef
50 CFStringRef UStringToCFString(const UString& inUString)
51 {
52         return CFStringCreateWithCharacters(NULL, (const UniChar*)inUString.data(), inUString.size());
53 }
54
55
56 #if JAG_PINK_OR_LATER
57 //--------------------------------------------------------------------------
58 //      CFStringToIdentifier
59 //--------------------------------------------------------------------------
60
61 Identifier CFStringToIdentifier(CFStringRef inCFString)
62 {
63         return Identifier(CFStringToUString(inCFString));
64 }
65
66
67 //--------------------------------------------------------------------------
68 //      IdentifierToCFString
69 //--------------------------------------------------------------------------
70 // Caller is responsible for releasing the returned CFStringRef
71 CFStringRef IdentifierToCFString(const Identifier& inIdentifier)
72 {
73         return UStringToCFString(inIdentifier.ustring());
74 }
75 #endif
76
77
78 //--------------------------------------------------------------------------
79 //      KJSValueToJSObject
80 //--------------------------------------------------------------------------
81 JSUserObject* KJSValueToJSObject(ValueImp *inValue, ExecState *exec)
82 {
83     JSUserObject* result = NULL;
84     
85     if (inValue->isObject(&UserObjectImp::info)) {
86         UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
87         result = userObjectImp->GetJSUserObject();
88         if (result) 
89             result->Retain();
90     } else {
91         JSValueWrapper* wrapperValue = new JSValueWrapper(inValue, exec);
92         if (wrapperValue) {
93             JSObjectCallBacks callBacks;
94             JSValueWrapper::GetJSObectCallBacks(callBacks);
95             result = (JSUserObject*)JSObjectCreate(wrapperValue, &callBacks);
96             if (!result) {
97                 delete wrapperValue;
98             }
99         }
100     }
101     return result;
102 }
103
104 //--------------------------------------------------------------------------
105 //      JSObjectKJSValue
106 //--------------------------------------------------------------------------
107 ValueImp *JSObjectKJSValue(JSUserObject* ptr)
108 {
109     InterpreterLock lock;
110
111     ValueImp *result = Undefined();
112     if (ptr)
113     {
114         bool handled = false;
115         
116         switch (ptr->DataType())
117         {
118             case kJSUserObjectDataTypeJSValueWrapper:
119             {
120                 JSValueWrapper* wrapper = (JSValueWrapper*)ptr->GetData();
121                 if (wrapper)
122                 {
123                     result = wrapper->GetValue();
124                     handled = true;
125                 }
126                 break;
127             }
128                 
129             case kJSUserObjectDataTypeCFType:
130             {
131                 CFTypeRef cfType = (CFTypeRef*)ptr->GetData();
132                 if (cfType)
133                 {
134                     CFTypeID typeID = CFGetTypeID(cfType);
135                     if (typeID == CFStringGetTypeID())
136                     {
137                         result = String(CFStringToUString((CFStringRef)cfType));
138                         handled = true;
139                     }
140                     else if (typeID == CFNumberGetTypeID())
141                     {
142                         if (CFNumberIsFloatType((CFNumberRef)cfType))
143                         {
144                             double num;
145                             if (CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num))
146                             {
147                                 result = Number(num);
148                                 handled = true;
149                             }
150                         }
151                         else
152                         {
153                             long num;
154                             if (CFNumberGetValue((CFNumberRef)cfType, kCFNumberLongType, &num))
155                             {
156                                 result = Number(num);
157                                 handled = true;
158                             }
159                         }
160                     }
161                     else if (typeID == CFBooleanGetTypeID())
162                     {
163                         result = KJS::Boolean(CFBooleanGetValue((CFBooleanRef)cfType));
164                         handled = true;
165                     }
166                     else if (typeID == CFDateGetTypeID())
167                     {
168                     }
169                     else if (typeID == CFNullGetTypeID())
170                     {
171                         result = Null();
172                         handled = true;
173                     }
174                 }
175                 break;
176             }
177         }
178         if (!handled)
179         {
180             result = new UserObjectImp(ptr);
181         }
182     }
183     return result;
184 }
185
186
187
188
189 //--------------------------------------------------------------------------
190 //      KJSValueToCFTypeInternal
191 //--------------------------------------------------------------------------
192 // Caller is responsible for releasing the returned CFTypeRef
193 CFTypeRef KJSValueToCFTypeInternal(ValueImp *inValue, ExecState *exec, ObjectImpList* inImps)
194 {
195         if (inValue)
196                 return NULL;
197                 
198         CFTypeRef result = NULL;
199         
200         InterpreterLock lock;
201
202         switch (inValue->type())
203         {
204                 case BooleanType:
205                         {
206                                 result = inValue->toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse;
207                                 RetainCFType(result);
208                         }
209                         break;
210                         
211                 case StringType:
212                         {
213                                 UString uString = inValue->toString(exec);
214                                 result = UStringToCFString(uString);
215                         }
216                         break;
217                         
218                 case NumberType:
219                         {
220                                 double number1 = inValue->toNumber(exec);
221                                 double number2 = (double)inValue->toInteger(exec);
222                                 if (number1 ==  number2)
223                                 {
224                                         int intValue = (int)number2;
225                                         result = CFNumberCreate(NULL, kCFNumberIntType, &intValue);
226                                 }
227                                 else
228                                 {
229                                         result = CFNumberCreate(NULL, kCFNumberDoubleType, &number1);
230                                 }
231                         }
232                         break;
233                         
234                 case ObjectType:
235                         {
236                             if (inValue->isObject(&UserObjectImp::info)) {
237                                 UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
238                                         JSUserObject* ptr = userObjectImp->GetJSUserObject();
239                                         if (ptr)
240                                         {
241                                                 result = ptr->CopyCFValue();
242                                         }
243                                 }
244                                 else
245                                 {
246                                         ObjectImp *object = inValue->toObject(exec);
247                                         UInt8 isArray = false;
248
249                                         // if two objects reference each
250                                         ObjectImp* imp = object;
251                                         ObjectImpList* temp = inImps;
252                                         while (temp) {
253                                                 if (imp == temp->imp) {
254                                                         return CFRetain(GetCFNull());
255                                                 }
256                                                 temp = temp->next;
257                                         }
258
259                                         ObjectImpList imps;
260                                         imps.next = inImps;
261                                         imps.imp = imp;
262
263                                         
264 //[...] HACK since we do not have access to the class info we use class name instead
265 #if 0
266                                         if (object->inherits(&ArrayInstanceImp::info))
267 #else
268                                         if (object->className() == "Array")
269 #endif
270                                         {
271                                                 isArray = true;                                 
272 #if JAG_PINK_OR_LATER
273                                                 JSInterpreter* intrepreter = (JSInterpreter*)exec->dynamicInterpreter();
274                                                 if (intrepreter && (intrepreter->Flags() & kJSFlagConvertAssociativeArray)) {
275                                                         IdentifierSequencedSet propList;
276                                                         object->getPropertyNames(exec, propList);
277                                                         IdentifierSequencedSetIterator iter = propList.begin();
278                                                         IdentifierSequencedSetIterator end = propList.end();
279                                                         while(iter != end && isArray)
280                                                         {
281                                                                 Identifier propName = *iter;
282                                                                 UString ustr = propName.ustring();
283                                                                 const UniChar* uniChars = (const UniChar*)ustr.data();
284                                                                 int size = ustr.size();
285                                                                 while (size--) {
286                                                                         if (uniChars[size] < '0' || uniChars[size] > '9') {
287                                                                                 isArray = false;
288                                                                                 break;
289                                                                         }
290                                                                 }
291                                                                 ++iter;
292                                                         }
293                                                 }
294 #endif
295                                         }
296                                         
297                                         if (isArray)
298                                         {                               
299                                                 // This is an KJS array
300                                                 unsigned int length = object->get(exec, "length")->toUInt32(exec);
301                                                 result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
302                                                 if (result)
303                                                 {
304 #if JAG_PINK_OR_LATER
305                                                         for (unsigned i = 0; i < length; i++)
306                                                         {
307                                                                 CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, i), exec, &imps);
308                                                                 CFArrayAppendValue((CFMutableArrayRef)result, cfValue);
309                                                                 ReleaseCFType(cfValue);
310                                                         }
311 #else
312                                                         for (unsigned int i = 0; i < length; i++)
313                                                         {
314                                                                 UString propertyName = UString::from(i);
315                                                                 CFTypeRef cfValue = KJSValueToCFTypeInternal(object.get(exec, propertyName), exec, &imps);
316                                                                 CFArrayAppendValue((CFMutableArrayRef)result, cfValue);
317                                                                 ReleaseCFType(cfValue);
318                                                         }
319 #endif
320                                                 }
321                                         }
322                                         else
323                                         {
324 #if JAG_PINK_OR_LATER
325                                                 // Not an arry, just treat it like a dictionary which contains (property name, property value) paiars
326                                                 IdentifierSequencedSet propList;
327                                                 object->getPropertyNames(exec, propList);
328                                                 {
329                                                         result = CFDictionaryCreateMutable(NULL, 
330                                                                                                                            0, 
331                                                                                                                            &kCFTypeDictionaryKeyCallBacks, 
332                                                                                                                            &kCFTypeDictionaryValueCallBacks);
333                                                         if (result)
334                                                         {
335                                                                 IdentifierSequencedSetIterator iter = propList.begin();
336                                                                 IdentifierSequencedSetIterator end = propList.end();
337                                                                 while(iter != end)
338                                                                 {
339                                                                         Identifier propName = *iter;
340                                                                         if (object->hasProperty(exec, propName))
341                                                                         {
342                                                                                 CFStringRef cfKey = IdentifierToCFString(propName);
343                                                                                 CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, propName), exec, &imps);
344                                                                                 if (cfKey && cfValue)
345                                                                                 {
346                                                                                         CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue);
347                                                                                 }
348                                                                                 ReleaseCFType(cfKey);
349                                                                                 ReleaseCFType(cfValue);
350                                                                         }
351                                                                         ++iter;
352                                                                 }
353                                                         }
354                                                 }
355 #else
356                                                 List propList = object.propList(exec);
357                                                 if (propList.size() > 0)
358                                                 {
359                                                         result = CFDictionaryCreateMutable(NULL, 
360                                                                                                                            0, 
361                                                                                                                            &kCFTypeDictionaryKeyCallBacks, 
362                                                                                                                            &kCFTypeDictionaryValueCallBacks);
363                                                         if (result)
364                                                         {
365                                                                 ListIterator iter = propList.begin();
366                                                                 ListIterator end = propList.end();
367                                                                 while(iter != end)
368                                                                 {
369                                                                         UString propName = iter->getPropertyName(exec);
370                                                                         if (object.hasProperty(exec, propName))
371                                                                         {
372                                                                                 CFStringRef cfKey = UStringToCFString(propName);
373                                                                                 CFTypeRef cfValue = KJSValueToCFTypeInternal(iter->getValue(exec), exec, &imps);
374                                                                                 if (cfKey && cfValue)
375                                                                                 {
376                                                                                         CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue);
377                                                                                 }
378                                                                                 ReleaseCFType(cfKey);
379                                                                                 ReleaseCFType(cfValue);
380                                                                         }
381                                                                         ++iter;
382                                                                 }
383                                                         }
384                                                 }
385 #endif
386                                         }
387                                 }
388                         }
389                         break;
390
391 #if !JAG_PINK_OR_LATER
392                 case ReferenceType:
393                         {
394                                 ValueImp *value = inValue->getValue(exec);
395                                 result = KJSValueToCFTypeInternal(value, exec, NULL);
396                         }
397                         break;
398
399                 case ListType:
400                         {
401                                 List list = List::dynamicCast(inValue);
402                                 if (!list.isNull())
403                                 {
404                                         result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
405                                         if (result)
406                                         {
407                                                 ListIterator iter = list.begin();
408                                                 ListIterator end = list.end();
409                                                 while (iter != end)
410                                                 {
411                                                         CFTypeRef cfTypeRef = KJSValueToCFTypeInternal(*iter, exec, NULL);
412                                                         if (cfTypeRef)
413                                                                 CFArrayAppendValue((CFMutableArrayRef)result, cfTypeRef);
414                                                         ++iter;
415                                                 }
416                                         }
417                                 }
418                         }
419                         break;
420 #endif
421                 
422                 case NullType:
423                 case UndefinedType:
424                 case UnspecifiedType:
425                         result = RetainCFType(GetCFNull());
426                         break;
427                         
428 #if !JAG_PINK_OR_LATER
429                 case CompletionType:
430                         {
431                                 Completion completion = Completion::dynamicCast(inValue);
432                                 if (completion.isValueCompletion())
433                                 {
434                                         result = KJSValueToCFTypeInternal(completion.value(), exec, NULL);
435                                 }
436                         }
437                         break;
438 #endif
439
440 #if JAG_PINK_OR_LATER
441                 default:
442                         fprintf(stderr, "KJSValueToCFType: wrong value type %d\n", inValue->type());
443                         break;
444 #endif
445         }
446         
447         return result;
448 }
449
450 CFTypeRef KJSValueToCFType(ValueImp *inValue, ExecState *exec)
451 {
452         return KJSValueToCFTypeInternal(inValue, exec, NULL);
453 }
454
455 CFTypeRef GetCFNull(void)
456 {
457         static CFArrayRef sCFNull = CFArrayCreate(NULL, NULL, 0, NULL);
458         CFTypeRef result = JSGetCFNull();
459         if (!result)
460         {
461                 result = sCFNull;
462         }
463         return result;
464 }
465