| /* |
| * Copyright (C) 2010 Google 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: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * 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. |
| * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT |
| * OWNER OR 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 "CppVariant.h" |
| |
| #include "WebBindings.h" |
| #include <limits> |
| #include <wtf/Assertions.h> |
| #include <wtf/StringExtras.h> |
| |
| using namespace WebKit; |
| using namespace std; |
| |
| CppVariant::CppVariant() |
| { |
| type = NPVariantType_Null; |
| } |
| |
| // Note that Set() performs a deep copy, which is necessary to safely |
| // call FreeData() on the value in the destructor. |
| CppVariant::CppVariant(const CppVariant& original) |
| { |
| type = NPVariantType_Null; |
| set(original); |
| } |
| |
| // See comment for copy constructor, above. |
| CppVariant& CppVariant::operator=(const CppVariant& original) |
| { |
| if (&original != this) |
| set(original); |
| return *this; |
| } |
| |
| CppVariant::~CppVariant() |
| { |
| freeData(); |
| } |
| |
| void CppVariant::freeData() |
| { |
| WebBindings::releaseVariantValue(this); |
| } |
| |
| bool CppVariant::isEqual(const CppVariant& other) const |
| { |
| if (type != other.type) |
| return false; |
| |
| switch (type) { |
| case NPVariantType_Bool: |
| return (value.boolValue == other.value.boolValue); |
| case NPVariantType_Int32: |
| return (value.intValue == other.value.intValue); |
| case NPVariantType_Double: |
| return (value.doubleValue == other.value.doubleValue); |
| case NPVariantType_String: { |
| const NPString *this_value = &value.stringValue; |
| const NPString *other_value = &other.value.stringValue; |
| uint32_t len = this_value->UTF8Length; |
| return len == other_value->UTF8Length |
| && !strncmp(this_value->UTF8Characters, |
| other_value->UTF8Characters, len); |
| } |
| case NPVariantType_Null: |
| case NPVariantType_Void: |
| return true; |
| case NPVariantType_Object: { |
| NPObject* thisValue = value.objectValue; |
| NPObject* otherValue = other.value.objectValue; |
| return thisValue->_class == otherValue->_class |
| && thisValue->referenceCount == otherValue->referenceCount; |
| } |
| } |
| return false; |
| } |
| |
| void CppVariant::copyToNPVariant(NPVariant* result) const |
| { |
| result->type = type; |
| switch (type) { |
| case NPVariantType_Bool: |
| result->value.boolValue = value.boolValue; |
| break; |
| case NPVariantType_Int32: |
| result->value.intValue = value.intValue; |
| break; |
| case NPVariantType_Double: |
| result->value.doubleValue = value.doubleValue; |
| break; |
| case NPVariantType_String: |
| WebBindings::initializeVariantWithStringCopy(result, &value.stringValue); |
| break; |
| case NPVariantType_Null: |
| case NPVariantType_Void: |
| // Nothing to set. |
| break; |
| case NPVariantType_Object: |
| result->type = NPVariantType_Object; |
| result->value.objectValue = WebBindings::retainObject(value.objectValue); |
| break; |
| } |
| } |
| |
| void CppVariant::set(const NPVariant& newValue) |
| { |
| freeData(); |
| switch (newValue.type) { |
| case NPVariantType_Bool: |
| set(newValue.value.boolValue); |
| break; |
| case NPVariantType_Int32: |
| set(newValue.value.intValue); |
| break; |
| case NPVariantType_Double: |
| set(newValue.value.doubleValue); |
| break; |
| case NPVariantType_String: |
| set(newValue.value.stringValue); |
| break; |
| case NPVariantType_Null: |
| case NPVariantType_Void: |
| type = newValue.type; |
| break; |
| case NPVariantType_Object: |
| set(newValue.value.objectValue); |
| break; |
| } |
| } |
| |
| void CppVariant::setNull() |
| { |
| freeData(); |
| type = NPVariantType_Null; |
| } |
| |
| void CppVariant::set(bool newValue) |
| { |
| freeData(); |
| type = NPVariantType_Bool; |
| value.boolValue = newValue; |
| } |
| |
| void CppVariant::set(int32_t newValue) |
| { |
| freeData(); |
| type = NPVariantType_Int32; |
| value.intValue = newValue; |
| } |
| |
| void CppVariant::set(double newValue) |
| { |
| freeData(); |
| type = NPVariantType_Double; |
| value.doubleValue = newValue; |
| } |
| |
| // The newValue must be a null-terminated string. |
| void CppVariant::set(const char* newValue) |
| { |
| freeData(); |
| type = NPVariantType_String; |
| NPString newString = {newValue, |
| static_cast<uint32_t>(strlen(newValue))}; |
| WebBindings::initializeVariantWithStringCopy(this, &newString); |
| } |
| |
| void CppVariant::set(const string& newValue) |
| { |
| freeData(); |
| type = NPVariantType_String; |
| NPString newString = {newValue.data(), |
| static_cast<uint32_t>(newValue.size())}; |
| WebBindings::initializeVariantWithStringCopy(this, &newString); |
| } |
| |
| void CppVariant::set(const NPString& newValue) |
| { |
| freeData(); |
| type = NPVariantType_String; |
| WebBindings::initializeVariantWithStringCopy(this, &newValue); |
| } |
| |
| void CppVariant::set(NPObject* newValue) |
| { |
| freeData(); |
| type = NPVariantType_Object; |
| value.objectValue = WebBindings::retainObject(newValue); |
| } |
| |
| string CppVariant::toString() const |
| { |
| ASSERT(isString()); |
| return string(value.stringValue.UTF8Characters, |
| value.stringValue.UTF8Length); |
| } |
| |
| int32_t CppVariant::toInt32() const |
| { |
| if (isInt32()) |
| return value.intValue; |
| if (isDouble()) |
| return static_cast<int32_t>(value.doubleValue); |
| ASSERT_NOT_REACHED(); |
| return 0; |
| } |
| |
| double CppVariant::toDouble() const |
| { |
| if (isInt32()) |
| return static_cast<double>(value.intValue); |
| if (isDouble()) |
| return value.doubleValue; |
| ASSERT_NOT_REACHED(); |
| return 0; |
| } |
| |
| bool CppVariant::toBoolean() const |
| { |
| ASSERT(isBool()); |
| return value.boolValue; |
| } |
| |
| Vector<string> CppVariant::toStringVector() const |
| { |
| |
| ASSERT(isObject()); |
| Vector<string> stringVector; |
| NPObject* npValue = value.objectValue; |
| NPIdentifier lengthId = WebBindings::getStringIdentifier("length"); |
| |
| if (!WebBindings::hasProperty(0, npValue, lengthId)) |
| return stringVector; |
| |
| NPVariant lengthValue; |
| if (!WebBindings::getProperty(0, npValue, lengthId, &lengthValue)) |
| return stringVector; |
| |
| int length = 0; |
| // The length is a double in some cases. |
| if (NPVARIANT_IS_DOUBLE(lengthValue)) |
| length = static_cast<int>(NPVARIANT_TO_DOUBLE(lengthValue)); |
| else if (NPVARIANT_IS_INT32(lengthValue)) |
| length = NPVARIANT_TO_INT32(lengthValue); |
| WebBindings::releaseVariantValue(&lengthValue); |
| |
| // For sanity, only allow 100 items. |
| length = min(100, length); |
| for (int i = 0; i < length; ++i) { |
| // Get each of the items. |
| char indexInChar[20]; // Enough size to store 32-bit integer |
| snprintf(indexInChar, 20, "%d", i); |
| string index(indexInChar); |
| NPIdentifier indexId = WebBindings::getStringIdentifier(index.c_str()); |
| if (!WebBindings::hasProperty(0, npValue, indexId)) |
| continue; |
| NPVariant indexValue; |
| if (!WebBindings::getProperty(0, npValue, indexId, &indexValue)) |
| continue; |
| if (NPVARIANT_IS_STRING(indexValue)) { |
| string item(NPVARIANT_TO_STRING(indexValue).UTF8Characters, |
| NPVARIANT_TO_STRING(indexValue).UTF8Length); |
| stringVector.append(item); |
| } |
| WebBindings::releaseVariantValue(&indexValue); |
| } |
| return stringVector; |
| } |
| |
| bool CppVariant::invoke(const string& method, const CppVariant* arguments, |
| uint32_t argumentCount, CppVariant& result) const |
| { |
| ASSERT(isObject()); |
| NPIdentifier methodName = WebBindings::getStringIdentifier(method.c_str()); |
| NPObject* npObject = value.objectValue; |
| if (!WebBindings::hasMethod(0, npObject, methodName)) |
| return false; |
| NPVariant r; |
| bool status = WebBindings::invoke(0, npObject, methodName, arguments, argumentCount, &r); |
| result.set(r); |
| return status; |
| } |