// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // This file contains definitions for CppVariant. #include <limits> #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" #include "webkit/glue/cpp_variant.h" #include "base/logging.h" #include "base/string_util.h" #include "base/stringprintf.h" #include "base/utf_string_conversions.h" using WebKit::WebBindings; 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 *this_value = value.objectValue; NPObject *other_value = other.value.objectValue; return (this_value->_class == other_value->_class && this_value->referenceCount == other_value->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& new_value) { FreeData(); switch (new_value.type) { case NPVariantType_Bool: Set(new_value.value.boolValue); break; case NPVariantType_Int32: Set(new_value.value.intValue); break; case NPVariantType_Double: Set(new_value.value.doubleValue); break; case NPVariantType_String: Set(new_value.value.stringValue); break; case NPVariantType_Null: case NPVariantType_Void: type = new_value.type; break; case NPVariantType_Object: Set(new_value.value.objectValue); break; } } void CppVariant::SetNull() { FreeData(); type = NPVariantType_Null; } void CppVariant::Set(bool new_value) { FreeData(); type = NPVariantType_Bool; value.boolValue = new_value; } void CppVariant::Set(int32_t new_value) { FreeData(); type = NPVariantType_Int32; value.intValue = new_value; } void CppVariant::Set(double new_value) { FreeData(); type = NPVariantType_Double; value.doubleValue = new_value; } // The new_value must be a null-terminated string. void CppVariant::Set(const char* new_value) { FreeData(); type = NPVariantType_String; NPString new_string = {new_value, static_cast<uint32_t>(strlen(new_value))}; WebBindings::initializeVariantWithStringCopy(this, &new_string); } void CppVariant::Set(const std::string& new_value) { FreeData(); type = NPVariantType_String; NPString new_string = {new_value.data(), static_cast<uint32_t>(new_value.size())}; WebBindings::initializeVariantWithStringCopy(this, &new_string); } void CppVariant::Set(const NPString& new_value) { FreeData(); type = NPVariantType_String; WebBindings::initializeVariantWithStringCopy(this, &new_value); } void CppVariant::Set(NPObject* new_value) { FreeData(); type = NPVariantType_Object; value.objectValue = WebBindings::retainObject(new_value); } std::string CppVariant::ToString() const { DCHECK(isString()); return std::string(value.stringValue.UTF8Characters, value.stringValue.UTF8Length); } int32_t CppVariant::ToInt32() const { if (isInt32()) { return value.intValue; } else if (isDouble()) { return static_cast<int32_t>(value.doubleValue); } else { NOTREACHED(); return 0; } } double CppVariant::ToDouble() const { if (isInt32()) { return static_cast<double>(value.intValue); } else if (isDouble()) { return value.doubleValue; } else { NOTREACHED(); return 0.0; } } bool CppVariant::ToBoolean() const { DCHECK(isBool()); return value.boolValue; } std::vector<CppVariant> CppVariant::ToVector() const { DCHECK(isObject()); std::vector<CppVariant> vector; NPObject* np_value = value.objectValue; NPIdentifier length_id = WebBindings::getStringIdentifier("length"); if (WebBindings::hasProperty(NULL, np_value, length_id)) { CppVariant length_value; if (WebBindings::getProperty(NULL, np_value, length_id, &length_value)) { int length = 0; // The length is a double in some cases. if (NPVARIANT_IS_DOUBLE(length_value)) length = static_cast<int>(NPVARIANT_TO_DOUBLE(length_value)); else if (NPVARIANT_IS_INT32(length_value)) length = NPVARIANT_TO_INT32(length_value); else NOTREACHED(); // For sanity, only allow 60000 items. length = std::min(60000, length); for (int i = 0; i < length; ++i) { // Get each of the items. NPIdentifier index = WebBindings::getIntIdentifier(i); if (WebBindings::hasProperty(NULL, np_value, index)) { CppVariant index_value; if (WebBindings::getProperty(NULL, np_value, index, &index_value)) vector.push_back(index_value); } } } } else { NOTREACHED(); } return vector; } bool CppVariant::Invoke(const std::string& method, const CppVariant* args, uint32 arg_count, CppVariant& result) const { DCHECK(isObject()); NPIdentifier method_name = WebBindings::getStringIdentifier(method.c_str()); NPObject* np_object = value.objectValue; if (WebBindings::hasMethod(NULL, np_object, method_name)) { NPVariant r; bool status = WebBindings::invoke(NULL, np_object, method_name, args, arg_count, &r); result.Set(r); return status; } else { return false; } }