1/*
2 * Copyright (C) 2010 Google 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef Dictionary_h
27#define Dictionary_h
28
29#include "bindings/v8/ExceptionMessages.h"
30#include "bindings/v8/ExceptionState.h"
31#include "bindings/v8/ScriptValue.h"
32#include "bindings/v8/V8Binding.h"
33#include "bindings/v8/V8BindingMacros.h"
34#include "core/events/EventListener.h"
35#include "core/dom/MessagePort.h"
36#include <v8.h>
37#include "wtf/HashMap.h"
38#include "wtf/HashSet.h"
39#include "wtf/Vector.h"
40#include "wtf/text/AtomicString.h"
41#include "wtf/text/WTFString.h"
42
43namespace WebCore {
44
45class ArrayValue;
46class DOMError;
47class DOMWindow;
48class IDBKeyRange;
49class MIDIPort;
50class MediaKeyError;
51class Notification;
52class SpeechRecognitionError;
53class SpeechRecognitionResult;
54class SpeechRecognitionResultList;
55class Storage;
56class TrackBase;
57class VoidCallback;
58
59class Dictionary {
60public:
61    Dictionary();
62    Dictionary(const v8::Handle<v8::Value>& options, v8::Isolate*);
63    ~Dictionary();
64
65    Dictionary& operator=(const Dictionary&);
66
67    bool isObject() const;
68    bool isUndefinedOrNull() const;
69
70    bool get(const String&, bool&) const;
71    bool get(const String&, int32_t&) const;
72    bool get(const String&, double&, bool& hasValue) const;
73    bool get(const String&, double&) const;
74    bool get(const String&, String&) const;
75    bool get(const String&, ScriptValue&) const;
76    bool get(const String&, short&) const;
77    bool get(const String&, unsigned short&) const;
78    bool get(const String&, unsigned&) const;
79    bool get(const String&, unsigned long&) const;
80    bool get(const String&, unsigned long long&) const;
81    bool get(const String&, RefPtr<DOMWindow>&) const;
82    bool get(const String&, RefPtr<Storage>&) const;
83    bool get(const String&, MessagePortArray&) const;
84    bool get(const String&, RefPtr<Uint8Array>&) const;
85    bool get(const String&, RefPtr<ArrayBufferView>&) const;
86    bool get(const String&, RefPtr<MIDIPort>&) const;
87    bool get(const String&, RefPtr<MediaKeyError>&) const;
88    bool get(const String&, RefPtr<TrackBase>&) const;
89    bool get(const String&, RefPtr<SpeechRecognitionError>&) const;
90    bool get(const String&, RefPtr<SpeechRecognitionResult>&) const;
91    bool get(const String&, RefPtr<SpeechRecognitionResultList>&) const;
92    bool get(const String&, RefPtr<MediaStream>&) const;
93    bool get(const String&, RefPtr<EventTarget>&) const;
94    bool get(const String&, HashSet<AtomicString>&) const;
95    bool get(const String&, Dictionary&) const;
96    bool get(const String&, Vector<String>&) const;
97    bool get(const String&, ArrayValue&) const;
98    bool get(const String&, RefPtr<DOMError>&) const;
99    bool get(const String&, OwnPtr<VoidCallback>&) const;
100    bool get(const String&, v8::Local<v8::Value>&) const;
101
102    class ConversionContext {
103    public:
104        ConversionContext(const String& interfaceName, const String& methodName, ExceptionState& exceptionState)
105            : m_interfaceName(interfaceName)
106            , m_methodName(methodName)
107            , m_exceptionState(exceptionState)
108            , m_dirty(true)
109        {
110            resetPerPropertyContext();
111        }
112
113        const String& interfaceName() const { return m_interfaceName; }
114        const String& methodName() const { return m_methodName; }
115        bool forConstructor() const { return m_methodName.isEmpty(); }
116        ExceptionState& exceptionState() const { return m_exceptionState; }
117
118        bool isNullable() const { return m_isNullable; }
119        String typeName() const { return m_propertyTypeName; }
120
121        ConversionContext& setConversionType(const String&, bool);
122
123        void throwTypeError(const String& detail);
124
125        void resetPerPropertyContext();
126
127    private:
128        const String m_interfaceName;
129        const String m_methodName;
130        ExceptionState& m_exceptionState;
131        bool m_dirty;
132
133        bool m_isNullable;
134        String m_propertyTypeName;
135    };
136
137    class ConversionContextScope {
138    public:
139        ConversionContextScope(ConversionContext& context)
140            : m_context(context) { }
141        ~ConversionContextScope()
142        {
143            m_context.resetPerPropertyContext();
144        }
145    private:
146        ConversionContext& m_context;
147    };
148
149    bool convert(ConversionContext&, const String&, bool&) const;
150    bool convert(ConversionContext&, const String&, double&) const;
151    bool convert(ConversionContext&, const String&, String&) const;
152    bool convert(ConversionContext&, const String&, ScriptValue&) const;
153
154    template<typename IntegralType>
155    bool convert(ConversionContext &, const String&, IntegralType&) const;
156    bool convert(ConversionContext &, const String&, MessagePortArray&) const;
157    bool convert(ConversionContext &, const String&, HashSet<AtomicString>&) const;
158    bool convert(ConversionContext &, const String&, Dictionary&) const;
159    bool convert(ConversionContext &, const String&, Vector<String>&) const;
160    bool convert(ConversionContext &, const String&, ArrayValue&) const;
161    template<typename T>
162    bool convert(ConversionContext &, const String&, RefPtr<T>&) const;
163
164    bool getOwnPropertiesAsStringHashMap(HashMap<String, String>&) const;
165    bool getOwnPropertyNames(Vector<String>&) const;
166
167    bool getWithUndefinedOrNullCheck(const String&, String&) const;
168
169    bool hasProperty(const String&) const;
170
171    // Only allow inline allocation.
172    void* operator new(size_t, NotNullTag, void* location) { return location; }
173
174private:
175    // Disallow new allocation.
176    void* operator new(size_t);
177
178    bool getKey(const String& key, v8::Local<v8::Value>&) const;
179
180    v8::Handle<v8::Value> m_options;
181    v8::Isolate* m_isolate;
182};
183
184template<>
185struct NativeValueTraits<Dictionary> {
186    static inline Dictionary nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
187    {
188        return Dictionary(value, isolate);
189    }
190};
191
192template <typename T>
193struct IntegralTypeTraits {
194};
195
196template <>
197struct IntegralTypeTraits<uint8_t> {
198    static inline uint8_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
199    {
200        return toUInt8(value, configuration, ok);
201    }
202    static const String typeName() { return "UInt8"; }
203};
204
205template <>
206struct IntegralTypeTraits<int8_t> {
207    static inline int8_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
208    {
209        return toInt8(value, configuration, ok);
210    }
211    static const String typeName() { return "Int8"; }
212};
213
214template <>
215struct IntegralTypeTraits<unsigned short> {
216    static inline uint16_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
217    {
218        return toUInt16(value, configuration, ok);
219    }
220    static const String typeName() { return "UInt16"; }
221};
222
223template <>
224struct IntegralTypeTraits<short> {
225    static inline int16_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
226    {
227        return toInt16(value, configuration, ok);
228    }
229    static const String typeName() { return "Int16"; }
230};
231
232template <>
233struct IntegralTypeTraits<unsigned> {
234    static inline uint32_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
235    {
236        return toUInt32(value, configuration, ok);
237    }
238    static const String typeName() { return "UInt32"; }
239};
240
241template <>
242struct IntegralTypeTraits<unsigned long> {
243    static inline uint32_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
244    {
245        return toUInt32(value, configuration, ok);
246    }
247    static const String typeName() { return "UInt32"; }
248};
249
250template <>
251struct IntegralTypeTraits<int> {
252    static inline int32_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
253    {
254        return toInt32(value, configuration, ok);
255    }
256    static const String typeName() { return "Int32"; }
257};
258
259template <>
260struct IntegralTypeTraits<long> {
261    static inline int32_t toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
262    {
263        return toInt32(value, configuration, ok);
264    }
265    static const String typeName() { return "Int32"; }
266};
267
268template <>
269struct IntegralTypeTraits<unsigned long long> {
270    static inline unsigned long long toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
271    {
272        return toUInt64(value, configuration, ok);
273    }
274    static const String typeName() { return "UInt64"; }
275};
276
277template <>
278struct IntegralTypeTraits<long long> {
279    static inline long long toIntegral(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok)
280    {
281        return toInt64(value, configuration, ok);
282    }
283    static const String typeName() { return "Int64"; }
284};
285
286template<typename T> bool Dictionary::convert(ConversionContext& context, const String& key, T& value) const
287{
288    ConversionContextScope scope(context);
289
290    v8::Local<v8::Value> v8Value;
291    if (!getKey(key, v8Value))
292        return true;
293
294    bool ok = false;
295    value = IntegralTypeTraits<T>::toIntegral(v8Value, NormalConversion, ok);
296    if (ok)
297        return true;
298
299    V8TRYCATCH_RETURN(v8::Local<v8::Number>, v8Number, v8Value->ToNumber(), false);
300    ASSERT(v8Number.IsEmpty());
301    context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "does not have type " + IntegralTypeTraits<T>::typeName() + "."));
302    return false;
303}
304
305template<typename T> bool Dictionary::convert(ConversionContext& context, const String& key, RefPtr<T>& value) const
306{
307    ConversionContextScope scope(context);
308
309    if (!get(key, value))
310        return true;
311
312    if (value)
313        return true;
314
315    v8::Local<v8::Value> v8Value;
316    getKey(key, v8Value);
317    if (context.isNullable() && WebCore::isUndefinedOrNull(v8Value))
318        return true;
319
320    context.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "does not have a " + context.typeName() + " type."));
321    return false;
322}
323
324}
325
326#endif // Dictionary_h
327