1/*
2 * Copyright (C) 2006, 2007 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 COMPUTER, 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 COMPUTER, 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#include "config.h"
27#include "WebKitDLL.h"
28#include "CFDictionaryPropertyBag.h"
29
30#include "MarshallingHelpers.h"
31#include "WebKit.h"
32
33// CFDictionaryPropertyBag -----------------------------------------------
34
35CFDictionaryPropertyBag::CFDictionaryPropertyBag()
36: m_refCount(0)
37{
38    gClassCount++;
39    gClassNameCount.add("CFDictionaryPropertyBag");
40}
41
42CFDictionaryPropertyBag::~CFDictionaryPropertyBag()
43{
44    gClassCount--;
45    gClassNameCount.remove("CFDictionaryPropertyBag");
46}
47
48COMPtr<CFDictionaryPropertyBag> CFDictionaryPropertyBag::createInstance()
49{
50    return new CFDictionaryPropertyBag;
51}
52
53void CFDictionaryPropertyBag::setDictionary(CFMutableDictionaryRef dictionary)
54{
55    m_dictionary = dictionary;
56}
57
58CFMutableDictionaryRef CFDictionaryPropertyBag::dictionary() const
59{
60    return m_dictionary.get();
61}
62
63// IUnknown -------------------------------------------------------------------
64
65HRESULT STDMETHODCALLTYPE CFDictionaryPropertyBag::QueryInterface(REFIID riid, void** ppvObject)
66{
67    *ppvObject = 0;
68    if (IsEqualGUID(riid, IID_IUnknown))
69        *ppvObject = static_cast<IPropertyBag*>(this);
70    else if (IsEqualGUID(riid, IID_IPropertyBag))
71        *ppvObject = static_cast<IPropertyBag*>(this);
72    else if (IsEqualGUID(riid, __uuidof(this)))
73        *ppvObject = this;
74    else
75        return E_NOINTERFACE;
76
77    AddRef();
78    return S_OK;
79}
80
81ULONG STDMETHODCALLTYPE CFDictionaryPropertyBag::AddRef(void)
82{
83    return ++m_refCount;
84}
85
86ULONG STDMETHODCALLTYPE CFDictionaryPropertyBag::Release(void)
87{
88    ULONG newRef = --m_refCount;
89    if (!newRef)
90        delete(this);
91
92    return newRef;
93}
94
95// IPropertyBag ------------------------------------------------------------
96
97static bool ConvertCFTypeToVariant(VARIANT* pVar, void* cfObj)
98{
99    if (!cfObj) {
100        V_VT(pVar) = VT_NULL;
101        return true;
102    }
103    else {
104        // if caller expects a string, retrieve BSTR from CFStringRef
105        if (V_VT(pVar) == VT_BSTR) {
106            V_BSTR(pVar) = MarshallingHelpers::CFStringRefToBSTR((CFStringRef) cfObj);
107            return true;
108        } else if (V_VT(pVar) == VT_I4) {
109            V_I4(pVar) = MarshallingHelpers::CFNumberRefToInt((CFNumberRef) cfObj);
110            return true;
111        } else if (!!(V_VT(pVar)&VT_ARRAY)) {
112            if ((V_VT(pVar)&~VT_ARRAY) == VT_BSTR) {
113                V_ARRAY(pVar) = MarshallingHelpers::stringArrayToSafeArray((CFArrayRef) cfObj);
114                return true;
115            } else if ((V_VT(pVar)&~VT_ARRAY) == VT_I4) {
116                V_ARRAY(pVar) = MarshallingHelpers::intArrayToSafeArray((CFArrayRef) cfObj);
117                return true;
118            } else if ((V_VT(pVar)&~VT_ARRAY) == VT_UNKNOWN) {
119                V_ARRAY(pVar) = MarshallingHelpers::iunknownArrayToSafeArray((CFArrayRef) cfObj);
120                return true;
121            }
122        }
123    }
124    return false;
125}
126
127static bool ConvertVariantToCFType(VARIANT* pVar, void** cfObj)
128{
129    if (V_VT(pVar) == VT_NULL) {
130        *cfObj = 0;
131        return true;
132    }
133    else {
134        // if caller expects a string, retrieve BSTR from CFStringRef
135        if (V_VT(pVar) == VT_BSTR) {
136            *cfObj = (void*) MarshallingHelpers::BSTRToCFStringRef(V_BSTR(pVar));
137            return true;
138        } else if (V_VT(pVar) == VT_I4) {
139            *cfObj = (void*) MarshallingHelpers::intToCFNumberRef(V_I4(pVar));
140            return true;
141        } else if (!!(V_VT(pVar)&VT_ARRAY)) {
142            if ((V_VT(pVar)&~VT_ARRAY) == VT_BSTR) {
143                *cfObj = (void*) MarshallingHelpers::safeArrayToStringArray(V_ARRAY(pVar));
144                return true;
145            } else if ((V_VT(pVar)&~VT_ARRAY) == VT_I4) {
146                *cfObj = (void*) MarshallingHelpers::safeArrayToIntArray(V_ARRAY(pVar));
147                return true;
148            } else if ((V_VT(pVar)&~VT_ARRAY) == VT_UNKNOWN) {
149                *cfObj = (void*) MarshallingHelpers::safeArrayToIUnknownArray(V_ARRAY(pVar));
150                return true;
151            }
152        }
153    }
154    return false;
155}
156
157HRESULT STDMETHODCALLTYPE CFDictionaryPropertyBag::Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog * /*pErrorLog*/)
158{
159    if (!pszPropName)
160        return E_POINTER;
161    if (m_dictionary) {
162        void* value;
163        CFStringRef key = MarshallingHelpers::LPCOLESTRToCFStringRef(pszPropName);
164        HRESULT hr = E_FAIL;
165        if (CFDictionaryGetValueIfPresent(m_dictionary.get(), key, (const void**) &value)) {
166            if (ConvertCFTypeToVariant(pVar, value))
167                hr = S_OK;
168        } else
169            hr = E_INVALIDARG;
170        CFRelease(key);
171        return hr;
172    }
173    return E_FAIL;
174}
175
176HRESULT STDMETHODCALLTYPE CFDictionaryPropertyBag::Write(LPCOLESTR pszPropName, VARIANT* pVar)
177{
178    if (!pszPropName || !pVar)
179        return E_POINTER;
180    if (!m_dictionary) {
181        m_dictionary = adoptCF(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
182    }
183    void* cfObj;
184    if (ConvertVariantToCFType(pVar, &cfObj)) {
185        CFStringRef key = MarshallingHelpers::LPCOLESTRToCFStringRef(pszPropName);
186        CFDictionaryAddValue(m_dictionary.get(), key, cfObj);
187        // CFDictionaryAddValue should automatically retain the CF objects passed in, so release them here
188        CFRelease(key);
189        CFRelease(cfObj);
190        return S_OK;
191    }
192    return E_FAIL;
193}