tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IDBKeyRange.cpp (7989B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "IDBKeyRange.h"
      8 
      9 #include "Key.h"
     10 #include "mozilla/ErrorResult.h"
     11 #include "mozilla/HoldDropJSObjects.h"
     12 #include "mozilla/dom/BindingUtils.h"
     13 #include "mozilla/dom/IDBKeyRangeBinding.h"
     14 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
     15 
     16 namespace mozilla::dom {
     17 
     18 using namespace mozilla::dom::indexedDB;
     19 
     20 namespace {
     21 
     22 void GetKeyFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, Key& aKey,
     23                     ErrorResult& aRv) {
     24  auto result = aKey.SetFromJSVal(aCx, aVal);
     25  if (result.isErr()) {
     26    aRv = result.unwrapErr().ExtractErrorResult(
     27        InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
     28    return;
     29  }
     30 
     31  if (aKey.IsUnset()) {
     32    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
     33  }
     34 }
     35 
     36 }  // namespace
     37 
     38 IDBKeyRange::IDBKeyRange(bool aLowerOpen, bool aUpperOpen, bool aIsOnly)
     39    : mCachedLowerVal(JS::UndefinedValue()),
     40      mCachedUpperVal(JS::UndefinedValue()),
     41      mLowerOpen(aLowerOpen),
     42      mUpperOpen(aUpperOpen),
     43      mIsOnly(aIsOnly),
     44      mHaveCachedLowerVal(false),
     45      mHaveCachedUpperVal(false),
     46      mRooted(false) {
     47  AssertIsOnOwningThread();
     48 }
     49 
     50 IDBKeyRange::~IDBKeyRange() { DropJSObjects(); }
     51 
     52 // static
     53 void IDBKeyRange::FromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal,
     54                            RefPtr<IDBKeyRange>* aKeyRange, ErrorResult& aRv) {
     55  MOZ_ASSERT_IF(!aCx, aVal.isUndefined());
     56  MOZ_ASSERT(aKeyRange);
     57 
     58  RefPtr<IDBKeyRange> keyRange;
     59 
     60  if (aVal.isNullOrUndefined()) {
     61    // undefined and null returns no IDBKeyRange.
     62    *aKeyRange = std::move(keyRange);
     63    return;
     64  }
     65 
     66  JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr);
     67 
     68  // Unwrap an IDBKeyRange object if possible.
     69  if (obj && NS_SUCCEEDED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) {
     70    MOZ_ASSERT(keyRange);
     71    *aKeyRange = std::move(keyRange);
     72    return;
     73  }
     74 
     75  // A valid key returns an 'only' IDBKeyRange.
     76  keyRange = new IDBKeyRange(false, false, true);
     77  GetKeyFromJSVal(aCx, aVal, keyRange->Lower(), aRv);
     78  if (!aRv.Failed()) {
     79    *aKeyRange = std::move(keyRange);
     80  }
     81 }
     82 
     83 // static
     84 RefPtr<IDBKeyRange> IDBKeyRange::FromSerialized(
     85    const SerializedKeyRange& aKeyRange) {
     86  RefPtr<IDBKeyRange> keyRange = new IDBKeyRange(
     87      aKeyRange.lowerOpen(), aKeyRange.upperOpen(), aKeyRange.isOnly());
     88  keyRange->Lower() = aKeyRange.lower();
     89  if (!keyRange->IsOnly()) {
     90    keyRange->Upper() = aKeyRange.upper();
     91  }
     92  return keyRange;
     93 }
     94 
     95 void IDBKeyRange::ToSerialized(SerializedKeyRange& aKeyRange) const {
     96  aKeyRange.lowerOpen() = LowerOpen();
     97  aKeyRange.upperOpen() = UpperOpen();
     98  aKeyRange.isOnly() = IsOnly();
     99 
    100  aKeyRange.lower() = Lower();
    101  if (!IsOnly()) {
    102    aKeyRange.upper() = Upper();
    103  }
    104 }
    105 
    106 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
    107 
    108 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
    109 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    110 
    111 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
    112  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedLowerVal)
    113  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedUpperVal)
    114 NS_IMPL_CYCLE_COLLECTION_TRACE_END
    115 
    116 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
    117  tmp->DropJSObjects();
    118 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    119 
    120 void IDBKeyRange::DropJSObjects() {
    121  if (!mRooted) {
    122    return;
    123  }
    124  mHaveCachedLowerVal = false;
    125  mHaveCachedUpperVal = false;
    126  mRooted = false;
    127  mozilla::DropJSObjects(this);
    128 }
    129 
    130 bool IDBKeyRange::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
    131                             JS::MutableHandle<JSObject*> aReflector) {
    132  return IDBKeyRange_Binding::Wrap(aCx, this, aGivenProto, aReflector);
    133 }
    134 
    135 void IDBKeyRange::GetLower(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
    136                           ErrorResult& aRv) {
    137  AssertIsOnOwningThread();
    138 
    139  if (!mHaveCachedLowerVal) {
    140    if (!mRooted) {
    141      mozilla::HoldJSObjects(this);
    142      mRooted = true;
    143    }
    144 
    145    aRv = Lower().ToJSVal(aCx, mCachedLowerVal);
    146    if (aRv.Failed()) {
    147      return;
    148    }
    149 
    150    mHaveCachedLowerVal = true;
    151  }
    152 
    153  aResult.set(mCachedLowerVal);
    154 }
    155 
    156 void IDBKeyRange::GetUpper(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
    157                           ErrorResult& aRv) {
    158  AssertIsOnOwningThread();
    159 
    160  if (!mHaveCachedUpperVal) {
    161    if (!mRooted) {
    162      mozilla::HoldJSObjects(this);
    163      mRooted = true;
    164    }
    165 
    166    aRv = Upper().ToJSVal(aCx, mCachedUpperVal);
    167    if (aRv.Failed()) {
    168      return;
    169    }
    170 
    171    mHaveCachedUpperVal = true;
    172  }
    173 
    174  aResult.set(mCachedUpperVal);
    175 }
    176 
    177 bool IDBKeyRange::Includes(JSContext* aCx, JS::Handle<JS::Value> aValue,
    178                           ErrorResult& aRv) const {
    179  Key key;
    180  GetKeyFromJSVal(aCx, aValue, key, aRv);
    181  if (aRv.Failed()) {
    182    return false;
    183  }
    184 
    185  MOZ_ASSERT(!(Lower().IsUnset() && Upper().IsUnset()));
    186  MOZ_ASSERT_IF(IsOnly(), !Lower().IsUnset() && !LowerOpen() &&
    187                              Lower() == Upper() && LowerOpen() == UpperOpen());
    188 
    189  if (!Lower().IsUnset()) {
    190    switch (Key::CompareKeys(Lower(), key)) {
    191      case 1:
    192        return false;
    193      case 0:
    194        // Identical keys.
    195        return !LowerOpen();
    196      case -1:
    197        if (IsOnly()) {
    198          return false;
    199        }
    200        break;
    201      default:
    202        MOZ_CRASH();
    203    }
    204  }
    205 
    206  if (!Upper().IsUnset()) {
    207    switch (Key::CompareKeys(key, Upper())) {
    208      case 1:
    209        return false;
    210      case 0:
    211        // Identical keys.
    212        return !UpperOpen();
    213      case -1:
    214        break;
    215    }
    216  }
    217 
    218  return true;
    219 }
    220 
    221 // static
    222 RefPtr<IDBKeyRange> IDBKeyRange::Only(const GlobalObject& aGlobal,
    223                                      JS::Handle<JS::Value> aValue,
    224                                      ErrorResult& aRv) {
    225  RefPtr<IDBKeyRange> keyRange = new IDBKeyRange(false, false, true);
    226 
    227  GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower(), aRv);
    228  if (aRv.Failed()) {
    229    return nullptr;
    230  }
    231 
    232  return keyRange;
    233 }
    234 
    235 // static
    236 RefPtr<IDBKeyRange> IDBKeyRange::LowerBound(const GlobalObject& aGlobal,
    237                                            JS::Handle<JS::Value> aValue,
    238                                            bool aOpen, ErrorResult& aRv) {
    239  RefPtr<IDBKeyRange> keyRange = new IDBKeyRange(aOpen, true, false);
    240 
    241  GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Lower(), aRv);
    242  if (aRv.Failed()) {
    243    return nullptr;
    244  }
    245 
    246  return keyRange;
    247 }
    248 
    249 // static
    250 RefPtr<IDBKeyRange> IDBKeyRange::UpperBound(const GlobalObject& aGlobal,
    251                                            JS::Handle<JS::Value> aValue,
    252                                            bool aOpen, ErrorResult& aRv) {
    253  RefPtr<IDBKeyRange> keyRange = new IDBKeyRange(true, aOpen, false);
    254 
    255  GetKeyFromJSVal(aGlobal.Context(), aValue, keyRange->Upper(), aRv);
    256  if (aRv.Failed()) {
    257    return nullptr;
    258  }
    259 
    260  return keyRange;
    261 }
    262 
    263 // static
    264 RefPtr<IDBKeyRange> IDBKeyRange::Bound(const GlobalObject& aGlobal,
    265                                       JS::Handle<JS::Value> aLower,
    266                                       JS::Handle<JS::Value> aUpper,
    267                                       bool aLowerOpen, bool aUpperOpen,
    268                                       ErrorResult& aRv) {
    269  RefPtr<IDBKeyRange> keyRange = new IDBKeyRange(aLowerOpen, aUpperOpen, false);
    270 
    271  GetKeyFromJSVal(aGlobal.Context(), aLower, keyRange->Lower(), aRv);
    272  if (aRv.Failed()) {
    273    return nullptr;
    274  }
    275 
    276  GetKeyFromJSVal(aGlobal.Context(), aUpper, keyRange->Upper(), aRv);
    277  if (aRv.Failed()) {
    278    return nullptr;
    279  }
    280 
    281  if (keyRange->Lower() > keyRange->Upper() ||
    282      (keyRange->Lower() == keyRange->Upper() && (aLowerOpen || aUpperOpen))) {
    283    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
    284    return nullptr;
    285  }
    286 
    287  return keyRange;
    288 }
    289 
    290 }  // namespace mozilla::dom