// Copyright (c) 2006-2008 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. #include "webkit/activex_shim/npn_scripting.h" #include "base/logging.h" #include "base/string_util.h" #include "webkit/activex_shim/npp_impl.h" namespace activex_shim { NPNScriptableObject::NPNScriptableObject() : npp_(NULL), object_(NULL) { } NPNScriptableObject::NPNScriptableObject(NPP npp, NPObject* object) : npp_(npp), object_(object) { } NPNScriptableObject::NPNScriptableObject(NPNScriptableObject& object) : npp_(object.npp_), object_(object.object_) { if (object_) g_browser->retainobject(object_); } NPNScriptableObject::~NPNScriptableObject() { Release(); } NPNScriptableObject& NPNScriptableObject::operator=( NPNScriptableObject& object) { if (this == &object) return *this; if (object_) g_browser->releaseobject(object_); npp_ = object.npp_; object_ = object.object_; if (object_) g_browser->retainobject(object_); return *this; } void NPNScriptableObject::Init(NPP npp, NPObject* object) { Release(); npp_ = npp; object_ = object; } void NPNScriptableObject::Release() { if (object_) { g_browser->releaseobject(object_); object_ = NULL; } npp_ = NULL; } bool NPNScriptableObject::HasProperty(const std::string& name) { if (!IsValid()) return false; NPIdentifier id = g_browser->getstringidentifier(name.c_str()); bool res = g_browser->hasproperty(npp_, object_, id); // How do we release id since it's coming from the browser? the answer is // we never release them. See implementation of NPN_GetStringIdentifier // in npruntime.cpp. return res; } bool NPNScriptableObject::GetProperty(const std::string& name, NPVariant* ret) { if (!IsValid()) return false; NPIdentifier id = g_browser->getstringidentifier(name.c_str()); return g_browser->getproperty(npp_, object_, id, ret); } bool NPNScriptableObject::SetProperty(const std::string& name, const NPVariant& val) { if (!IsValid()) return false; NPIdentifier id = g_browser->getstringidentifier(name.c_str()); return g_browser->setproperty(npp_, object_, id, &val); } NPNScriptableObject NPNScriptableObject::GetObjectProperty( const std::string& name, bool* succeeded) { NPNScriptableObject res; if (succeeded) *succeeded = false; NPVariant var; if (!GetProperty(name, &var)) return res; if (var.type == NPVariantType_Object) { res.Init(npp_, var.value.objectValue); // From now, the object should have reference count as 1. We shall not // release the variant cause it will release the object. if (succeeded) *succeeded = true; } else { g_browser->releasevariantvalue(&var); } return res; } std::wstring NPNScriptableObject::GetStringProperty(const std::string& name, bool* succeeded) { std::wstring res; if (succeeded) *succeeded = false; NPVariant var; if (!GetProperty(name, &var)) return res; if (var.type == NPVariantType_String) { std::string tmp(var.value.stringValue.UTF8Characters, var.value.stringValue.UTF8Length); res = UTF8ToWide(tmp.c_str()); if (succeeded) *succeeded = true; } // We've made a copy of the string. Thus we should release the variant in // any case. g_browser->releasevariantvalue(&var); return res; } bool NPNScriptableObject::SetStringProperty(const std::string& name, const std::wstring& val) { NPVariantWrap var; var.SetString(val); return SetProperty(name, var); } bool NPNScriptableObject::Invoke(const std::string& name, const char* format, ...) { if (!IsValid()) return false; NPIdentifier id = g_browser->getstringidentifier(name.c_str()); std::vector args; va_list argptr; va_start(argptr, format); for (const char* p = format; *p; ++p) { char c = *p; DCHECK(c == '%' && *(p + 1) != 0); if (c != '%' || *(p + 1) == 0) continue; ++p; c = *p; NPVariantWrap var; switch(c) { case 's': { // String wchar_t *s = va_arg(argptr, wchar_t*); var.SetString(s); break; } case 'd': { // String int n = va_arg(argptr, int); var.SetInt(n); break; } default: { DCHECK(false); break; } } args.push_back(var); } NPVariant ret; ret.type = NPVariantType_Void; bool res = false; if (args.size()) res = g_browser->invoke(npp_, object_, id, &args[0], static_cast(args.size()), &ret); else res = g_browser->invoke(npp_, object_, id, NULL, 0, &ret); g_browser->releasevariantvalue(&ret); return res; } NPVariantWrap::NPVariantWrap() { type = NPVariantType_Void; } NPVariantWrap::NPVariantWrap(const NPVariantWrap& v) { type = NPVariantType_Void; Copy(v); } NPVariantWrap::~NPVariantWrap() { Release(); } NPVariantWrap& NPVariantWrap::operator=(const NPVariantWrap& v) { if (this != &v) Copy(v); return *this; } void NPVariantWrap::Copy(const NPVariant& v) { if (this == &v) return; Release(); switch(v.type) { case NPVariantType_Void: break; case NPVariantType_Null: break; case NPVariantType_Bool: value.boolValue = v.value.boolValue; break; case NPVariantType_Int32: value.intValue = v.value.intValue; break; case NPVariantType_Double: value.doubleValue = v.value.doubleValue; break; case NPVariantType_String: SetUTF8String(v.value.stringValue.UTF8Characters, v.value.stringValue.UTF8Length); break; case NPVariantType_Object: g_browser->retainobject(v.value.objectValue); value.objectValue = v.value.objectValue; break; default: DCHECK(false); break; } type = v.type; } void NPVariantWrap::Release() { if (type == NPVariantType_String) { delete[] value.stringValue.UTF8Characters; } else if (type == NPVariantType_Object) { g_browser->releaseobject(value.objectValue); } type = NPVariantType_Void; } void NPVariantWrap::SetBool(bool val) { Release(); value.boolValue = val; type = NPVariantType_Bool; } void NPVariantWrap::SetInt(int val) { Release(); value.intValue = val; type = NPVariantType_Int32; } void NPVariantWrap::SetUTF8String(const NPUTF8* p, unsigned int size) { Release(); value.stringValue.UTF8Characters = new char[size + 1]; memcpy(const_cast(value.stringValue.UTF8Characters), p, size + 1); value.stringValue.UTF8Length = size; type = NPVariantType_String; } void NPVariantWrap::SetString(const std::wstring& val) { std::string s = WideToUTF8(val); SetUTF8String(s.c_str(), static_cast(s.size())); } } // namespace activex_shim