webengine/osswebengine/JavaScriptGlue/JSUtils.cpp
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/JavaScriptGlue/JSUtils.cpp	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSUtils.h"
+#include "JSBase.h"
+#include "JSObject.h"
+#include "JSRun.h"
+#include "UserObjectImp.h"
+#include "JSValueWrapper.h"
+#include "JSObject.h"
+#include <JavaScriptCore/PropertyNameArray.h>
+
+struct ObjectImpList {
+    JSObject* imp;
+    ObjectImpList* next;
+    CFTypeRef data;
+};
+
+static CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps);
+
+
+//--------------------------------------------------------------------------
+// CFStringToUString
+//--------------------------------------------------------------------------
+
+UString CFStringToUString(CFStringRef inCFString)
+{
+    UString result;
+    if (inCFString) {
+        CFIndex len = CFStringGetLength(inCFString);
+        UniChar* buffer = (UniChar*)malloc(sizeof(UniChar) * len);
+        if (buffer)
+        {
+            CFStringGetCharacters(inCFString, CFRangeMake(0, len), buffer);
+            result = UString((const UChar *)buffer, len);
+            free(buffer);
+        }
+    }
+    return result;
+}
+
+
+//--------------------------------------------------------------------------
+// UStringToCFString
+//--------------------------------------------------------------------------
+// Caller is responsible for releasing the returned CFStringRef
+CFStringRef UStringToCFString(const UString& inUString)
+{
+    return CFStringCreateWithCharacters(0, (const UniChar*)inUString.data(), inUString.size());
+}
+
+
+//--------------------------------------------------------------------------
+// CFStringToIdentifier
+//--------------------------------------------------------------------------
+
+Identifier CFStringToIdentifier(CFStringRef inCFString)
+{
+    return Identifier(CFStringToUString(inCFString));
+}
+
+
+//--------------------------------------------------------------------------
+// IdentifierToCFString
+//--------------------------------------------------------------------------
+// Caller is responsible for releasing the returned CFStringRef
+CFStringRef IdentifierToCFString(const Identifier& inIdentifier)
+{
+    return UStringToCFString(inIdentifier.ustring());
+}
+
+
+//--------------------------------------------------------------------------
+// KJSValueToJSObject
+//--------------------------------------------------------------------------
+JSUserObject* KJSValueToJSObject(JSValue *inValue, ExecState *exec)
+{
+    JSUserObject* result = 0;
+
+    if (inValue->isObject(&UserObjectImp::info)) {
+        UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
+        result = userObjectImp->GetJSUserObject();
+        if (result)
+            result->Retain();
+    } else {
+        JSValueWrapper* wrapperValue = new JSValueWrapper(inValue);
+        if (wrapperValue) {
+            JSObjectCallBacks callBacks;
+            JSValueWrapper::GetJSObectCallBacks(callBacks);
+            result = (JSUserObject*)JSObjectCreate(wrapperValue, &callBacks);
+            if (!result) {
+                delete wrapperValue;
+            }
+        }
+    }
+    return result;
+}
+
+//--------------------------------------------------------------------------
+// JSObjectKJSValue
+//--------------------------------------------------------------------------
+JSValue *JSObjectKJSValue(JSUserObject* ptr)
+{
+    JSLock lock;
+
+    JSValue *result = jsUndefined();
+    if (ptr)
+    {
+        bool handled = false;
+
+        switch (ptr->DataType())
+        {
+            case kJSUserObjectDataTypeJSValueWrapper:
+            {
+                JSValueWrapper* wrapper = (JSValueWrapper*)ptr->GetData();
+                if (wrapper)
+                {
+                    result = wrapper->GetValue();
+                    handled = true;
+                }
+                break;
+            }
+
+            case kJSUserObjectDataTypeCFType:
+            {
+                CFTypeRef cfType = (CFTypeRef*)ptr->GetData();
+                if (cfType)
+                {
+                    CFTypeID typeID = CFGetTypeID(cfType);
+                    if (typeID == CFStringGetTypeID())
+                    {
+                        result = jsString(CFStringToUString((CFStringRef)cfType));
+                        handled = true;
+                    }
+                    else if (typeID == CFNumberGetTypeID())
+                    {
+                        double num;
+                        CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num);
+                        result = jsNumber(num);
+                        handled = true;
+                    }
+                    else if (typeID == CFBooleanGetTypeID())
+                    {
+                        result = jsBoolean(CFBooleanGetValue((CFBooleanRef)cfType));
+                        handled = true;
+                    }
+                    else if (typeID == CFNullGetTypeID())
+                    {
+                        result = jsNull();
+                        handled = true;
+                    }
+                }
+                break;
+            }
+        }
+        if (!handled)
+        {
+            result = new UserObjectImp(ptr);
+        }
+    }
+    return result;
+}
+
+
+
+
+//--------------------------------------------------------------------------
+// KJSValueToCFTypeInternal
+//--------------------------------------------------------------------------
+// Caller is responsible for releasing the returned CFTypeRef
+CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps)
+{
+    if (!inValue)
+        return 0;
+
+    CFTypeRef result = 0;
+
+    JSLock lock;
+
+    switch (inValue->type())
+    {
+        case BooleanType:
+            {
+                result = inValue->toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse;
+                RetainCFType(result);
+            }
+            break;
+
+        case StringType:
+            {
+                UString uString = inValue->toString(exec);
+                result = UStringToCFString(uString);
+            }
+            break;
+
+        case NumberType:
+            {
+                double number1 = inValue->toNumber(exec);
+                double number2 = (double)inValue->toInteger(exec);
+                if (number1 ==  number2)
+                {
+                    int intValue = (int)number2;
+                    result = CFNumberCreate(0, kCFNumberIntType, &intValue);
+                }
+                else
+                {
+                    result = CFNumberCreate(0, kCFNumberDoubleType, &number1);
+                }
+            }
+            break;
+
+        case ObjectType:
+            {
+                            if (inValue->isObject(&UserObjectImp::info)) {
+                                UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
+                    JSUserObject* ptr = userObjectImp->GetJSUserObject();
+                    if (ptr)
+                    {
+                        result = ptr->CopyCFValue();
+                    }
+                }
+                else
+                {
+                    JSObject *object = inValue->toObject(exec);
+                    UInt8 isArray = false;
+
+                    // if two objects reference each
+                    JSObject* imp = object;
+                    ObjectImpList* temp = inImps;
+                    while (temp) {
+                        if (imp == temp->imp) {
+                            return CFRetain(GetCFNull());
+                        }
+                        temp = temp->next;
+                    }
+
+                    ObjectImpList imps;
+                    imps.next = inImps;
+                    imps.imp = imp;
+
+
+//[...] HACK since we do not have access to the class info we use class name instead
+#if 0
+                    if (object->inherits(&ArrayInstanceImp::info))
+#else
+                    if (object->className() == "Array")
+#endif
+                    {
+                        isArray = true;
+                        JSInterpreter* intrepreter = (JSInterpreter*)exec->dynamicInterpreter();
+                        if (intrepreter && (intrepreter->Flags() & kJSFlagConvertAssociativeArray)) {
+                            PropertyNameArray propNames;
+                            object->getPropertyNames(exec, propNames);
+                            PropertyNameArrayIterator iter = propNames.begin();
+                            PropertyNameArrayIterator end = propNames.end();
+                            while(iter != end && isArray)
+                            {
+                                Identifier propName = *iter;
+                                UString ustr = propName.ustring();
+                                const UniChar* uniChars = (const UniChar*)ustr.data();
+                                int size = ustr.size();
+                                while (size--) {
+                                    if (uniChars[size] < '0' || uniChars[size] > '9') {
+                                        isArray = false;
+                                        break;
+                                    }
+                                }
+                                iter++;
+                            }
+                        }
+                    }
+
+                    if (isArray)
+                    {
+                        // This is an KJS array
+                        unsigned int length = object->get(exec, "length")->toUInt32(exec);
+                        result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
+                        if (result)
+                        {
+                            for (unsigned i = 0; i < length; i++)
+                            {
+                                CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, i), exec, &imps);
+                                CFArrayAppendValue((CFMutableArrayRef)result, cfValue);
+                                ReleaseCFType(cfValue);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // Not an array, just treat it like a dictionary which contains (property name, property value) pairs
+                        PropertyNameArray propNames;
+                        object->getPropertyNames(exec, propNames);
+                        {
+                            result = CFDictionaryCreateMutable(0,
+                                                               0,
+                                                               &kCFTypeDictionaryKeyCallBacks,
+                                                               &kCFTypeDictionaryValueCallBacks);
+                            if (result)
+                            {
+                                PropertyNameArrayIterator iter = propNames.begin();
+                                PropertyNameArrayIterator end = propNames.end();
+                                while(iter != end)
+                                {
+                                    Identifier propName = *iter;
+                                    if (object->hasProperty(exec, propName))
+                                    {
+                                        CFStringRef cfKey = IdentifierToCFString(propName);
+                                        CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, propName), exec, &imps);
+                                        if (cfKey && cfValue)
+                                        {
+                                            CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue);
+                                        }
+                                        ReleaseCFType(cfKey);
+                                        ReleaseCFType(cfValue);
+                                    }
+                                    iter++;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            break;
+
+        case NullType:
+        case UndefinedType:
+        case UnspecifiedType:
+            result = RetainCFType(GetCFNull());
+            break;
+
+        default:
+            fprintf(stderr, "KJSValueToCFType: wrong value type %d\n", inValue->type());
+            break;
+    }
+
+    return result;
+}
+
+CFTypeRef KJSValueToCFType(JSValue *inValue, ExecState *exec)
+{
+    return KJSValueToCFTypeInternal(inValue, exec, 0);
+}
+
+CFTypeRef GetCFNull(void)
+{
+    static CFArrayRef sCFNull = CFArrayCreate(0, 0, 0, 0);
+    CFTypeRef result = JSGetCFNull();
+    if (!result)
+    {
+        result = sCFNull;
+    }
+    return result;
+}
+