/* * 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; }