webengine/osswebengine/JavaScriptGlue/JSUtils.cpp
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     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  */
       
    28 
       
    29 #include "config.h"
       
    30 #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"
       
    37 #include <JavaScriptCore/PropertyNameArray.h>
       
    38 
       
    39 struct ObjectImpList {
       
    40     JSObject* imp;
       
    41     ObjectImpList* next;
       
    42     CFTypeRef data;
       
    43 };
       
    44 
       
    45 static CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps);
       
    46 
       
    47 
       
    48 //--------------------------------------------------------------------------
       
    49 // CFStringToUString
       
    50 //--------------------------------------------------------------------------
       
    51 
       
    52 UString CFStringToUString(CFStringRef inCFString)
       
    53 {
       
    54     UString result;
       
    55     if (inCFString) {
       
    56         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     }
       
    65     return result;
       
    66 }
       
    67 
       
    68 
       
    69 //--------------------------------------------------------------------------
       
    70 // UStringToCFString
       
    71 //--------------------------------------------------------------------------
       
    72 // Caller is responsible for releasing the returned CFStringRef
       
    73 CFStringRef UStringToCFString(const UString& inUString)
       
    74 {
       
    75     return CFStringCreateWithCharacters(0, (const UniChar*)inUString.data(), inUString.size());
       
    76 }
       
    77 
       
    78 
       
    79 //--------------------------------------------------------------------------
       
    80 // CFStringToIdentifier
       
    81 //--------------------------------------------------------------------------
       
    82 
       
    83 Identifier CFStringToIdentifier(CFStringRef inCFString)
       
    84 {
       
    85     return Identifier(CFStringToUString(inCFString));
       
    86 }
       
    87 
       
    88 
       
    89 //--------------------------------------------------------------------------
       
    90 // IdentifierToCFString
       
    91 //--------------------------------------------------------------------------
       
    92 // Caller is responsible for releasing the returned CFStringRef
       
    93 CFStringRef IdentifierToCFString(const Identifier& inIdentifier)
       
    94 {
       
    95     return UStringToCFString(inIdentifier.ustring());
       
    96 }
       
    97 
       
    98 
       
    99 //--------------------------------------------------------------------------
       
   100 // KJSValueToJSObject
       
   101 //--------------------------------------------------------------------------
       
   102 JSUserObject* KJSValueToJSObject(JSValue *inValue, ExecState *exec)
       
   103 {
       
   104     JSUserObject* result = 0;
       
   105 
       
   106     if (inValue->isObject(&UserObjectImp::info)) {
       
   107         UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
       
   108         result = userObjectImp->GetJSUserObject();
       
   109         if (result)
       
   110             result->Retain();
       
   111     } else {
       
   112         JSValueWrapper* wrapperValue = new JSValueWrapper(inValue);
       
   113         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;
       
   123 }
       
   124 
       
   125 //--------------------------------------------------------------------------
       
   126 // JSObjectKJSValue
       
   127 //--------------------------------------------------------------------------
       
   128 JSValue *JSObjectKJSValue(JSUserObject* ptr)
       
   129 {
       
   130     JSLock lock;
       
   131 
       
   132     JSValue *result = jsUndefined();
       
   133     if (ptr)
       
   134     {
       
   135         bool handled = false;
       
   136 
       
   137         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             }
       
   149 
       
   150             case kJSUserObjectDataTypeCFType:
       
   151             {
       
   152                 CFTypeRef cfType = (CFTypeRef*)ptr->GetData();
       
   153                 if (cfType)
       
   154                 {
       
   155                     CFTypeID typeID = CFGetTypeID(cfType);
       
   156                     if (typeID == CFStringGetTypeID())
       
   157                     {
       
   158                         result = jsString(CFStringToUString((CFStringRef)cfType));
       
   159                         handled = true;
       
   160                     }
       
   161                     else if (typeID == CFNumberGetTypeID())
       
   162                     {
       
   163                         double num;
       
   164                         CFNumberGetValue((CFNumberRef)cfType, kCFNumberDoubleType, &num);
       
   165                         result = jsNumber(num);
       
   166                         handled = true;
       
   167                     }
       
   168                     else if (typeID == CFBooleanGetTypeID())
       
   169                     {
       
   170                         result = jsBoolean(CFBooleanGetValue((CFBooleanRef)cfType));
       
   171                         handled = true;
       
   172                     }
       
   173                     else if (typeID == CFNullGetTypeID())
       
   174                     {
       
   175                         result = jsNull();
       
   176                         handled = true;
       
   177                     }
       
   178                 }
       
   179                 break;
       
   180             }
       
   181         }
       
   182         if (!handled)
       
   183         {
       
   184             result = new UserObjectImp(ptr);
       
   185         }
       
   186     }
       
   187     return result;
       
   188 }
       
   189 
       
   190 
       
   191 
       
   192 
       
   193 //--------------------------------------------------------------------------
       
   194 // KJSValueToCFTypeInternal
       
   195 //--------------------------------------------------------------------------
       
   196 // Caller is responsible for releasing the returned CFTypeRef
       
   197 CFTypeRef KJSValueToCFTypeInternal(JSValue *inValue, ExecState *exec, ObjectImpList* inImps)
       
   198 {
       
   199     if (!inValue)
       
   200         return 0;
       
   201 
       
   202     CFTypeRef result = 0;
       
   203 
       
   204     JSLock lock;
       
   205 
       
   206     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             {
       
   240                             if (inValue->isObject(&UserObjectImp::info)) {
       
   241                                 UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(inValue);
       
   242                     JSUserObject* ptr = userObjectImp->GetJSUserObject();
       
   243                     if (ptr)
       
   244                     {
       
   245                         result = ptr->CopyCFValue();
       
   246                     }
       
   247                 }
       
   248                 else
       
   249                 {
       
   250                     JSObject *object = inValue->toObject(exec);
       
   251                     UInt8 isArray = false;
       
   252 
       
   253                     // if two objects reference each
       
   254                     JSObject* imp = object;
       
   255                     ObjectImpList* temp = inImps;
       
   256                     while (temp) {
       
   257                         if (imp == temp->imp) {
       
   258                             return CFRetain(GetCFNull());
       
   259                         }
       
   260                         temp = temp->next;
       
   261                     }
       
   262 
       
   263                     ObjectImpList imps;
       
   264                     imps.next = inImps;
       
   265                     imps.imp = imp;
       
   266 
       
   267 
       
   268 //[...] HACK since we do not have access to the class info we use class name instead
       
   269 #if 0
       
   270                     if (object->inherits(&ArrayInstanceImp::info))
       
   271 #else
       
   272                     if (object->className() == "Array")
       
   273 #endif
       
   274                     {
       
   275                         isArray = true;
       
   276                         JSInterpreter* intrepreter = (JSInterpreter*)exec->dynamicInterpreter();
       
   277                         if (intrepreter && (intrepreter->Flags() & kJSFlagConvertAssociativeArray)) {
       
   278                             PropertyNameArray propNames;
       
   279                             object->getPropertyNames(exec, propNames);
       
   280                             PropertyNameArrayIterator iter = propNames.begin();
       
   281                             PropertyNameArrayIterator end = propNames.end();
       
   282                             while(iter != end && isArray)
       
   283                             {
       
   284                                 Identifier propName = *iter;
       
   285                                 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                                 }
       
   294                                 iter++;
       
   295                             }
       
   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
       
   317                         PropertyNameArray propNames;
       
   318                         object->getPropertyNames(exec, propNames);
       
   319                         {
       
   320                             result = CFDictionaryCreateMutable(0,
       
   321                                                                0,
       
   322                                                                &kCFTypeDictionaryKeyCallBacks,
       
   323                                                                &kCFTypeDictionaryValueCallBacks);
       
   324                             if (result)
       
   325                             {
       
   326                                 PropertyNameArrayIterator iter = propNames.begin();
       
   327                                 PropertyNameArrayIterator end = propNames.end();
       
   328                                 while(iter != end)
       
   329                                 {
       
   330                                     Identifier propName = *iter;
       
   331                                     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                                     }
       
   342                                     iter++;
       
   343                                 }
       
   344                             }
       
   345                         }
       
   346                     }
       
   347                 }
       
   348             }
       
   349             break;
       
   350 
       
   351         case NullType:
       
   352         case UndefinedType:
       
   353         case UnspecifiedType:
       
   354             result = RetainCFType(GetCFNull());
       
   355             break;
       
   356 
       
   357         default:
       
   358             fprintf(stderr, "KJSValueToCFType: wrong value type %d\n", inValue->type());
       
   359             break;
       
   360     }
       
   361 
       
   362     return result;
       
   363 }
       
   364 
       
   365 CFTypeRef KJSValueToCFType(JSValue *inValue, ExecState *exec)
       
   366 {
       
   367     return KJSValueToCFTypeInternal(inValue, exec, 0);
       
   368 }
       
   369 
       
   370 CFTypeRef GetCFNull(void)
       
   371 {
       
   372     static CFArrayRef sCFNull = CFArrayCreate(0, 0, 0, 0);
       
   373     CFTypeRef result = JSGetCFNull();
       
   374     if (!result)
       
   375     {
       
   376         result = sCFNull;
       
   377     }
       
   378     return result;
       
   379 }
       
   380