025de485a9cf0dd46856c541bab2e71c6b4f0a38
[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/reference_list.h"
13
14 struct ObjectImpList {
15     JSObject* imp;
16     ObjectImpList* next;
17     CFTypeRef data;
18 };
19
20 static CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps);
21
22
23 //--------------------------------------------------------------------------
24 // CFStringToUString
25 //--------------------------------------------------------------------------
26
27 UString CFStringToUString(CFStringRef inCFString)
28 {
29     JSLock 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(0, (const UniChar*)inUString.data(), inUString.size());
53 }
54
55
56 //--------------------------------------------------------------------------
57 // CFStringToIdentifier
58 //--------------------------------------------------------------------------
59
60 Identifier CFStringToIdentifier(CFStringRef inCFString)
61 {
62     return Identifier(CFStringToUString(inCFString));
63 }
64
65
66 //--------------------------------------------------------------------------
67 // IdentifierToCFString
68 //--------------------------------------------------------------------------
69 // Caller is responsible for releasing the returned CFStringRef
70 CFStringRef IdentifierToCFString(const Identifier& inIdentifier)
71 {
72     return UStringToCFString(inIdentifier.ustring());
73 }
74
75
76 //--------------------------------------------------------------------------
77 // KJSValueToJSObject
78 //--------------------------------------------------------------------------
79 JSUserObject* KJSValueToJSObject(JSValue *inValue, ExecState *exec)
80 {
81     JSUserObject* result = 0;
82
83     if (inValue->isObject(&UserObjectImp::info)) {
84         UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
85         result = userObjectImp->GetJSUserObject();
86         if (result)
87             result->Retain();
88     } else {
89         JSValueWrapper* wrapperValue = new JSValueWrapper(inValue, exec);
90         if (wrapperValue) {
91             JSObjectCallBacks callBacks;
92             JSValueWrapper::GetJSObectCallBacks(callBacks);
93             result = (JSUserObject*)JSObjectCreate(wrapperValue, &callBacks);
94             if (!result) {
95                 delete wrapperValue;
96             }
97         }
98     }
99     return result;
100 }
101
102 //--------------------------------------------------------------------------
103 // JSObjectKJSValue
104 //--------------------------------------------------------------------------
105 JSValue *JSObjectKJSValue(JSUserObject* ptr)
106 {
107     JSLock lock;
108
109     JSValue *result = jsUndefined();
110     if (ptr)
111     {
112         bool handled = false;
113
114         switch (ptr->DataType())
115         {
116             case kJSUserObjectDataTypeJSValueWrapper:
117             {
118                 JSValueWrapper* wrapper = (JSValueWrapper*)ptr->GetData();
119                 if (wrapper)
120                 {
121                     result = wrapper->GetValue();
122                     handled = true;
123                 }
124                 break;
125             }
126
127             case kJSUserObjectDataTypeCFType:
128             {
129                 CFTypeRef cfType = (CFTypeRef*)ptr->GetData();
130                 if (cfType)
131                 {
132                     CFTypeID typeID = CFGetTypeID(cfType);
133                     if (typeID == CFStringGetTypeID())
134                     {
135                         result = jsString(CFStringToUString((CFStringRef)cfType));
136                         handled = true;
137                     }
138                     else if (typeID == CFNumberGetTypeID())
139                     {
140                         if (CFNumberIsFloatType((CFNumberRef)cfType))
141                         {
142                             double num;
143                             if (CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num))
144                             {
145                                 result = jsNumber(num);
146                                 handled = true;
147                             }
148                         }
149                         else
150                         {
151                             long num;
152                             if (CFNumberGetValue((CFNumberRef)cfType, kCFNumberLongType, &num))
153                             {
154                                 result = jsNumber(num);
155                                 handled = true;
156                             }
157                         }
158                     }
159                     else if (typeID == CFBooleanGetTypeID())
160                     {
161                         result = jsBoolean(CFBooleanGetValue((CFBooleanRef)cfType));
162                         handled = true;
163                     }
164                     else if (typeID == CFDateGetTypeID())
165                     {
166                     }
167                     else if (typeID == CFNullGetTypeID())
168                     {
169                         result = jsNull();
170                         handled = true;
171                     }
172                 }
173                 break;
174             }
175         }
176         if (!handled)
177         {
178             result = new UserObjectImp(ptr);
179         }
180     }
181     return result;
182 }
183
184
185
186
187 //--------------------------------------------------------------------------
188 // KJSValueToCFTypeInternal
189 //--------------------------------------------------------------------------
190 // Caller is responsible for releasing the returned CFTypeRef
191 CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps)
192 {
193     if (!inValue)
194         return 0;
195
196     CFTypeRef result = 0;
197
198     JSLock lock;
199
200     switch (inValue->type())
201     {
202         case BooleanType:
203             {
204                 result = inValue->toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse;
205                 RetainCFType(result);
206             }
207             break;
208
209         case StringType:
210             {
211                 UString uString = inValue->toString(exec);
212                 result = UStringToCFString(uString);
213             }
214             break;
215
216         case NumberType:
217             {
218                 double number1 = inValue->toNumber(exec);
219                 double number2 = (double)inValue->toInteger(exec);
220                 if (number1 ==  number2)
221                 {
222                     int intValue = (int)number2;
223                     result = CFNumberCreate(0, kCFNumberIntType, &intValue);
224                 }
225                 else
226                 {
227                     result = CFNumberCreate(0, kCFNumberDoubleType, &number1);
228                 }
229             }
230             break;
231
232         case ObjectType:
233             {
234                             if (inValue->isObject(&UserObjectImp::info)) {
235                                 UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
236                     JSUserObject* ptr = userObjectImp->GetJSUserObject();
237                     if (ptr)
238                     {
239                         result = ptr->CopyCFValue();
240                     }
241                 }
242                 else
243                 {
244                     JSObject *object = inValue->toObject(exec);
245                     UInt8 isArray = false;
246
247                     // if two objects reference each
248                     JSObject* imp = object;
249                     ObjectImpList* temp = inImps;
250                     while (temp) {
251                         if (imp == temp->imp) {
252                             return CFRetain(GetCFNull());
253                         }
254                         temp = temp->next;
255                     }
256
257                     ObjectImpList imps;
258                     imps.next = inImps;
259                     imps.imp = imp;
260
261
262 //[...] HACK since we do not have access to the class info we use class name instead
263 #if 0
264                     if (object->inherits(&ArrayInstanceImp::info))
265 #else
266                     if (object->className() == "Array")
267 #endif
268                     {
269                         isArray = true;
270                         JSInterpreter* intrepreter = (JSInterpreter*)exec->dynamicInterpreter();
271                         if (intrepreter && (intrepreter->Flags() & kJSFlagConvertAssociativeArray)) {
272                             ReferenceList propList = object->propList(exec);
273                             ReferenceListIterator iter = propList.begin();
274                             ReferenceListIterator end = propList.end();
275                             while(iter != end && isArray)
276                             {
277                                 Identifier propName = iter->getPropertyName(exec);
278                                 UString ustr = propName.ustring();
279                                 const UniChar* uniChars = (const UniChar*)ustr.data();
280                                 int size = ustr.size();
281                                 while (size--) {
282                                     if (uniChars[size] < '0' || uniChars[size] > '9') {
283                                         isArray = false;
284                                         break;
285                                     }
286                                 }
287                                 iter++;
288                             }
289                         }
290                     }
291
292                     if (isArray)
293                     {
294                         // This is an KJS array
295                         unsigned int length = object->get(exec, "length")->toUInt32(exec);
296                         result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
297                         if (result)
298                         {
299                             for (unsigned i = 0; i < length; i++)
300                             {
301                                 CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, i), exec, &imps);
302                                 CFArrayAppendValue((CFMutableArrayRef)result, cfValue);
303                                 ReleaseCFType(cfValue);
304                             }
305                         }
306                     }
307                     else
308                     {
309                         // Not an array, just treat it like a dictionary which contains (property name, property value) pairs
310                         ReferenceList propList = object->propList(exec);
311                         {
312                             result = CFDictionaryCreateMutable(0,
313                                                                0,
314                                                                &kCFTypeDictionaryKeyCallBacks,
315                                                                &kCFTypeDictionaryValueCallBacks);
316                             if (result)
317                             {
318                                 ReferenceListIterator iter = propList.begin();
319                                 ReferenceListIterator end = propList.end();
320                                 while(iter != end)
321                                 {
322                                     Identifier propName = iter->getPropertyName(exec);
323                                     if (object->hasProperty(exec, propName))
324                                     {
325                                         CFStringRef cfKey = IdentifierToCFString(propName);
326                                         CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, propName), exec, &imps);
327                                         if (cfKey && cfValue)
328                                         {
329                                             CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue);
330                                         }
331                                         ReleaseCFType(cfKey);
332                                         ReleaseCFType(cfValue);
333                                     }
334                                     iter++;
335                                 }
336                             }
337                         }
338                     }
339                 }
340             }
341             break;
342
343         case NullType:
344         case UndefinedType:
345         case UnspecifiedType:
346             result = RetainCFType(GetCFNull());
347             break;
348
349         default:
350             fprintf(stderr, "KJSValueToCFType: wrong value type %d\n", inValue->type());
351             break;
352     }
353
354     return result;
355 }
356
357 CFTypeRef KJSValueToCFType(JSValue *inValue, ExecState *exec)
358 {
359     return KJSValueToCFTypeInternal(inValue, exec, 0);
360 }
361
362 CFTypeRef GetCFNull(void)
363 {
364     static CFArrayRef sCFNull = CFArrayCreate(0, 0, 0, 0);
365     CFTypeRef result = JSGetCFNull();
366     if (!result)
367     {
368         result = sCFNull;
369     }
370     return result;
371 }
372