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