b0d21f45eb51cf0f586844a01fbaecd172affc6a
[WebKit-https.git] / Source / WebKitLegacy / win / COMPropertyBag.h
1 /*
2  * Copyright (C) 2008, 2015 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #ifndef COMPropertyBag_h
27 #define COMPropertyBag_h
28
29 #include <ocidl.h>
30 #include <unknwn.h>
31
32 #include <wtf/Noncopyable.h>
33 #include <wtf/HashMap.h>
34
35 #include "COMVariantSetter.h"
36
37 template<typename ValueType, typename KeyType = typename WTF::String, typename HashType = typename WTF::StringHash>
38 class COMPropertyBag final : public IPropertyBag, public IPropertyBag2 {
39     WTF_MAKE_NONCOPYABLE(COMPropertyBag);
40 public:
41     typedef HashMap<KeyType, ValueType, HashType> HashMapType;
42
43     static COMPropertyBag* createInstance(const HashMapType&);
44     static COMPropertyBag* adopt(HashMapType&);
45
46     // IUnknown
47     virtual HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject);
48     virtual ULONG STDMETHODCALLTYPE AddRef();
49     virtual ULONG STDMETHODCALLTYPE Release();
50
51     // IPropertyBag
52     virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT*, IErrorLog*);
53     virtual HRESULT STDMETHODCALLTYPE Write(_In_ LPCOLESTR pszPropName, _In_ VARIANT*);
54
55     // IPropertyBag2
56     virtual HRESULT STDMETHODCALLTYPE Read(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2*, _In_opt_ IErrorLog*, __out_ecount_full(cProperties) VARIANT*, __inout_ecount_full_opt(cProperties) HRESULT*);
57     virtual HRESULT STDMETHODCALLTYPE Write(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2*, __inout_ecount_full(cProperties) VARIANT*);
58     virtual HRESULT STDMETHODCALLTYPE CountProperties(_Out_ ULONG* pcProperties);
59     virtual HRESULT STDMETHODCALLTYPE GetPropertyInfo(ULONG iProperty, ULONG cProperties, __out_ecount_full(cProperties) PROPBAG2*, _Out_ ULONG* pcProperties);
60     virtual HRESULT STDMETHODCALLTYPE LoadObject(_In_ LPCOLESTR pstrName, DWORD dwHint, _In_opt_ IUnknown*, _In_opt_ IErrorLog*);
61
62 private:
63     COMPropertyBag()
64     {
65     }
66
67     COMPropertyBag(const HashMapType& hashMap)
68         : m_hashMap(hashMap)
69     {
70     }
71
72     ~COMPropertyBag() {}
73
74     ULONG m_refCount { 0 };
75     HashMapType m_hashMap;
76 };
77
78 // COMPropertyBag ------------------------------------------------------------------
79 template<typename ValueType, typename KeyType, typename HashType>
80 COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::createInstance(const HashMapType& hashMap)
81 {
82     COMPropertyBag* instance = new COMPropertyBag(hashMap);
83     instance->AddRef();
84     return instance;
85 }
86
87 template<typename ValueType, typename KeyType, typename HashType>
88 COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::adopt(HashMapType& hashMap)
89 {
90     COMPropertyBag* instance = new COMPropertyBag;
91     instance->m_hashMap.swap(hashMap);
92     instance->AddRef();
93     return instance;
94 }
95
96 // IUnknown ------------------------------------------------------------------------
97 template<typename ValueType, typename KeyType, typename HashType>
98 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject)
99 {
100     if (!ppvObject)
101         return E_POINTER;
102     *ppvObject = nullptr;
103     if (IsEqualGUID(riid, IID_IUnknown))
104         *ppvObject = static_cast<IPropertyBag*>(this);
105     else if (IsEqualGUID(riid, IID_IPropertyBag))
106         *ppvObject = static_cast<IPropertyBag*>(this);
107     else if (IsEqualGUID(riid, IID_IPropertyBag2))
108         *ppvObject = static_cast<IPropertyBag2*>(this);
109     else
110         return E_NOINTERFACE;
111
112     AddRef();
113     return S_OK;
114 }
115
116 template<typename ValueType, typename KeyType, typename HashType>
117 ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::AddRef()
118 {
119     return ++m_refCount;
120 }
121
122 template<typename ValueType, typename KeyType, typename HashType>
123 ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Release()
124 {
125     ULONG newRef = --m_refCount;
126     if (!newRef)
127         delete this;
128
129     return newRef;
130 }
131
132 // IPropertyBag --------------------------------------------------------------------
133
134 template<typename ValueType, typename KeyType, typename HashType>
135 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog)
136 {
137     if (!pszPropName)
138         return E_POINTER;
139
140     HashMapType::const_iterator it = m_hashMap.find(String(pszPropName));
141     HashMapType::const_iterator end = m_hashMap.end();
142     if (it == end)
143         return E_INVALIDARG;
144
145     VARTYPE requestedType = V_VT(pVar);
146     V_VT(pVar) = VT_EMPTY;
147     COMVariantSetter<ValueType>::setVariant(pVar, it->value);
148
149     if (requestedType != COMVariantSetter<ValueType>::variantType(it->value) && requestedType != VT_EMPTY)
150         return ::VariantChangeType(pVar, pVar, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL, requestedType);
151
152     return S_OK;
153 }
154
155 template<typename ValueType, typename KeyType, typename HashType>
156 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(_In_ LPCOLESTR pszPropName, _In_ VARIANT* pVar)
157 {
158     return E_FAIL;
159 }
160
161 template<typename ValueType, typename KeyType, typename HashType>
162 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2* pPropBag, _In_opt_ IErrorLog* pErrorLog, __out_ecount_full(cProperties) VARIANT* pvarValue, __inout_ecount_full_opt(cProperties) HRESULT* phrError)
163 {
164     if (!pPropBag || !pvarValue || !phrError)
165         return E_POINTER;
166
167     HRESULT hr = S_OK;
168
169     for (ULONG i = 0; i < cProperties; ++i) {
170         ::VariantInit(&pvarValue[i]);
171         pvarValue[i].vt = pPropBag[i].vt;
172         phrError[i] = Read(pPropBag[i].pstrName, &pvarValue[i], pErrorLog);
173         if (FAILED(phrError[i]))
174             hr = E_FAIL;
175     }
176
177     return hr;
178 }
179
180 template<typename ValueType, typename KeyType, typename HashType>
181 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2*, __inout_ecount_full(cProperties) VARIANT*)
182 {
183     return E_NOTIMPL;
184 }
185
186 template<typename ValueType, typename KeyType, typename HashType>
187 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::CountProperties(_Out_ ULONG* pcProperties)
188 {
189     if (!pcProperties)
190         return E_POINTER;
191
192     *pcProperties = m_hashMap.size();
193     return S_OK;
194 }
195
196 template<typename ValueType, typename KeyType, typename HashType>
197 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::GetPropertyInfo(ULONG iProperty, ULONG cProperties, __out_ecount_full(cProperties) PROPBAG2* pPropBag, _Out_ ULONG* pcProperties)
198 {
199     if (!pPropBag || !pcProperties)
200         return E_POINTER;
201
202     *pcProperties = 0;
203
204     if (m_hashMap.size() <= iProperty)
205         return E_INVALIDARG;
206
207     *pcProperties = 0;
208     typedef HashMapType::const_iterator Iterator;
209     Iterator current = m_hashMap.begin();
210     Iterator end = m_hashMap.end();
211     for (ULONG i = 0; i < iProperty; ++i, ++current)
212         ;
213     for (ULONG j = 0; j < cProperties && current != end; ++j, ++current) {
214         // FIXME: the following fields aren't filled in
215         //pPropBag[j].cfType;   // (CLIPFORMAT) Clipboard format or MIME type of the property.
216         //pPropBag[j].clsid;    // (CLSID) CLSID of the object. This member is valid only if dwType is PROPBAG2_TYPE_OBJECT.
217
218         pPropBag[j].dwType = PROPBAG2_TYPE_DATA;
219         pPropBag[j].vt = COMVariantSetter<ValueType>::variantType(current->value);
220         pPropBag[j].dwHint = iProperty + j;
221         pPropBag[j].pstrName = (LPOLESTR)CoTaskMemAlloc(sizeof(wchar_t)*(current->key.length()+1));
222         if (!pPropBag[j].pstrName)
223             return E_OUTOFMEMORY;
224         wcscpy_s(pPropBag[j].pstrName, current->key.length()+1, static_cast<String>(current->key).charactersWithNullTermination().data());
225         ++*pcProperties;
226     }
227     return S_OK;
228 }
229
230 template<typename ValueType, typename KeyType, typename HashType>
231 HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::LoadObject(_In_ LPCOLESTR pstrName, DWORD dwHint, _In_opt_ IUnknown*, _In_opt_ IErrorLog*)
232 {
233     return E_NOTIMPL;
234 }
235
236 #endif // COMPropertyBag_h