Reviewed by Darin.
[WebKit-https.git] / WebKit / win / COMEnumVariant.h
1 /*\r
2  * Copyright (C) 2007 Apple Inc. All rights reserved.\r
3  *\r
4  * Redistribution and use in source and binary forms, with or without\r
5  * modification, are permitted provided that the following conditions\r
6  * are met:\r
7  *\r
8  * 1.  Redistributions of source code must retain the above copyright\r
9  *     notice, this list of conditions and the following disclaimer.\r
10  * 2.  Redistributions in binary form must reproduce the above copyright\r
11  *     notice, this list of conditions and the following disclaimer in the\r
12  *     documentation and/or other materials provided with the distribution.\r
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of\r
14  *     its contributors may be used to endorse or promote products derived\r
15  *     from this software without specific prior written permission.\r
16  *\r
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY\r
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY\r
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  */\r
28 \r
29 #ifndef COMEnumVariant_h\r
30 #define COMEnumVariant_h\r
31 \r
32 #define NOMINMAX\r
33 #include <unknwn.h>\r
34 \r
35 #include <WebCore/BString.h>\r
36 #include <WTF/Assertions.h>\r
37 #include <WTF/Noncopyable.h>\r
38 \r
39 namespace WebCore {\r
40     class String;\r
41 }\r
42 \r
43 template<typename T> struct COMVariantSetter {};\r
44 \r
45 template<> struct COMVariantSetter<WebCore::String>\r
46 {\r
47     static void setVariant(VARIANT* variant, const WebCore::String& value)\r
48     {\r
49         ASSERT(V_VT(variant) == VT_EMPTY);\r
50 \r
51         V_VT(variant) = VT_BSTR;\r
52         V_BSTR(variant) = WebCore::BString(value).release();\r
53     }\r
54 };\r
55 \r
56 template<typename COMType, typename UnderlyingType>\r
57 struct COMIUnknownVariantSetter\r
58 {\r
59     static void setVariant(VARIANT* variant, const UnderlyingType& value)\r
60     {\r
61         ASSERT(V_VT(variant) == VT_EMPTY);\r
62 \r
63         V_VT(variant) = VT_UNKNOWN;\r
64         V_UNKNOWN(variant) = COMType::createInstance(value);\r
65     }\r
66 };\r
67 \r
68 template<typename ContainerType>\r
69 class COMEnumVariant : public IEnumVARIANT, Noncopyable {\r
70 public:\r
71     static COMEnumVariant* adopt(ContainerType&);\r
72     static COMEnumVariant* createInstance(const ContainerType&);\r
73 \r
74     // IUnknown\r
75     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);\r
76     virtual ULONG STDMETHODCALLTYPE AddRef();\r
77     virtual ULONG STDMETHODCALLTYPE Release();\r
78 \r
79     // IEnumVARIANT\r
80     virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, VARIANT* rgVar, ULONG* pCeltFetched);\r
81     virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt);\r
82     virtual HRESULT STDMETHODCALLTYPE Reset();\r
83     virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT** ppEnum);\r
84 \r
85 private:\r
86     COMEnumVariant()\r
87         : m_refCount(0)\r
88     {\r
89     }\r
90 \r
91     COMEnumVariant(const ContainerType& container)\r
92         : m_refCount(0)\r
93         , m_container(container)       \r
94         , m_currentPos(m_container.begin())\r
95     {\r
96     }\r
97 \r
98     ~COMEnumVariant() {}\r
99 \r
100     ULONG m_refCount;\r
101 \r
102     ContainerType m_container;\r
103     typename ContainerType::const_iterator m_currentPos;\r
104 };\r
105 \r
106 // COMEnumVariant ------------------------------------------------------------------\r
107 template<typename ContainerType>\r
108 COMEnumVariant<typename ContainerType>* COMEnumVariant<ContainerType>::adopt(ContainerType& container) \r
109 {\r
110     COMEnumVariant* instance = new COMEnumVariant;\r
111     instance->m_container.swap(container);\r
112     instance->m_currentPos = instance->m_container.begin();\r
113     instance->AddRef();\r
114     return instance;\r
115 }\r
116 \r
117 template<typename ContainerType>\r
118 COMEnumVariant<typename ContainerType>* COMEnumVariant<ContainerType>::createInstance(const ContainerType& container)\r
119 {\r
120     COMEnumVariant* instance = new COMEnumVariant(container);\r
121     instance->AddRef();\r
122     return instance;\r
123 }\r
124 \r
125 // IUnknown ------------------------------------------------------------------------\r
126 template<typename ContainerType>\r
127 HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::QueryInterface(REFIID riid, void** ppvObject)\r
128 {\r
129     *ppvObject = 0;\r
130     if (IsEqualGUID(riid, IID_IUnknown))\r
131         *ppvObject = static_cast<COMEnumVariant*>(this);\r
132     else if (IsEqualGUID(riid, IID_IEnumVARIANT))\r
133         *ppvObject = static_cast<COMEnumVariant*>(this);\r
134     else\r
135         return E_NOINTERFACE;\r
136 \r
137     AddRef();\r
138     return S_OK;\r
139 }\r
140 \r
141 template<typename ContainerType>\r
142 ULONG STDMETHODCALLTYPE COMEnumVariant<ContainerType>::AddRef()\r
143 {\r
144     return ++m_refCount;\r
145 }\r
146 \r
147 template<typename ContainerType>\r
148 ULONG STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Release()\r
149 {\r
150     ULONG newRef = --m_refCount;\r
151     if (!newRef)\r
152         delete this;\r
153 \r
154     return newRef;\r
155 }\r
156 \r
157 // IEnumVARIANT --------------------------------------------------------------------\r
158 template<typename ContainerType>\r
159 HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Next(ULONG celt, VARIANT* rgVar, ULONG* pCeltFetched)\r
160 {\r
161     if (pCeltFetched)\r
162         *pCeltFetched = 0;\r
163     if (!rgVar)\r
164         return E_POINTER;\r
165     for (unsigned i = 0 ; i < celt; i++)\r
166         VariantInit(&rgVar[i]);\r
167 \r
168     for (unsigned i = 0; i < celt; i++) {\r
169         if (m_currentPos == m_container.end())\r
170             return S_FALSE;\r
171 \r
172         COMVariantSetter<ContainerType::ValueType>::setVariant(&rgVar[i], *m_currentPos);\r
173         ++m_currentPos;\r
174     }\r
175 \r
176     return S_OK;\r
177 }\r
178 \r
179 template<typename ContainerType>\r
180 HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Skip(ULONG celt) \r
181 {\r
182     for (unsigned i = 0; i < celt; i++) {\r
183         if (m_currentPos == m_container.end())\r
184             return S_FALSE;\r
185 \r
186         ++m_currentPos;\r
187     }\r
188     return S_OK;\r
189 }\r
190     \r
191 template<typename ContainerType>\r
192 HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Reset() \r
193 {\r
194     m_currentPos = m_container.begin();\r
195     return S_OK;\r
196 }\r
197     \r
198 template<typename ContainerType>\r
199 HRESULT STDMETHODCALLTYPE COMEnumVariant<ContainerType>::Clone(IEnumVARIANT** ppEnum)\r
200 {\r
201     if (!ppEnum)\r
202         return E_POINTER;\r
203 \r
204     *ppEnum = 0;\r
205     return E_NOTIMPL;\r
206 }\r
207 \r
208 #endif\r