blob: 53af5055e63e6761ad98462522500bb9b2307852 [file] [log] [blame]
thatcher43a8c5172006-01-19 02:40:56 +00001/*
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 */
mjs7f5285a2005-09-06 08:10:03 +000028
mjs3bfb61b2006-03-02 09:12:06 +000029#include "config.h"
mjs7f5285a2005-09-06 08:10:03 +000030#include "JSUtils.h"
31#include "JSBase.h"
32#include "JSObject.h"
33#include "JSRun.h"
34#include "UserObjectImp.h"
35#include "JSValueWrapper.h"
36#include "JSObject.h"
mjsb3598b82006-07-16 21:06:28 +000037#include <JavaScriptCore/PropertyNameArray.h>
mjs7f5285a2005-09-06 08:10:03 +000038
39struct ObjectImpList {
darinb139ea12005-12-11 02:03:35 +000040 JSObject* imp;
darin09654692005-10-10 23:32:34 +000041 ObjectImpList* next;
42 CFTypeRef data;
mjs7f5285a2005-09-06 08:10:03 +000043};
44
darinb139ea12005-12-11 02:03:35 +000045static CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps);
mjs7f5285a2005-09-06 08:10:03 +000046
47
48//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +000049// CFStringToUString
mjs7f5285a2005-09-06 08:10:03 +000050//--------------------------------------------------------------------------
51
52UString CFStringToUString(CFStringRef inCFString)
53{
mjsb156cfd2005-10-06 04:36:04 +000054 UString result;
55 if (inCFString) {
mjs7f5285a2005-09-06 08:10:03 +000056 CFIndex len = CFStringGetLength(inCFString);
57 UniChar* buffer = (UniChar*)malloc(sizeof(UniChar) * len);
58 if (buffer)
59 {
60 CFStringGetCharacters(inCFString, CFRangeMake(0, len), buffer);
61 result = UString((const UChar *)buffer, len);
62 free(buffer);
63 }
64 }
mjsb156cfd2005-10-06 04:36:04 +000065 return result;
mjs7f5285a2005-09-06 08:10:03 +000066}
67
68
69//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +000070// UStringToCFString
mjs7f5285a2005-09-06 08:10:03 +000071//--------------------------------------------------------------------------
72// Caller is responsible for releasing the returned CFStringRef
73CFStringRef UStringToCFString(const UString& inUString)
74{
darin09654692005-10-10 23:32:34 +000075 return CFStringCreateWithCharacters(0, (const UniChar*)inUString.data(), inUString.size());
mjs7f5285a2005-09-06 08:10:03 +000076}
77
78
mjs7f5285a2005-09-06 08:10:03 +000079//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +000080// CFStringToIdentifier
mjs7f5285a2005-09-06 08:10:03 +000081//--------------------------------------------------------------------------
82
83Identifier CFStringToIdentifier(CFStringRef inCFString)
84{
darin09654692005-10-10 23:32:34 +000085 return Identifier(CFStringToUString(inCFString));
mjs7f5285a2005-09-06 08:10:03 +000086}
87
88
89//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +000090// IdentifierToCFString
mjs7f5285a2005-09-06 08:10:03 +000091//--------------------------------------------------------------------------
92// Caller is responsible for releasing the returned CFStringRef
93CFStringRef IdentifierToCFString(const Identifier& inIdentifier)
94{
darin09654692005-10-10 23:32:34 +000095 return UStringToCFString(inIdentifier.ustring());
mjs7f5285a2005-09-06 08:10:03 +000096}
mjs7f5285a2005-09-06 08:10:03 +000097
98
99//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +0000100// KJSValueToJSObject
mjs7f5285a2005-09-06 08:10:03 +0000101//--------------------------------------------------------------------------
darinb139ea12005-12-11 02:03:35 +0000102JSUserObject* KJSValueToJSObject(JSValue *inValue, ExecState *exec)
mjs7f5285a2005-09-06 08:10:03 +0000103{
darin09654692005-10-10 23:32:34 +0000104 JSUserObject* result = 0;
105
mjs1edef722005-10-07 04:22:50 +0000106 if (inValue->isObject(&UserObjectImp::info)) {
107 UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
108 result = userObjectImp->GetJSUserObject();
darin09654692005-10-10 23:32:34 +0000109 if (result)
mjs1edef722005-10-07 04:22:50 +0000110 result->Retain();
111 } else {
ggarendb16cf42006-04-02 08:55:58 +0000112 JSValueWrapper* wrapperValue = new JSValueWrapper(inValue);
mjs1edef722005-10-07 04:22:50 +0000113 if (wrapperValue) {
114 JSObjectCallBacks callBacks;
115 JSValueWrapper::GetJSObectCallBacks(callBacks);
116 result = (JSUserObject*)JSObjectCreate(wrapperValue, &callBacks);
117 if (!result) {
118 delete wrapperValue;
119 }
120 }
121 }
122 return result;
mjs7f5285a2005-09-06 08:10:03 +0000123}
124
125//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +0000126// JSObjectKJSValue
mjs7f5285a2005-09-06 08:10:03 +0000127//--------------------------------------------------------------------------
darinb139ea12005-12-11 02:03:35 +0000128JSValue *JSObjectKJSValue(JSUserObject* ptr)
mjs7f5285a2005-09-06 08:10:03 +0000129{
mjsa564fe12005-11-27 03:10:03 +0000130 JSLock lock;
mjsb156cfd2005-10-06 04:36:04 +0000131
darinb139ea12005-12-11 02:03:35 +0000132 JSValue *result = jsUndefined();
mjs7f5285a2005-09-06 08:10:03 +0000133 if (ptr)
134 {
135 bool handled = false;
darin09654692005-10-10 23:32:34 +0000136
mjs7f5285a2005-09-06 08:10:03 +0000137 switch (ptr->DataType())
138 {
139 case kJSUserObjectDataTypeJSValueWrapper:
140 {
141 JSValueWrapper* wrapper = (JSValueWrapper*)ptr->GetData();
142 if (wrapper)
143 {
144 result = wrapper->GetValue();
145 handled = true;
146 }
147 break;
148 }
darin09654692005-10-10 23:32:34 +0000149
mjs7f5285a2005-09-06 08:10:03 +0000150 case kJSUserObjectDataTypeCFType:
151 {
152 CFTypeRef cfType = (CFTypeRef*)ptr->GetData();
153 if (cfType)
154 {
155 CFTypeID typeID = CFGetTypeID(cfType);
156 if (typeID == CFStringGetTypeID())
157 {
darin9bd60642005-12-11 00:35:59 +0000158 result = jsString(CFStringToUString((CFStringRef)cfType));
mjs7f5285a2005-09-06 08:10:03 +0000159 handled = true;
160 }
161 else if (typeID == CFNumberGetTypeID())
162 {
darinfa0c87f2007-02-16 21:56:43 +0000163 double num;
164 CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num);
165 result = jsNumber(num);
166 handled = true;
mjs7f5285a2005-09-06 08:10:03 +0000167 }
168 else if (typeID == CFBooleanGetTypeID())
169 {
darin9bd60642005-12-11 00:35:59 +0000170 result = jsBoolean(CFBooleanGetValue((CFBooleanRef)cfType));
mjs7f5285a2005-09-06 08:10:03 +0000171 handled = true;
172 }
mjs7f5285a2005-09-06 08:10:03 +0000173 else if (typeID == CFNullGetTypeID())
174 {
darin9bd60642005-12-11 00:35:59 +0000175 result = jsNull();
mjs7f5285a2005-09-06 08:10:03 +0000176 handled = true;
177 }
178 }
179 break;
180 }
181 }
182 if (!handled)
183 {
mjs1edef722005-10-07 04:22:50 +0000184 result = new UserObjectImp(ptr);
mjs7f5285a2005-09-06 08:10:03 +0000185 }
186 }
187 return result;
188}
189
190
191
192
193//--------------------------------------------------------------------------
darin09654692005-10-10 23:32:34 +0000194// KJSValueToCFTypeInternal
mjs7f5285a2005-09-06 08:10:03 +0000195//--------------------------------------------------------------------------
196// Caller is responsible for releasing the returned CFTypeRef
darinb139ea12005-12-11 02:03:35 +0000197CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps)
mjs7f5285a2005-09-06 08:10:03 +0000198{
ggarenab4c7222005-11-11 05:15:02 +0000199 if (!inValue)
darin09654692005-10-10 23:32:34 +0000200 return 0;
201
202 CFTypeRef result = 0;
203
mjsa564fe12005-11-27 03:10:03 +0000204 JSLock lock;
mjsb156cfd2005-10-06 04:36:04 +0000205
darin09654692005-10-10 23:32:34 +0000206 switch (inValue->type())
207 {
208 case BooleanType:
209 {
210 result = inValue->toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse;
211 RetainCFType(result);
212 }
213 break;
214
215 case StringType:
216 {
217 UString uString = inValue->toString(exec);
218 result = UStringToCFString(uString);
219 }
220 break;
221
222 case NumberType:
223 {
224 double number1 = inValue->toNumber(exec);
225 double number2 = (double)inValue->toInteger(exec);
226 if (number1 == number2)
227 {
228 int intValue = (int)number2;
229 result = CFNumberCreate(0, kCFNumberIntType, &intValue);
230 }
231 else
232 {
233 result = CFNumberCreate(0, kCFNumberDoubleType, &number1);
234 }
235 }
236 break;
237
238 case ObjectType:
239 {
mjs1edef722005-10-07 04:22:50 +0000240 if (inValue->isObject(&UserObjectImp::info)) {
241 UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
darin09654692005-10-10 23:32:34 +0000242 JSUserObject* ptr = userObjectImp->GetJSUserObject();
243 if (ptr)
244 {
245 result = ptr->CopyCFValue();
246 }
247 }
248 else
249 {
darinb139ea12005-12-11 02:03:35 +0000250 JSObject *object = inValue->toObject(exec);
darin09654692005-10-10 23:32:34 +0000251 UInt8 isArray = false;
mjs7f5285a2005-09-06 08:10:03 +0000252
darin09654692005-10-10 23:32:34 +0000253 // if two objects reference each
darinb139ea12005-12-11 02:03:35 +0000254 JSObject* imp = object;
darin09654692005-10-10 23:32:34 +0000255 ObjectImpList* temp = inImps;
256 while (temp) {
257 if (imp == temp->imp) {
258 return CFRetain(GetCFNull());
259 }
260 temp = temp->next;
261 }
mjs7f5285a2005-09-06 08:10:03 +0000262
darin09654692005-10-10 23:32:34 +0000263 ObjectImpList imps;
264 imps.next = inImps;
265 imps.imp = imp;
mjs7f5285a2005-09-06 08:10:03 +0000266
darin09654692005-10-10 23:32:34 +0000267
mjs7f5285a2005-09-06 08:10:03 +0000268//[...] HACK since we do not have access to the class info we use class name instead
269#if 0
darin09654692005-10-10 23:32:34 +0000270 if (object->inherits(&ArrayInstanceImp::info))
mjs7f5285a2005-09-06 08:10:03 +0000271#else
darin09654692005-10-10 23:32:34 +0000272 if (object->className() == "Array")
mjs7f5285a2005-09-06 08:10:03 +0000273#endif
darin09654692005-10-10 23:32:34 +0000274 {
275 isArray = true;
276 JSInterpreter* intrepreter = (JSInterpreter*)exec->dynamicInterpreter();
277 if (intrepreter && (intrepreter->Flags() & kJSFlagConvertAssociativeArray)) {
mjsb3598b82006-07-16 21:06:28 +0000278 PropertyNameArray propNames;
279 object->getPropertyNames(exec, propNames);
280 PropertyNameArrayIterator iter = propNames.begin();
281 PropertyNameArrayIterator end = propNames.end();
darin09654692005-10-10 23:32:34 +0000282 while(iter != end && isArray)
283 {
mjsb3598b82006-07-16 21:06:28 +0000284 Identifier propName = *iter;
darin09654692005-10-10 23:32:34 +0000285 UString ustr = propName.ustring();
286 const UniChar* uniChars = (const UniChar*)ustr.data();
287 int size = ustr.size();
288 while (size--) {
289 if (uniChars[size] < '0' || uniChars[size] > '9') {
290 isArray = false;
291 break;
292 }
293 }
mjs9b9c2822005-11-02 00:53:05 +0000294 iter++;
darin09654692005-10-10 23:32:34 +0000295 }
296 }
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(0, 0, &kCFTypeArrayCallBacks);
304 if (result)
305 {
306 for (unsigned i = 0; i < length; i++)
307 {
308 CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, i), exec, &imps);
309 CFArrayAppendValue((CFMutableArrayRef)result, cfValue);
310 ReleaseCFType(cfValue);
311 }
312 }
313 }
314 else
315 {
316 // Not an array, just treat it like a dictionary which contains (property name, property value) pairs
mjsb3598b82006-07-16 21:06:28 +0000317 PropertyNameArray propNames;
318 object->getPropertyNames(exec, propNames);
darin09654692005-10-10 23:32:34 +0000319 {
320 result = CFDictionaryCreateMutable(0,
321 0,
322 &kCFTypeDictionaryKeyCallBacks,
323 &kCFTypeDictionaryValueCallBacks);
324 if (result)
325 {
mjsb3598b82006-07-16 21:06:28 +0000326 PropertyNameArrayIterator iter = propNames.begin();
327 PropertyNameArrayIterator end = propNames.end();
darin09654692005-10-10 23:32:34 +0000328 while(iter != end)
329 {
mjsb3598b82006-07-16 21:06:28 +0000330 Identifier propName = *iter;
darin09654692005-10-10 23:32:34 +0000331 if (object->hasProperty(exec, propName))
332 {
333 CFStringRef cfKey = IdentifierToCFString(propName);
334 CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, propName), exec, &imps);
335 if (cfKey && cfValue)
336 {
337 CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue);
338 }
339 ReleaseCFType(cfKey);
340 ReleaseCFType(cfValue);
341 }
mjs9b9c2822005-11-02 00:53:05 +0000342 iter++;
darin09654692005-10-10 23:32:34 +0000343 }
344 }
345 }
346 }
347 }
348 }
349 break;
mjs7f5285a2005-09-06 08:10:03 +0000350
darin09654692005-10-10 23:32:34 +0000351 case NullType:
352 case UndefinedType:
353 case UnspecifiedType:
354 result = RetainCFType(GetCFNull());
355 break;
mjs7f5285a2005-09-06 08:10:03 +0000356
darin09654692005-10-10 23:32:34 +0000357 default:
358 fprintf(stderr, "KJSValueToCFType: wrong value type %d\n", inValue->type());
359 break;
360 }
mjs7f5285a2005-09-06 08:10:03 +0000361
darin09654692005-10-10 23:32:34 +0000362 return result;
mjs7f5285a2005-09-06 08:10:03 +0000363}
364
darinb139ea12005-12-11 02:03:35 +0000365CFTypeRef KJSValueToCFType(JSValue *inValue, ExecState *exec)
mjs7f5285a2005-09-06 08:10:03 +0000366{
darin09654692005-10-10 23:32:34 +0000367 return KJSValueToCFTypeInternal(inValue, exec, 0);
mjs7f5285a2005-09-06 08:10:03 +0000368}
369
370CFTypeRef GetCFNull(void)
371{
darin09654692005-10-10 23:32:34 +0000372 static CFArrayRef sCFNull = CFArrayCreate(0, 0, 0, 0);
373 CFTypeRef result = JSGetCFNull();
374 if (!result)
375 {
376 result = sCFNull;
377 }
378 return result;
mjs7f5285a2005-09-06 08:10:03 +0000379}
380