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/. */
7 #ifndef mozilla_dom_indexeddb_key_h__
8 #define mozilla_dom_indexeddb_key_h__
10 #include "mozilla/dom/indexedDB/IDBResult.h"
12 #include "js/RootingAPI.h"
13 #include "js/TypeDecls.h"
16 class mozIStorageStatement
;
17 class mozIStorageValueArray
;
31 friend struct IPC::ParamTraits
<Key
>;
46 static const uint8_t kMaxArrayCollapse
= uint8_t(3);
47 static const uint8_t kMaxRecursionDepth
= uint8_t(64);
51 explicit Key(nsCString aBuffer
) : mBuffer(std::move(aBuffer
)) {}
53 Key
& operator=(int64_t aInt
) {
58 bool operator==(const Key
& aOther
) const {
59 MOZ_ASSERT(!mBuffer
.IsVoid());
60 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
62 return mBuffer
.Equals(aOther
.mBuffer
);
65 bool operator!=(const Key
& aOther
) const {
66 MOZ_ASSERT(!mBuffer
.IsVoid());
67 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
69 return !mBuffer
.Equals(aOther
.mBuffer
);
72 bool operator<(const Key
& aOther
) const {
73 MOZ_ASSERT(!mBuffer
.IsVoid());
74 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
76 return Compare(mBuffer
, aOther
.mBuffer
) < 0;
79 bool operator>(const Key
& aOther
) const {
80 MOZ_ASSERT(!mBuffer
.IsVoid());
81 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
83 return Compare(mBuffer
, aOther
.mBuffer
) > 0;
86 bool operator<=(const Key
& aOther
) const {
87 MOZ_ASSERT(!mBuffer
.IsVoid());
88 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
90 return Compare(mBuffer
, aOther
.mBuffer
) <= 0;
93 bool operator>=(const Key
& aOther
) const {
94 MOZ_ASSERT(!mBuffer
.IsVoid());
95 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
97 return Compare(mBuffer
, aOther
.mBuffer
) >= 0;
100 void Unset() { mBuffer
.SetIsVoid(true); }
102 bool IsUnset() const { return mBuffer
.IsVoid(); }
104 bool IsFloat() const { return !IsUnset() && *BufferStart() == eFloat
; }
106 bool IsDate() const { return !IsUnset() && *BufferStart() == eDate
; }
108 bool IsString() const { return !IsUnset() && *BufferStart() == eString
; }
110 bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary
; }
112 bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray
; }
114 double ToFloat() const {
115 MOZ_ASSERT(IsFloat());
116 const EncodedDataType
* pos
= BufferStart();
117 double res
= DecodeNumber(pos
, BufferEnd());
118 MOZ_ASSERT(pos
>= BufferEnd());
122 double ToDateMsec() const {
123 MOZ_ASSERT(IsDate());
124 const EncodedDataType
* pos
= BufferStart();
125 double res
= DecodeNumber(pos
, BufferEnd());
126 MOZ_ASSERT(pos
>= BufferEnd());
130 nsAutoString
ToString() const {
131 MOZ_ASSERT(IsString());
132 const EncodedDataType
* pos
= BufferStart();
133 auto res
= DecodeString(pos
, BufferEnd());
134 MOZ_ASSERT(pos
>= BufferEnd());
138 Result
<Ok
, nsresult
> SetFromString(const nsAString
& aString
);
140 void SetFromInteger(int64_t aInt
) {
142 EncodeNumber(double(aInt
), eFloat
);
146 // This function implements the standard algorithm "convert a value to a key".
147 // A key return value is indicated by returning `true` whereas `false` means
148 // either invalid (if `aRv.Failed()` is `false`) or an exception (otherwise).
149 IDBResult
<Ok
, IDBSpecialValue::Invalid
> SetFromJSVal(
150 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
);
152 nsresult
ToJSVal(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
) const;
154 nsresult
ToJSVal(JSContext
* aCx
, JS::Heap
<JS::Value
>& aVal
) const;
156 // See SetFromJSVal() for the meaning of values returned by this function.
157 IDBResult
<Ok
, IDBSpecialValue::Invalid
> AppendItem(
158 JSContext
* aCx
, bool aFirstOfArray
, JS::Handle
<JS::Value
> aVal
);
160 Result
<Key
, nsresult
> ToLocaleAwareKey(const nsCString
& aLocale
) const;
162 void FinishArray() { TrimBuffer(); }
164 const nsCString
& GetBuffer() const { return mBuffer
; }
166 nsresult
BindToStatement(mozIStorageStatement
* aStatement
,
167 const nsACString
& aParamName
) const;
169 nsresult
SetFromStatement(mozIStorageStatement
* aStatement
, uint32_t aIndex
);
171 nsresult
SetFromValueArray(mozIStorageValueArray
* aValues
, uint32_t aIndex
);
173 static int16_t CompareKeys(const Key
& aFirst
, const Key
& aSecond
) {
174 int32_t result
= Compare(aFirst
.mBuffer
, aSecond
.mBuffer
);
188 class MOZ_STACK_CLASS ArrayValueEncoder
;
190 using EncodedDataType
= unsigned char;
192 const EncodedDataType
* BufferStart() const {
193 // TODO it would be nicer if mBuffer was also using EncodedDataType
194 return reinterpret_cast<const EncodedDataType
*>(mBuffer
.BeginReading());
197 const EncodedDataType
* BufferEnd() const {
198 return reinterpret_cast<const EncodedDataType
*>(mBuffer
.EndReading());
201 // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
204 const char* end
= mBuffer
.EndReading() - 1;
209 mBuffer
.Truncate(end
+ 1 - mBuffer
.BeginReading());
212 // Encoding functions. These append the encoded value to the end of mBuffer
213 IDBResult
<Ok
, IDBSpecialValue::Invalid
> EncodeJSVal(
214 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
, uint8_t aTypeOffset
);
216 Result
<Ok
, nsresult
> EncodeString(const nsAString
& aString
,
217 uint8_t aTypeOffset
);
219 template <typename T
>
220 Result
<Ok
, nsresult
> EncodeString(Span
<const T
> aInput
, uint8_t aTypeOffset
);
222 template <typename T
>
223 Result
<Ok
, nsresult
> EncodeAsString(Span
<const T
> aInput
, uint8_t aType
);
225 Result
<Ok
, nsresult
> EncodeLocaleString(const nsAString
& aString
,
227 const nsCString
& aLocale
);
229 void EncodeNumber(double aFloat
, uint8_t aType
);
231 Result
<Ok
, nsresult
> EncodeBinary(JSObject
* aObject
, bool aIsViewObject
,
232 uint8_t aTypeOffset
);
234 // Decoding functions. aPos points into mBuffer and is adjusted to point
235 // past the consumed value. (Note: this may be beyond aEnd).
236 static nsresult
DecodeJSVal(const EncodedDataType
*& aPos
,
237 const EncodedDataType
* aEnd
, JSContext
* aCx
,
238 JS::MutableHandle
<JS::Value
> aVal
);
240 static nsAutoString
DecodeString(const EncodedDataType
*& aPos
,
241 const EncodedDataType
* aEnd
);
243 static double DecodeNumber(const EncodedDataType
*& aPos
,
244 const EncodedDataType
* aEnd
);
246 static JSObject
* DecodeBinary(const EncodedDataType
*& aPos
,
247 const EncodedDataType
* aEnd
, JSContext
* aCx
);
249 // Returns the size of the decoded data for stringy (string or binary),
250 // excluding a null terminator.
251 // On return, aOutSectionEnd points to the last byte behind the current
252 // encoded section, i.e. either aEnd, or the eTerminator.
253 // T is the base type for the decoded data.
254 template <typename T
>
255 static uint32_t CalcDecodedStringySize(
256 const EncodedDataType
* aBegin
, const EncodedDataType
* aEnd
,
257 const EncodedDataType
** aOutEncodedSectionEnd
);
259 static uint32_t LengthOfEncodedBinary(const EncodedDataType
* aPos
,
260 const EncodedDataType
* aEnd
);
262 template <typename T
>
263 static void DecodeAsStringy(const EncodedDataType
* aEncodedSectionBegin
,
264 const EncodedDataType
* aEncodedSectionEnd
,
265 uint32_t aDecodedLength
, T
* aOut
);
267 template <EncodedDataType TypeMask
, typename T
, typename AcquireBuffer
,
268 typename AcquireEmpty
>
269 static void DecodeStringy(const EncodedDataType
*& aPos
,
270 const EncodedDataType
* aEnd
,
271 const AcquireBuffer
& acquireBuffer
,
272 const AcquireEmpty
& acquireEmpty
);
274 IDBResult
<Ok
, IDBSpecialValue::Invalid
> EncodeJSValInternal(
275 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
, uint8_t aTypeOffset
,
276 uint16_t aRecursionDepth
);
278 static nsresult
DecodeJSValInternal(const EncodedDataType
*& aPos
,
279 const EncodedDataType
* aEnd
,
280 JSContext
* aCx
, uint8_t aTypeOffset
,
281 JS::MutableHandle
<JS::Value
> aVal
,
282 uint16_t aRecursionDepth
);
284 template <typename T
>
285 nsresult
SetFromSource(T
* aSource
, uint32_t aIndex
);
288 } // namespace indexedDB
290 } // namespace mozilla
292 #endif // mozilla_dom_indexeddb_key_h__