LCOV - code coverage report
Current view: directory - dom/indexedDB - IDBKeyRange.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 170 107 62.9 %
Date: 2012-06-02 Functions: 24 19 79.2 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* vim: set ts=2 et sw=2 tw=80: */
       3                 : /* ***** BEGIN LICENSE BLOCK *****
       4                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       5                 :  *
       6                 :  * The contents of this file are subject to the Mozilla Public License Version
       7                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       8                 :  * the License. You may obtain a copy of the License at
       9                 :  * http://www.mozilla.org/MPL/
      10                 :  *
      11                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      12                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      13                 :  * for the specific language governing rights and limitations under the
      14                 :  * License.
      15                 :  *
      16                 :  * The Original Code is Indexed Database.
      17                 :  *
      18                 :  * The Initial Developer of the Original Code is
      19                 :  * The Mozilla Foundation.
      20                 :  * Portions created by the Initial Developer are Copyright (C) 2010
      21                 :  * the Initial Developer. All Rights Reserved.
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *   Ben Turner <bent.mozilla@gmail.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "IDBKeyRange.h"
      41                 : 
      42                 : #include "nsIXPConnect.h"
      43                 : 
      44                 : #include "nsDOMClassInfo.h"
      45                 : #include "nsJSUtils.h"
      46                 : #include "nsThreadUtils.h"
      47                 : #include "nsContentUtils.h"
      48                 : 
      49                 : #include "Key.h"
      50                 : 
      51                 : USING_INDEXEDDB_NAMESPACE
      52                 : 
      53                 : namespace {
      54                 : 
      55                 : inline
      56                 : bool
      57             142 : ReturnKeyRange(JSContext* aCx,
      58                 :                jsval* aVp,
      59                 :                IDBKeyRange* aKeyRange)
      60                 : {
      61             142 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
      62             142 :   NS_ASSERTION(aCx, "Null pointer!");
      63             142 :   NS_ASSERTION(aVp, "Null pointer!");
      64             142 :   NS_ASSERTION(aKeyRange, "Null pointer!");
      65                 : 
      66             142 :   nsIXPConnect* xpc = nsContentUtils::XPConnect();
      67             142 :   NS_ASSERTION(xpc, "This should never be null!");
      68                 : 
      69             142 :   JSObject* global = JS_GetGlobalForScopeChain(aCx);
      70             142 :   if (!global) {
      71               0 :     NS_WARNING("Couldn't get global object!");
      72               0 :     return false;
      73                 :   }
      74                 : 
      75             284 :   nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
      76             142 :   if (NS_FAILED(xpc->WrapNative(aCx, global, aKeyRange,
      77                 :                                 NS_GET_IID(nsIIDBKeyRange),
      78                 :                                 getter_AddRefs(holder)))) {
      79               0 :     JS_ReportError(aCx, "Couldn't wrap IDBKeyRange object.");
      80               0 :     return false;
      81                 :   }
      82                 : 
      83                 :   JSObject* result;
      84             142 :   if (NS_FAILED(holder->GetJSObject(&result))) {
      85               0 :     JS_ReportError(aCx, "Couldn't get JSObject from wrapper.");
      86               0 :     return false;
      87                 :   }
      88                 : 
      89             142 :   JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(result));
      90             142 :   return true;
      91                 : }
      92                 : 
      93                 : inline
      94                 : nsresult
      95             428 : GetKeyFromJSVal(JSContext* aCx,
      96                 :                 jsval aVal,
      97                 :                 Key& aKey,
      98                 :                 bool aAllowUnset = false)
      99                 : {
     100             428 :   nsresult rv = aKey.SetFromJSVal(aCx, aVal);
     101             428 :   if (NS_FAILED(rv)) {
     102               0 :     NS_ASSERTION(NS_ERROR_GET_MODULE(rv) == NS_ERROR_MODULE_DOM_INDEXEDDB,
     103                 :                  "Bad error code!");
     104               0 :     return rv;
     105                 :   }
     106                 : 
     107             428 :   if (aKey.IsUnset() && !aAllowUnset) {
     108               0 :     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     109                 :   }
     110                 : 
     111             428 :   return NS_OK;
     112                 : }
     113                 : 
     114                 : inline
     115                 : void
     116               3 : ThrowException(JSContext* aCx,
     117                 :                nsresult aErrorCode)
     118                 : {
     119               3 :   NS_ASSERTION(NS_FAILED(aErrorCode), "Not an error code!");
     120               3 :   if (!JS_IsExceptionPending(aCx)) {
     121               3 :     nsDOMClassInfo::ThrowJSException(aCx, aErrorCode);
     122                 :   }
     123               3 : }
     124                 : 
     125                 : inline
     126                 : bool
     127             199 : GetKeyFromJSValOrThrow(JSContext* aCx,
     128                 :                        jsval aVal,
     129                 :                        Key& aKey)
     130                 : {
     131             199 :   nsresult rv = GetKeyFromJSVal(aCx, aVal, aKey);
     132             199 :   if (NS_FAILED(rv)) {
     133               0 :     ThrowException(aCx, rv);
     134               0 :     return false;
     135                 :   }
     136             199 :   return true;
     137                 : }
     138                 : 
     139                 : JSBool
     140              27 : MakeOnlyKeyRange(JSContext* aCx,
     141                 :                  unsigned aArgc,
     142                 :                  jsval* aVp)
     143                 : {
     144              27 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     145                 : 
     146                 :   jsval val;
     147              27 :   if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &val)) {
     148               0 :     return false;
     149                 :   }
     150                 : 
     151              54 :   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(false, false, true);
     152                 : 
     153              27 :   if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
     154               0 :     return false;
     155                 :   }
     156                 : 
     157              27 :   return ReturnKeyRange(aCx, aVp, keyRange);
     158                 : }
     159                 : 
     160                 : JSBool
     161              36 : MakeLowerBoundKeyRange(JSContext* aCx,
     162                 :                        unsigned aArgc,
     163                 :                        jsval* aVp)
     164                 : {
     165              36 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     166                 : 
     167                 :   jsval val;
     168              36 :   JSBool open = false;
     169              36 :   if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", &val, &open)) {
     170               0 :     return false;
     171                 :   }
     172                 : 
     173              72 :   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(open, true, false);
     174                 : 
     175              36 :   if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Lower())) {
     176               0 :     return false;
     177                 :   }
     178                 : 
     179              36 :   return ReturnKeyRange(aCx, aVp, keyRange);
     180                 : }
     181                 : 
     182                 : JSBool
     183              28 : MakeUpperBoundKeyRange(JSContext* aCx,
     184                 :                        unsigned aArgc,
     185                 :                        jsval* aVp)
     186                 : {
     187              28 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     188                 : 
     189                 :   jsval val;
     190              28 :   JSBool open = false;
     191              28 :   if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v/b", &val, &open)) {
     192               0 :     return false;
     193                 :   }
     194                 : 
     195              56 :   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(true, open, false);
     196                 : 
     197              28 :   if (!GetKeyFromJSValOrThrow(aCx, val, keyRange->Upper())) {
     198               0 :     return false;
     199                 :   }
     200                 : 
     201              28 :   return ReturnKeyRange(aCx, aVp, keyRange);
     202                 : }
     203                 : 
     204                 : JSBool
     205              54 : MakeBoundKeyRange(JSContext* aCx,
     206                 :                   unsigned aArgc,
     207                 :                   jsval* aVp)
     208                 : {
     209              54 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     210                 : 
     211                 :   jsval lowerVal, upperVal;
     212              54 :   JSBool lowerOpen = false, upperOpen = false;
     213              54 :   if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "vv/bb", &lowerVal,
     214              54 :                            &upperVal, &lowerOpen, &upperOpen)) {
     215               0 :     return false;
     216                 :   }
     217                 : 
     218             108 :   nsRefPtr<IDBKeyRange> keyRange = new IDBKeyRange(lowerOpen, upperOpen, false);
     219                 : 
     220             108 :   if (!GetKeyFromJSValOrThrow(aCx, lowerVal, keyRange->Lower()) ||
     221              54 :       !GetKeyFromJSValOrThrow(aCx, upperVal, keyRange->Upper())) {
     222               0 :     return false;
     223                 :   }
     224                 : 
     225             107 :   if (keyRange->Lower() > keyRange->Upper() ||
     226              53 :       (keyRange->Lower() == keyRange->Upper() && (lowerOpen || upperOpen))) {
     227               3 :     ThrowException(aCx, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
     228               3 :     return false;
     229                 :   }
     230                 : 
     231              51 :   return ReturnKeyRange(aCx, aVp, keyRange);
     232                 : }
     233                 : 
     234                 : #define KEYRANGE_FUNCTION_FLAGS (JSPROP_ENUMERATE | JSPROP_PERMANENT)
     235                 : 
     236                 : const JSFunctionSpec gKeyRangeConstructors[] = {
     237                 :   JS_FN("only", MakeOnlyKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
     238                 :   JS_FN("lowerBound", MakeLowerBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
     239                 :   JS_FN("upperBound", MakeUpperBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
     240                 :   JS_FN("bound", MakeBoundKeyRange, 2, KEYRANGE_FUNCTION_FLAGS),
     241                 :   JS_FS_END
     242                 : };
     243                 : 
     244                 : #undef KEYRANGE_FUNCTION_FLAGS
     245                 : 
     246                 : } // anonymous namespace
     247                 : 
     248                 : // static
     249                 : JSBool
     250              50 : IDBKeyRange::DefineConstructors(JSContext* aCx,
     251                 :                                 JSObject* aObject)
     252                 : {
     253              50 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     254              50 :   NS_ASSERTION(aCx, "Null pointer!");
     255              50 :   NS_ASSERTION(aObject, "Null pointer!");
     256                 : 
     257                 :   // Add the constructor methods for key ranges.
     258                 :   return JS_DefineFunctions(aCx, aObject,
     259              50 :                             const_cast<JSFunctionSpec*>(gKeyRangeConstructors));
     260                 : }
     261                 : 
     262                 : // static
     263                 : nsresult
     264             413 : IDBKeyRange::FromJSVal(JSContext* aCx,
     265                 :                        const jsval& aVal,
     266                 :                        IDBKeyRange** aKeyRange)
     267                 : {
     268                 :   nsresult rv;
     269             826 :   nsRefPtr<IDBKeyRange> keyRange;
     270                 : 
     271             413 :   if (JSVAL_IS_VOID(aVal) || JSVAL_IS_NULL(aVal)) {
     272                 :     // undefined and null returns no IDBKeyRange.
     273                 :   }
     274             670 :   else if (JSVAL_IS_PRIMITIVE(aVal) ||
     275             147 :            JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(aVal)) ||
     276             147 :            JS_ObjectIsDate(aCx, JSVAL_TO_OBJECT(aVal))) {
     277                 :     // A valid key returns an 'only' IDBKeyRange.
     278             229 :     keyRange = new IDBKeyRange(false, false, true);
     279                 : 
     280             229 :     rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower());
     281             229 :     if (NS_FAILED(rv)) {
     282               0 :       return rv;
     283                 :     }
     284                 :   }
     285                 :   else {
     286                 :     // An object is not permitted unless it's another IDBKeyRange.
     287             147 :     nsIXPConnect* xpc = nsContentUtils::XPConnect();
     288             147 :     NS_ASSERTION(xpc, "This should never be null!");
     289                 : 
     290             294 :     nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
     291                 :     rv = xpc->GetWrappedNativeOfJSObject(aCx, JSVAL_TO_OBJECT(aVal),
     292             147 :                                          getter_AddRefs(wrapper));
     293             147 :     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     294                 : 
     295             292 :     nsCOMPtr<nsIIDBKeyRange> iface;
     296             146 :     if (!wrapper || !(iface = do_QueryInterface(wrapper->Native()))) {
     297                 :       // Some random JS object?
     298               0 :       return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
     299                 :     }
     300                 : 
     301             292 :     keyRange = static_cast<IDBKeyRange*>(iface.get());
     302                 :   }
     303                 : 
     304             412 :   keyRange.forget(aKeyRange);
     305             412 :   return NS_OK;
     306                 : }
     307                 : 
     308            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(IDBKeyRange)
     309                 : 
     310               2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBKeyRange)
     311               2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
     312               2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     313                 : 
     314               2 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBKeyRange)
     315               2 :   if (JSVAL_IS_GCTHING(tmp->mCachedLowerVal)) {
     316               0 :     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedLowerVal);
     317               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedLowerVal")
     318                 :   }
     319               2 :   if (JSVAL_IS_GCTHING(tmp->mCachedUpperVal)) {
     320               0 :     void *gcThing = JSVAL_TO_GCTHING(tmp->mCachedUpperVal);
     321               0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mCachedUpperVal")
     322                 :   }
     323               2 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     324                 : 
     325               2 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBKeyRange)
     326               2 :   if (tmp->mRooted) {
     327               0 :     NS_DROP_JS_OBJECTS(tmp, IDBKeyRange);
     328               0 :     tmp->mCachedLowerVal = JSVAL_VOID;
     329               0 :     tmp->mCachedUpperVal = JSVAL_VOID;
     330               0 :     tmp->mHaveCachedLowerVal = false;
     331               0 :     tmp->mHaveCachedUpperVal = false;
     332               0 :     tmp->mRooted = false;
     333                 :   }
     334               2 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     335                 : 
     336            1789 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBKeyRange)
     337             998 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
     338             856 :   NS_INTERFACE_MAP_ENTRY(nsIIDBKeyRange)
     339             568 :   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBKeyRange)
     340             426 : NS_INTERFACE_MAP_END
     341                 : 
     342            1327 : NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBKeyRange)
     343            1701 : NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBKeyRange)
     344                 : 
     345                 : DOMCI_DATA(IDBKeyRange, IDBKeyRange)
     346                 : 
     347             748 : IDBKeyRange::~IDBKeyRange()
     348                 : {
     349             374 :   if (mRooted) {
     350               0 :     NS_DROP_JS_OBJECTS(this, IDBKeyRange);
     351               0 :     mRooted = false;
     352                 :   }
     353             374 : }
     354                 : 
     355                 : NS_IMETHODIMP
     356               0 : IDBKeyRange::GetLower(JSContext* aCx,
     357                 :                       jsval* aLower)
     358                 : {
     359               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     360                 : 
     361               0 :   if (!mHaveCachedLowerVal) {
     362               0 :     if (!mRooted) {
     363               0 :       NS_HOLD_JS_OBJECTS(this, IDBKeyRange);
     364               0 :       mRooted = true;
     365                 :     }
     366                 : 
     367               0 :     nsresult rv = Lower().ToJSVal(aCx, &mCachedLowerVal);
     368               0 :     NS_ENSURE_SUCCESS(rv, rv);
     369                 : 
     370               0 :     mHaveCachedLowerVal = true;
     371                 :   }
     372                 : 
     373               0 :   *aLower = mCachedLowerVal;
     374               0 :   return NS_OK;
     375                 : }
     376                 : 
     377                 : NS_IMETHODIMP
     378               0 : IDBKeyRange::GetUpper(JSContext* aCx,
     379                 :                       jsval* aUpper)
     380                 : {
     381               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     382                 : 
     383               0 :   if (!mHaveCachedUpperVal) {
     384               0 :     if (!mRooted) {
     385               0 :       NS_HOLD_JS_OBJECTS(this, IDBKeyRange);
     386               0 :       mRooted = true;
     387                 :     }
     388                 : 
     389               0 :     nsresult rv = Upper().ToJSVal(aCx, &mCachedUpperVal);
     390               0 :     NS_ENSURE_SUCCESS(rv, rv);
     391                 : 
     392               0 :     mHaveCachedUpperVal = true;
     393                 :   }
     394                 : 
     395               0 :   *aUpper = mCachedUpperVal;
     396               0 :   return NS_OK;
     397                 : }
     398                 : 
     399                 : NS_IMETHODIMP
     400               0 : IDBKeyRange::GetLowerOpen(bool* aLowerOpen)
     401                 : {
     402               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     403                 : 
     404               0 :   *aLowerOpen = mLowerOpen;
     405               0 :   return NS_OK;
     406                 : }
     407                 : 
     408                 : 
     409                 : NS_IMETHODIMP
     410               0 : IDBKeyRange::GetUpperOpen(bool* aUpperOpen)
     411                 : {
     412               0 :   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     413                 : 
     414               0 :   *aUpperOpen = mUpperOpen;
     415               0 :   return NS_OK;
     416            4392 : }

Generated by: LCOV version 1.7