/* * Copyright (C) 2008 Apple 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: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. */ #ifndef COMPropertyBag_h #define COMPropertyBag_h #define NOMINMAX #include <unknwn.h> #include <wtf/Noncopyable.h> #include <wtf/HashMap.h> #include "COMVariantSetter.h" template<typename ValueType, typename KeyType = typename WebCore::String, typename HashType = typename WebCore::StringHash> class COMPropertyBag : public IPropertyBag, public IPropertyBag2, Noncopyable { public: typedef HashMap<KeyType, ValueType, HashType> HashMapType; static COMPropertyBag* createInstance(const HashMapType&); static COMPropertyBag* adopt(HashMapType&); // IUnknown virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); virtual ULONG STDMETHODCALLTYPE AddRef(); virtual ULONG STDMETHODCALLTYPE Release(); // IPropertyBag virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT*, IErrorLog*); virtual HRESULT STDMETHODCALLTYPE Write(LPCOLESTR pszPropName, VARIANT*); // IPropertyBag2 virtual HRESULT STDMETHODCALLTYPE Read(ULONG cProperties, PROPBAG2*, IErrorLog*, VARIANT* pvarValue, HRESULT* phrError); virtual HRESULT STDMETHODCALLTYPE Write(ULONG cProperties, PROPBAG2*, VARIANT*); virtual HRESULT STDMETHODCALLTYPE CountProperties(ULONG* pcProperties); virtual HRESULT STDMETHODCALLTYPE GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); virtual HRESULT STDMETHODCALLTYPE LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown*, IErrorLog*); private: COMPropertyBag() : m_refCount(0) { } COMPropertyBag(const HashMapType& hashMap) : m_refCount(0) , m_hashMap(hashMap) { } ~COMPropertyBag() {} ULONG m_refCount; HashMapType m_hashMap; }; // COMPropertyBag ------------------------------------------------------------------ template<typename ValueType, typename KeyType, typename HashType> COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::createInstance(const HashMapType& hashMap) { COMPropertyBag* instance = new COMPropertyBag(hashMap); instance->AddRef(); return instance; } template<typename ValueType, typename KeyType, typename HashType> COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::adopt(HashMapType& hashMap) { COMPropertyBag* instance = new COMPropertyBag; instance->m_hashMap.swap(hashMap); instance->AddRef(); return instance; } // IUnknown ------------------------------------------------------------------------ template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::QueryInterface(REFIID riid, void** ppvObject) { *ppvObject = 0; if (IsEqualGUID(riid, IID_IUnknown)) *ppvObject = static_cast<IPropertyBag*>(this); else if (IsEqualGUID(riid, IID_IPropertyBag)) *ppvObject = static_cast<IPropertyBag*>(this); else if (IsEqualGUID(riid, IID_IPropertyBag2)) *ppvObject = static_cast<IPropertyBag2*>(this); else return E_NOINTERFACE; AddRef(); return S_OK; } template<typename ValueType, typename KeyType, typename HashType> ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::AddRef() { return ++m_refCount; } template<typename ValueType, typename KeyType, typename HashType> ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Release() { ULONG newRef = --m_refCount; if (!newRef) delete this; return newRef; } // IPropertyBag -------------------------------------------------------------------- template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) { if (!pszPropName) return E_POINTER; HashMapType::const_iterator it = m_hashMap.find(String(pszPropName)); HashMapType::const_iterator end = m_hashMap.end(); if (it == end) return E_INVALIDARG; VARTYPE requestedType = V_VT(pVar); V_VT(pVar) = VT_EMPTY; COMVariantSetter<ValueType>::setVariant(pVar, it->second); if (requestedType != COMVariantSetter<ValueType>::variantType(it->second) && requestedType != VT_EMPTY) return ::VariantChangeType(pVar, pVar, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL, requestedType); return S_OK; } template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(LPCOLESTR pszPropName, VARIANT* pVar) { return E_FAIL; } template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrorLog, VARIANT* pvarValue, HRESULT* phrError) { if (!pPropBag || !pvarValue || !phrError) return E_POINTER; HRESULT hr = S_OK; for (ULONG i = 0; i < cProperties; ++i) { VariantInit(&pvarValue[i]); pvarValue[i].vt = pPropBag[i].vt; phrError[i] = Read(pPropBag[i].pstrName, &pvarValue[i], pErrorLog); if (FAILED(phrError[i])) hr = E_FAIL; } return hr; } template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(ULONG cProperties, PROPBAG2*, VARIANT*) { return E_NOTIMPL; } template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::CountProperties(ULONG* pcProperties) { if (!pcProperties) return E_POINTER; *pcProperties = m_hashMap.size(); return S_OK; } template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) { if (!pPropBag || !pcProperties) return E_POINTER; if (m_hashMap.size() <= iProperty) return E_INVALIDARG; *pcProperties = 0; typedef HashMapType::const_iterator Iterator; Iterator current = m_hashMap.begin(); Iterator end = m_hashMap.end(); for (ULONG i = 0; i < iProperty; ++i, ++current) ; for (ULONG j = 0; j < cProperties && current != end; ++j, ++current) { // FIXME: the following fields aren't filled in //pPropBag[j].cfType; // (CLIPFORMAT) Clipboard format or MIME type of the property. //pPropBag[j].clsid; // (CLSID) CLSID of the object. This member is valid only if dwType is PROPBAG2_TYPE_OBJECT. pPropBag[j].dwType = PROPBAG2_TYPE_DATA; pPropBag[j].vt = COMVariantSetter<ValueType>::variantType(current->second); pPropBag[j].dwHint = iProperty + j; pPropBag[j].pstrName = (LPOLESTR)CoTaskMemAlloc(sizeof(wchar_t)*(current->first.length()+1)); if (!pPropBag[j].pstrName) return E_OUTOFMEMORY; wcscpy_s(pPropBag[j].pstrName, current->first.length()+1, static_cast<String>(current->first).charactersWithNullTermination()); ++*pcProperties; } return S_OK; } template<typename ValueType, typename KeyType, typename HashType> HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown*, IErrorLog*) { return E_NOTIMPL; } #endif // COMPropertyBag_h