mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
352 lines
9.9 KiB
C++
352 lines
9.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Indexed Database.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* The Mozilla Foundation.
|
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Ben Turner <bent.mozilla@gmail.com>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "IDBKeyRange.h"
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "jscntxt.h"
|
|
#include "nsDOMClassInfo.h"
|
|
#include "nsJSUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "Key.h"
|
|
|
|
USING_INDEXEDDB_NAMESPACE
|
|
|
|
namespace {
|
|
|
|
inline
|
|
JSBool
|
|
ConvertArguments(JSContext* aCx,
|
|
uintN aArgc,
|
|
jsval* aVp,
|
|
const char* aMethodName,
|
|
nsTArray<nsCOMPtr<nsIVariant> >& aKeys)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
NS_ASSERTION(aCx, "Null pointer!");
|
|
NS_ASSERTION(aVp, "Null pointer!");
|
|
NS_ASSERTION(aMethodName, "Null pointer!");
|
|
NS_ASSERTION(aKeys.Capacity(), "Need guaranteed capacity!");
|
|
NS_ASSERTION(aKeys.IsEmpty(), "Not an empty array!");
|
|
|
|
if (aArgc < aKeys.Capacity()) {
|
|
nsCString num;
|
|
num.AppendInt(aKeys.Length());
|
|
JS_ReportErrorNumberUC(aCx, js_GetErrorMessage, nsnull,
|
|
JSMSG_MORE_ARGS_NEEDED, aMethodName, num.get(),
|
|
aKeys.Capacity() == 1 ? "" : "s");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
for (uintN i = 0; i < aKeys.Capacity(); i++) {
|
|
jsval& arg = JS_ARGV(aCx, aVp)[i];
|
|
if (JSVAL_IS_VOID(arg) || JSVAL_IS_NULL(arg) ||
|
|
!Key::CanBeConstructedFromJSVal(arg)) {
|
|
JS_ReportError(aCx, "Argument is not a supported key type.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
|
NS_ASSERTION(xpc, "This should never be null!");
|
|
|
|
nsCOMPtr<nsIVariant>* key = aKeys.AppendElement();
|
|
NS_ASSERTION(key, "This should never fail!");
|
|
|
|
if (NS_FAILED(xpc->JSValToVariant(aCx, &arg, getter_AddRefs(*key)))) {
|
|
JS_ReportError(aCx, "Could not convert argument to variant.");
|
|
return JS_FALSE;
|
|
}
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
inline
|
|
JSBool
|
|
ReturnKeyRange(JSContext* aCx,
|
|
jsval* aVp,
|
|
IDBKeyRange* aKeyRange)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
NS_ASSERTION(aCx, "Null pointer!");
|
|
NS_ASSERTION(aVp, "Null pointer!");
|
|
NS_ASSERTION(aKeyRange, "Null pointer!");
|
|
|
|
nsIXPConnect* xpc = nsContentUtils::XPConnect();
|
|
NS_ASSERTION(xpc, "This should never be null!");
|
|
|
|
JSObject* global = JS_GetGlobalForObject(aCx, JS_GetScopeChain(aCx));
|
|
NS_ENSURE_TRUE(global, JS_FALSE);
|
|
|
|
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
|
|
if (NS_FAILED(xpc->WrapNative(aCx, global, aKeyRange,
|
|
NS_GET_IID(nsIIDBKeyRange),
|
|
getter_AddRefs(holder)))) {
|
|
JS_ReportError(aCx, "Couldn't wrap IDBKeyRange object.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
JSObject* result;
|
|
if (NS_FAILED(holder->GetJSObject(&result))) {
|
|
JS_ReportError(aCx, "Couldn't get JSObject from wrapper.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(result));
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JSBool
|
|
MakeOnlyKeyRange(JSContext* aCx,
|
|
uintN aArgc,
|
|
jsval* aVp)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
nsAutoTArray<nsCOMPtr<nsIVariant>, 1> keys;
|
|
if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.only", keys)) {
|
|
return JS_FALSE;
|
|
}
|
|
NS_ASSERTION(keys.Length() == 1, "Didn't set all keys!");
|
|
|
|
nsRefPtr<IDBKeyRange> range =
|
|
IDBKeyRange::Create(keys[0], keys[0], PR_FALSE, PR_FALSE);
|
|
NS_ASSERTION(range, "Out of memory?");
|
|
|
|
if (!ReturnKeyRange(aCx, aVp, range)) {
|
|
return JS_FALSE;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JSBool
|
|
MakeLowerBoundKeyRange(JSContext* aCx,
|
|
uintN aArgc,
|
|
jsval* aVp)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
nsAutoTArray<nsCOMPtr<nsIVariant>, 1> keys;
|
|
if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.lowerBound", keys)) {
|
|
return JS_FALSE;
|
|
}
|
|
NS_ASSERTION(keys.Length() == 1, "Didn't set all keys!");
|
|
|
|
JSBool open = JS_FALSE;
|
|
if (aArgc > 1 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[1], &open)) {
|
|
JS_ReportError(aCx, "Couldn't convert argument 2 to boolean.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
nsRefPtr<IDBKeyRange> range =
|
|
IDBKeyRange::Create(keys[0], nsnull, !!open, PR_TRUE);
|
|
NS_ASSERTION(range, "Out of memory?");
|
|
|
|
if (!ReturnKeyRange(aCx, aVp, range)) {
|
|
return JS_FALSE;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JSBool
|
|
MakeUpperBoundKeyRange(JSContext* aCx,
|
|
uintN aArgc,
|
|
jsval* aVp)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
nsAutoTArray<nsCOMPtr<nsIVariant>, 1> keys;
|
|
if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.upperBound", keys)) {
|
|
return JS_FALSE;
|
|
}
|
|
NS_ASSERTION(keys.Length() == 1, "Didn't set all keys!");
|
|
|
|
JSBool open = JS_FALSE;
|
|
if (aArgc > 1 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[1], &open)) {
|
|
JS_ReportError(aCx, "Couldn't convert argument 2 to boolean.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
nsRefPtr<IDBKeyRange> range =
|
|
IDBKeyRange::Create(nsnull, keys[0], PR_TRUE, !!open);
|
|
NS_ASSERTION(range, "Out of memory?");
|
|
|
|
if (!ReturnKeyRange(aCx, aVp, range)) {
|
|
return JS_FALSE;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
JSBool
|
|
MakeBoundKeyRange(JSContext* aCx,
|
|
uintN aArgc,
|
|
jsval* aVp)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
nsAutoTArray<nsCOMPtr<nsIVariant>, 2> keys;
|
|
if (!ConvertArguments(aCx, aArgc, aVp, "IDBKeyRange.bound", keys)) {
|
|
return JS_FALSE;
|
|
}
|
|
NS_ASSERTION(keys.Length() == 2, "Didn't set all keys!");
|
|
|
|
JSBool lowerOpen = JS_FALSE;
|
|
if (aArgc > 2 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[2], &lowerOpen)) {
|
|
JS_ReportError(aCx, "Couldn't convert argument 3 to boolean.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
JSBool upperOpen = JS_FALSE;
|
|
if (aArgc > 3 && !JS_ValueToBoolean(aCx, JS_ARGV(aCx, aVp)[3], &upperOpen)) {
|
|
JS_ReportError(aCx, "Couldn't convert argument 3 to boolean.");
|
|
return JS_FALSE;
|
|
}
|
|
|
|
nsRefPtr<IDBKeyRange> range =
|
|
IDBKeyRange::Create(keys[0], keys[1], lowerOpen, upperOpen);
|
|
NS_ASSERTION(range, "Out of memory?");
|
|
|
|
if (!ReturnKeyRange(aCx, aVp, range)) {
|
|
return JS_FALSE;
|
|
}
|
|
|
|
return JS_TRUE;
|
|
}
|
|
|
|
|
|
#define KEYRANGE_FUNCTION_FLAGS (JSPROP_ENUMERATE | JSPROP_PERMANENT)
|
|
|
|
const JSFunctionSpec gKeyRangeConstructors[] = {
|
|
JS_FN("only", MakeOnlyKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
|
|
JS_FN("lowerBound", MakeLowerBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
|
|
JS_FN("upperBound", MakeUpperBoundKeyRange, 1, KEYRANGE_FUNCTION_FLAGS),
|
|
JS_FN("bound", MakeBoundKeyRange, 2, KEYRANGE_FUNCTION_FLAGS),
|
|
JS_FS_END
|
|
};
|
|
|
|
#undef KEYRANGE_FUNCTION_FLAGS
|
|
|
|
} // anonymous namespace
|
|
|
|
// static
|
|
JSBool
|
|
IDBKeyRange::DefineConstructors(JSContext* aCx,
|
|
JSObject* aObject)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
NS_ASSERTION(aCx, "Null pointer!");
|
|
NS_ASSERTION(aObject, "Null pointer!");
|
|
|
|
// Add the constructor methods for key ranges.
|
|
return JS_DefineFunctions(aCx, aObject,
|
|
const_cast<JSFunctionSpec*>(gKeyRangeConstructors));
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<IDBKeyRange>
|
|
IDBKeyRange::Create(nsIVariant* aLower,
|
|
nsIVariant* aUpper,
|
|
PRBool aLowerOpen,
|
|
PRBool aUpperOpen)
|
|
{
|
|
nsRefPtr<IDBKeyRange> keyRange(new IDBKeyRange());
|
|
keyRange->mLower = aLower;
|
|
keyRange->mUpper = aUpper;
|
|
keyRange->mLowerOpen = aLowerOpen;
|
|
keyRange->mUpperOpen = aUpperOpen;
|
|
|
|
return keyRange.forget();
|
|
}
|
|
|
|
NS_IMPL_ADDREF(IDBKeyRange)
|
|
NS_IMPL_RELEASE(IDBKeyRange)
|
|
|
|
NS_INTERFACE_MAP_BEGIN(IDBKeyRange)
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIDBKeyRange)
|
|
NS_INTERFACE_MAP_ENTRY(nsIIDBKeyRange)
|
|
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBKeyRange)
|
|
NS_INTERFACE_MAP_END
|
|
|
|
DOMCI_DATA(IDBKeyRange, IDBKeyRange)
|
|
|
|
NS_IMETHODIMP
|
|
IDBKeyRange::GetLower(nsIVariant** aLower)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
nsCOMPtr<nsIVariant> result(mLower);
|
|
result.forget(aLower);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
IDBKeyRange::GetUpper(nsIVariant** aUpper)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
nsCOMPtr<nsIVariant> result(mUpper);
|
|
result.forget(aUpper);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
IDBKeyRange::GetLowerOpen(PRBool* aLowerOpen)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
*aLowerOpen = mLowerOpen ? PR_TRUE : PR_FALSE;
|
|
return NS_OK;
|
|
}
|
|
|
|
|
|
NS_IMETHODIMP
|
|
IDBKeyRange::GetUpperOpen(PRBool* aUpperOpen)
|
|
{
|
|
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
|
|
|
*aUpperOpen = mUpperOpen ? PR_TRUE : PR_FALSE;
|
|
return NS_OK;
|
|
}
|