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#include "config.h" 27#include "IDBBindingUtilities.h" 28 29#if ENABLE(INDEXED_DATABASE) 30 31#include "IDBDatabaseException.h" 32#include "IDBKey.h" 33#include "IDBKeyPath.h" 34#include "SerializedScriptValue.h" 35#include "V8Binding.h" 36#include "V8IDBKey.h" 37#include <wtf/Vector.h> 38 39namespace WebCore { 40 41PassRefPtr<IDBKey> createIDBKeyFromValue(v8::Handle<v8::Value> value) 42{ 43 if (value->IsNull()) 44 return IDBKey::createNull(); 45 if (value->IsNumber()) 46 return IDBKey::createNumber(value->NumberValue()); 47 if (value->IsString()) 48 return IDBKey::createString(v8ValueToWebCoreString(value)); 49 if (value->IsDate()) 50 return IDBKey::createDate(value->NumberValue()); 51 52 return 0; // Signals type error. 53} 54 55namespace { 56 57template<typename T> 58bool getValueFrom(T indexOrName, v8::Handle<v8::Value>& v8Value) 59{ 60 v8::Local<v8::Object> object = v8Value->ToObject(); 61 if (!object->Has(indexOrName)) 62 return false; 63 v8Value = object->Get(indexOrName); 64 return true; 65} 66 67template<typename T> 68bool setValue(v8::Handle<v8::Value>& v8Object, T indexOrName, const v8::Handle<v8::Value>& v8Value) 69{ 70 v8::Local<v8::Object> object = v8Object->ToObject(); 71 ASSERT(!object->Has(indexOrName)); 72 return object->Set(indexOrName, v8Value); 73} 74 75bool get(v8::Handle<v8::Value>& object, const IDBKeyPathElement& keyPathElement) 76{ 77 switch (keyPathElement.type) { 78 case IDBKeyPathElement::IsIndexed: 79 return object->IsArray() && getValueFrom(keyPathElement.index, object); 80 case IDBKeyPathElement::IsNamed: 81 return object->IsObject() && getValueFrom(v8String(keyPathElement.identifier), object); 82 default: 83 ASSERT_NOT_REACHED(); 84 } 85 return false; 86} 87 88bool set(v8::Handle<v8::Value>& object, const IDBKeyPathElement& keyPathElement, const v8::Handle<v8::Value>& v8Value) 89{ 90 switch (keyPathElement.type) { 91 case IDBKeyPathElement::IsIndexed: 92 return object->IsArray() && setValue(object, keyPathElement.index, v8Value); 93 case IDBKeyPathElement::IsNamed: 94 return object->IsObject() && setValue(object, v8String(keyPathElement.identifier), v8Value); 95 default: 96 ASSERT_NOT_REACHED(); 97 } 98 return false; 99} 100 101class LocalContext { 102public: 103 LocalContext() 104 : m_context(v8::Context::New()) 105 { 106 m_context->Enter(); 107 } 108 109 ~LocalContext() 110 { 111 m_context->Exit(); 112 m_context.Dispose(); 113 } 114 115private: 116 v8::HandleScope m_scope; 117 v8::Persistent<v8::Context> m_context; 118}; 119 120v8::Handle<v8::Value> getNthValueOnKeyPath(v8::Handle<v8::Value>& rootValue, const Vector<IDBKeyPathElement>& keyPathElements, size_t index) 121{ 122 v8::Handle<v8::Value> currentValue(rootValue); 123 124 ASSERT(index <= keyPathElements.size()); 125 for (size_t i = 0; i < index; ++i) { 126 if (!get(currentValue, keyPathElements[i])) 127 return v8::Handle<v8::Value>(); 128 } 129 130 return currentValue; 131} 132 133} // anonymous namespace 134 135PassRefPtr<IDBKey> createIDBKeyFromSerializedValueAndKeyPath(PassRefPtr<SerializedScriptValue> value, const Vector<IDBKeyPathElement>& keyPath) 136{ 137 LocalContext localContext; 138 v8::Handle<v8::Value> v8Value(value->deserialize()); 139 v8::Handle<v8::Value> v8Key(getNthValueOnKeyPath(v8Value, keyPath, keyPath.size())); 140 if (v8Key.IsEmpty()) 141 return 0; 142 return createIDBKeyFromValue(v8Key); 143} 144 145PassRefPtr<SerializedScriptValue> injectIDBKeyIntoSerializedValue(PassRefPtr<IDBKey> key, PassRefPtr<SerializedScriptValue> value, const Vector<IDBKeyPathElement>& keyPath) 146{ 147 LocalContext localContext; 148 if (!keyPath.size()) 149 return 0; 150 151 v8::Handle<v8::Value> v8Value(value->deserialize()); 152 v8::Handle<v8::Value> parent(getNthValueOnKeyPath(v8Value, keyPath, keyPath.size() - 1)); 153 if (parent.IsEmpty()) 154 return 0; 155 156 if (!set(parent, keyPath.last(), toV8(key.get()))) 157 return 0; 158 159 return SerializedScriptValue::create(v8Value); 160} 161 162} // namespace WebCore 163 164#endif 165