2010-11-10 15:26:00 -08:00
|
|
|
/* -*- 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 ***** */
|
|
|
|
|
|
|
|
#ifndef mozilla_dom_indexeddb_key_h__
|
|
|
|
#define mozilla_dom_indexeddb_key_h__
|
|
|
|
|
|
|
|
#include "mozilla/dom/indexedDB/IndexedDatabase.h"
|
|
|
|
|
2011-11-03 08:57:30 -07:00
|
|
|
#include "mozIStorageStatement.h"
|
|
|
|
|
2010-11-10 15:26:00 -08:00
|
|
|
BEGIN_INDEXEDDB_NAMESPACE
|
|
|
|
|
|
|
|
class Key
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Key()
|
|
|
|
{
|
2011-11-03 08:57:30 -07:00
|
|
|
Unset();
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
Key& operator=(const nsAString& aString)
|
|
|
|
{
|
2011-11-03 08:57:30 -07:00
|
|
|
SetFromString(aString);
|
2010-11-10 15:26:00 -08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Key& operator=(PRInt64 aInt)
|
|
|
|
{
|
2011-11-03 08:57:30 -07:00
|
|
|
SetFromInteger(aInt);
|
2010-11-10 15:26:00 -08:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator==(const Key& aOther) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
|
2011-11-03 08:57:30 -07:00
|
|
|
"Don't compare unset keys!");
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
return mBuffer.Equals(aOther.mBuffer);
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const Key& aOther) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
|
|
|
|
"Don't compare unset keys!");
|
|
|
|
|
|
|
|
return !mBuffer.Equals(aOther.mBuffer);
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator<(const Key& aOther) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
|
2011-11-03 08:57:30 -07:00
|
|
|
"Don't compare unset keys!");
|
2011-11-02 18:57:48 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
return Compare(mBuffer, aOther.mBuffer) < 0;
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator>(const Key& aOther) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
|
|
|
|
"Don't compare unset keys!");
|
|
|
|
|
|
|
|
return Compare(mBuffer, aOther.mBuffer) > 0;
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
2010-12-09 18:15:00 -08:00
|
|
|
bool operator<=(const Key& aOther) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
|
|
|
|
"Don't compare unset keys!");
|
|
|
|
|
|
|
|
return Compare(mBuffer, aOther.mBuffer) <= 0;
|
2010-12-09 18:15:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool operator>=(const Key& aOther) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(!mBuffer.IsVoid() && !aOther.mBuffer.IsVoid(),
|
|
|
|
"Don't compare unset keys!");
|
|
|
|
|
|
|
|
return Compare(mBuffer, aOther.mBuffer) >= 0;
|
2010-12-09 18:15:00 -08:00
|
|
|
}
|
|
|
|
|
2011-11-03 08:57:30 -07:00
|
|
|
void
|
|
|
|
Unset()
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
mBuffer.SetIsVoid(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsUnset() const
|
|
|
|
{
|
|
|
|
return mBuffer.IsVoid();
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
bool IsFloat() const
|
|
|
|
{
|
|
|
|
return !mBuffer.IsVoid() && mBuffer.First() == eFloat;
|
|
|
|
}
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
double ToFloat() const
|
2011-11-03 08:57:30 -07:00
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
NS_ASSERTION(IsFloat(), "Why'd you call this?");
|
|
|
|
const unsigned char* pos = BufferStart();
|
|
|
|
double res = DecodeNumber(pos, BufferEnd());
|
|
|
|
NS_ASSERTION(pos >= BufferEnd(), "Should consume whole buffer");
|
|
|
|
return res;
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
void SetFromString(const nsAString& aString)
|
2011-11-03 08:57:30 -07:00
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
mBuffer.Truncate();
|
|
|
|
EncodeString(aString, 0);
|
|
|
|
TrimBuffer();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetFromInteger(PRInt64 aInt)
|
|
|
|
{
|
|
|
|
mBuffer.Truncate();
|
|
|
|
EncodeNumber(double(aInt), eFloat);
|
|
|
|
TrimBuffer();
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult SetFromJSVal(JSContext* aCx,
|
2011-12-20 02:58:44 -08:00
|
|
|
const jsval aVal)
|
2011-11-03 08:57:30 -07:00
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
mBuffer.Truncate();
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
if (JSVAL_IS_NULL(aVal) || JSVAL_IS_VOID(aVal)) {
|
|
|
|
Unset();
|
2011-11-03 08:57:30 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
nsresult rv = EncodeJSVal(aCx, aVal, 0);
|
|
|
|
if (NS_FAILED(rv)) {
|
2011-11-03 08:57:30 -07:00
|
|
|
Unset();
|
2011-12-20 02:58:44 -08:00
|
|
|
return rv;
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
2011-12-20 02:58:44 -08:00
|
|
|
TrimBuffer();
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
return NS_OK;
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult ToJSVal(JSContext* aCx,
|
|
|
|
jsval* aVal) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
if (IsUnset()) {
|
2011-11-03 08:57:30 -07:00
|
|
|
*aVal = JSVAL_VOID;
|
2011-12-20 02:58:44 -08:00
|
|
|
return NS_OK;
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
2010-11-10 15:26:00 -08:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
const unsigned char* pos = BufferStart();
|
|
|
|
nsresult rv = DecodeJSVal(pos, BufferEnd(), aCx, 0, aVal);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
NS_ASSERTION(pos >= BufferEnd(),
|
|
|
|
"Didn't consume whole buffer");
|
|
|
|
|
|
|
|
return NS_OK;
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:59:07 -08:00
|
|
|
nsresult AppendArrayItem(JSContext* aCx,
|
|
|
|
bool aFirst,
|
|
|
|
const jsval aVal)
|
|
|
|
{
|
|
|
|
if (aFirst) {
|
|
|
|
Unset();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = EncodeJSVal(aCx, aVal, aFirst ? eMaxType : 0);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
Unset();
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FinishArray()
|
|
|
|
{
|
|
|
|
TrimBuffer();
|
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
const nsCString& GetBuffer() const
|
2011-11-03 08:57:30 -07:00
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
return mBuffer;
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
2011-11-03 08:57:30 -07:00
|
|
|
nsresult BindToStatement(mozIStorageStatement* aStatement,
|
|
|
|
const nsACString& aParamName) const
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
nsresult rv = aStatement->BindBlobByName(aParamName,
|
|
|
|
reinterpret_cast<const PRUint8*>(mBuffer.get()), mBuffer.Length());
|
2011-11-03 08:57:30 -07:00
|
|
|
|
|
|
|
return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
2011-11-03 08:57:30 -07:00
|
|
|
nsresult SetFromStatement(mozIStorageStatement* aStatement,
|
|
|
|
PRUint32 aIndex)
|
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
PRUint8* data;
|
|
|
|
PRUint32 dataLength = 0;
|
|
|
|
|
|
|
|
nsresult rv = aStatement->GetBlob(aIndex, &dataLength, &data);
|
2011-11-03 08:57:30 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
mBuffer.Adopt(
|
|
|
|
reinterpret_cast<char*>(const_cast<PRUint8*>(data)), dataLength);
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
return NS_OK;
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
static
|
|
|
|
PRInt16 CompareKeys(Key& aFirst, Key& aSecond)
|
2011-11-03 08:57:30 -07:00
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
PRInt32 result = Compare(aFirst.mBuffer, aSecond.mBuffer);
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
if (result < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
if (result > 0) {
|
|
|
|
return 1;
|
2011-11-03 08:57:30 -07:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
return 0;
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
private:
|
|
|
|
const unsigned char* BufferStart() const
|
2011-11-03 08:57:30 -07:00
|
|
|
{
|
2011-12-20 02:58:44 -08:00
|
|
|
return reinterpret_cast<const unsigned char*>(mBuffer.BeginReading());
|
2010-11-10 15:26:00 -08:00
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
const unsigned char* BufferEnd() const
|
|
|
|
{
|
|
|
|
return reinterpret_cast<const unsigned char*>(mBuffer.EndReading());
|
|
|
|
}
|
|
|
|
|
|
|
|
enum {
|
|
|
|
eTerminator = 0,
|
|
|
|
eFloat = 1,
|
|
|
|
eDate = 2,
|
|
|
|
eString = 3,
|
|
|
|
eArray = 4,
|
|
|
|
eMaxType = eArray
|
2011-11-03 08:57:30 -07:00
|
|
|
};
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
// Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
|
|
|
|
// step.
|
|
|
|
void TrimBuffer()
|
|
|
|
{
|
|
|
|
const char* end = mBuffer.EndReading() - 1;
|
|
|
|
while (!*end) {
|
|
|
|
--end;
|
|
|
|
}
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
|
|
|
|
}
|
2011-11-03 08:57:30 -07:00
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
// Encoding functions. These append the encoded value to the end of mBuffer
|
2012-05-11 10:47:27 -07:00
|
|
|
inline nsresult EncodeJSVal(JSContext* aCx, const jsval aVal,
|
|
|
|
PRUint8 aTypeOffset)
|
|
|
|
{
|
|
|
|
return EncodeJSValInternal(aCx, aVal, aTypeOffset, 0);
|
|
|
|
}
|
2011-12-20 02:58:44 -08:00
|
|
|
void EncodeString(const nsAString& aString, PRUint8 aTypeOffset);
|
|
|
|
void EncodeNumber(double aFloat, PRUint8 aType);
|
|
|
|
|
|
|
|
// Decoding functions. aPos points into mBuffer and is adjusted to point
|
|
|
|
// past the consumed value.
|
2012-05-11 10:47:27 -07:00
|
|
|
static inline nsresult DecodeJSVal(const unsigned char*& aPos,
|
|
|
|
const unsigned char* aEnd, JSContext* aCx,
|
|
|
|
PRUint8 aTypeOffset, jsval* aVal)
|
|
|
|
{
|
|
|
|
return DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset, aVal, 0);
|
|
|
|
}
|
|
|
|
|
2011-12-20 02:58:44 -08:00
|
|
|
static void DecodeString(const unsigned char*& aPos,
|
|
|
|
const unsigned char* aEnd,
|
|
|
|
nsString& aString);
|
|
|
|
static double DecodeNumber(const unsigned char*& aPos,
|
|
|
|
const unsigned char* aEnd);
|
|
|
|
|
|
|
|
nsCString mBuffer;
|
2012-05-11 10:47:27 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
nsresult EncodeJSValInternal(JSContext* aCx, const jsval aVal,
|
|
|
|
PRUint8 aTypeOffset, PRUint16 aRecursionDepth);
|
|
|
|
|
|
|
|
static nsresult DecodeJSValInternal(const unsigned char*& aPos,
|
|
|
|
const unsigned char* aEnd,
|
|
|
|
JSContext* aCx, PRUint8 aTypeOffset,
|
|
|
|
jsval* aVal, PRUint16 aRecursionDepth);
|
2010-11-10 15:26:00 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
END_INDEXEDDB_NAMESPACE
|
|
|
|
|
|
|
|
#endif /* mozilla_dom_indexeddb_key_h__ */
|