/* * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "IDLTypes.h" #include "JSDOMConvertStrings.h" #include namespace WebCore { namespace Detail { template struct IdentifierConverter; template<> struct IdentifierConverter { static String convert(JSC::ExecState&, const JSC::Identifier& identifier) { return identifier.string(); } }; template<> struct IdentifierConverter { static String convert(JSC::ExecState& state, const JSC::Identifier& identifier) { return identifierToByteString(state, identifier); } }; template<> struct IdentifierConverter { static String convert(JSC::ExecState& state, const JSC::Identifier& identifier) { return identifierToUSVString(state, identifier); } }; } template struct Converter> : DefaultConverter> { using ReturnType = typename IDLRecord::ImplementationType; using KeyType = typename K::ImplementationType; using ValueType = typename V::ImplementationType; static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) { auto& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 1. Let result be a new empty instance of record. // 2. If Type(O) is Undefined or Null, return result. if (value.isUndefinedOrNull()) return { }; // 3. If Type(O) is not Object, throw a TypeError. if (!value.isObject()) { throwTypeError(&state, scope); return { }; } JSC::JSObject* object = JSC::asObject(value); ReturnType result; // 4. Let keys be ? O.[[OwnPropertyKeys]](). JSC::PropertyNameArray keys(&vm, JSC::PropertyNameMode::Strings); object->getOwnPropertyNames(object, &state, keys, JSC::EnumerationMode()); RETURN_IF_EXCEPTION(scope, { }); // 5. Repeat, for each element key of keys in List order: for (auto& key : keys) { // 1. Let desc be ? O.[[GetOwnProperty]](key). JSC::PropertyDescriptor descriptor; bool didGetDescriptor = object->getOwnPropertyDescriptor(&state, key, descriptor); RETURN_IF_EXCEPTION(scope, { }); if (!didGetDescriptor) continue; // 2. If desc is not undefined and desc.[[Enumerable]] is true: // FIXME: Do we need to check for enumerable / undefined, or is this handled by the default // enumeration mode? if (!descriptor.value().isUndefined() && descriptor.enumerable()) { // 1. Let typedKey be key converted to an IDL value of type K. auto typedKey = Detail::IdentifierConverter::convert(state, key); // 2. Let value be ? Get(O, key). auto subValue = object->get(&state, key); RETURN_IF_EXCEPTION(scope, { }); // 3. Let typedValue be value converted to an IDL value of type V. auto typedValue = Converter::convert(state, subValue); RETURN_IF_EXCEPTION(scope, { }); // 4. If typedKey is already a key in result, set its value to typedValue. // Note: This can happen when O is a proxy object. // FIXME: Handle this case. // 5. Otherwise, append to result a mapping (typedKey, typedValue). result.append({ typedKey, typedValue }); } } // 6. Return result. return result; } }; template struct JSConverter> { static constexpr bool needsState = true; static constexpr bool needsGlobalObject = true; template static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const MapType& map) { auto& vm = state.vm(); // 1. Let result be ! ObjectCreate(%ObjectPrototype%). auto result = constructEmptyObject(&state); // 2. Repeat, for each mapping (key, value) in D: for (const auto& keyValuePair : map) { // 1. Let esKey be key converted to an ECMAScript value. // Note, this step is not required, as we need the key to be // an Identifier, not a JSValue. // 2. Let esValue be value converted to an ECMAScript value. auto esValue = toJS(state, globalObject, keyValuePair.value); // 3. Let created be ! CreateDataProperty(result, esKey, esValue). bool created = result->putDirect(vm, JSC::Identifier::fromString(&vm, keyValuePair.key), esValue); // 4. Assert: created is true. ASSERT_UNUSED(created, created); } // 3. Return result. return result; } }; } // namespace WebCore