1/*
2 * Copyright (C) 2011 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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef JSDictionary_h
27#define JSDictionary_h
28
29#include "MessagePort.h"
30#include <heap/Strong.h>
31#include <heap/StrongInlines.h>
32#include <interpreter/CallFrame.h>
33#include <runtime/Operations.h>
34#include <wtf/Forward.h>
35
36namespace WebCore {
37
38class ArrayValue;
39class CSSFontFaceRule;
40class Dictionary;
41class DOMError;
42class DOMWindow;
43class EventTarget;
44class MediaKeyError;
45class MediaStream;
46class Node;
47class ScriptValue;
48class SerializedScriptValue;
49class Storage;
50class TrackBase;
51class VoidCallback;
52
53#if ENABLE(SCRIPTED_SPEECH)
54class SpeechRecognitionResultList;
55#endif
56
57class JSDictionary {
58public:
59    JSDictionary(JSC::ExecState* exec, JSC::JSObject* initializerObject)
60        : m_exec(exec)
61    {
62        if (exec && initializerObject)
63            m_initializerObject = JSC::Strong<JSC::JSObject>(exec->vm(), initializerObject);
64    }
65
66    // Returns false if any exceptions were thrown, regardless of whether the property was found.
67    template <typename Result>
68    bool tryGetProperty(const char* propertyName, Result&) const;
69    template <typename T, typename Result>
70    bool tryGetProperty(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const;
71
72    // Returns true if the property was found in the dictionary, and the value could be converted to the desired type.
73    template <typename Result>
74    bool get(const char* propertyName, Result&) const;
75    bool getWithUndefinedOrNullCheck(const String& propertyName, String& value) const;
76
77    JSC::ExecState* execState() const { return m_exec; }
78    JSC::JSObject* initializerObject() const { return m_initializerObject.get(); }
79    bool isValid() const { return m_exec && m_initializerObject; }
80
81private:
82    template <typename Result>
83    struct IdentitySetter {
84        static void identitySetter(Result* context, const Result& result)
85        {
86            *context = result;
87        }
88    };
89
90    enum GetPropertyResult {
91        ExceptionThrown,
92        NoPropertyFound,
93        PropertyFound
94    };
95
96    template <typename T, typename Result>
97    GetPropertyResult tryGetPropertyAndResult(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const;
98    GetPropertyResult tryGetProperty(const char* propertyName, JSC::JSValue&) const;
99
100    static void convertValue(JSC::ExecState*, JSC::JSValue, bool& result);
101    static void convertValue(JSC::ExecState*, JSC::JSValue, int& result);
102    static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned& result);
103    static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned short& result);
104    static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned long& result);
105    static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned long long& result);
106    static void convertValue(JSC::ExecState*, JSC::JSValue, double& result);
107    static void convertValue(JSC::ExecState*, JSC::JSValue, Dictionary& result);
108    static void convertValue(JSC::ExecState*, JSC::JSValue, String& result);
109    static void convertValue(JSC::ExecState*, JSC::JSValue, ScriptValue& result);
110    static void convertValue(JSC::ExecState*, JSC::JSValue, Vector<String>& result);
111    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<SerializedScriptValue>& result);
112    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<DOMWindow>& result);
113    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<EventTarget>& result);
114    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<Node>& result);
115    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<Storage>& result);
116    static void convertValue(JSC::ExecState*, JSC::JSValue, MessagePortArray& result);
117#if ENABLE(VIDEO_TRACK)
118    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<TrackBase>& result);
119#endif
120    static void convertValue(JSC::ExecState*, JSC::JSValue, HashSet<AtomicString>& result);
121    static void convertValue(JSC::ExecState*, JSC::JSValue, ArrayValue& result);
122    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<Uint8Array>& result);
123#if ENABLE(ENCRYPTED_MEDIA)
124    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<MediaKeyError>& result);
125#endif
126#if ENABLE(MEDIA_STREAM)
127    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<MediaStream>& result);
128#endif
129#if ENABLE(FONT_LOAD_EVENTS)
130    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<CSSFontFaceRule>& result);
131    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<DOMError>& result);
132    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<VoidCallback>& result);
133#endif
134#if ENABLE(SCRIPTED_SPEECH)
135    static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<SpeechRecognitionResultList>&);
136#endif
137
138    JSC::ExecState* m_exec;
139    JSC::Strong<JSC::JSObject> m_initializerObject;
140};
141
142template <typename T, typename Result>
143bool JSDictionary::tryGetProperty(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const
144{
145    return tryGetPropertyAndResult(propertyName, context, setter) != ExceptionThrown;
146}
147
148template <typename Result>
149bool JSDictionary::tryGetProperty(const char* propertyName, Result& finalResult) const
150{
151    return tryGetPropertyAndResult(propertyName, &finalResult, IdentitySetter<Result>::identitySetter) != ExceptionThrown;
152}
153
154template <typename Result>
155bool JSDictionary::get(const char* propertyName, Result& finalResult) const
156{
157    return tryGetPropertyAndResult(propertyName, &finalResult, IdentitySetter<Result>::identitySetter) == PropertyFound;
158}
159
160template <typename T, typename Result>
161JSDictionary::GetPropertyResult JSDictionary::tryGetPropertyAndResult(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const
162{
163    JSC::JSValue value;
164    GetPropertyResult getPropertyResult = tryGetProperty(propertyName, value);
165    switch (getPropertyResult) {
166    case ExceptionThrown:
167        return getPropertyResult;
168    case PropertyFound: {
169        Result result;
170        convertValue(m_exec, value, result);
171
172        if (m_exec->hadException())
173            return ExceptionThrown;
174
175        setter(context, result);
176        break;
177    }
178    case NoPropertyFound:
179        break;
180    }
181
182    return getPropertyResult;
183}
184
185} // namespace WebCore
186
187#endif // JSDictionary_h
188