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 class mozIStorageStatement
;
13 class mozIStorageValueArray
;
23 class ArrayBufferOrView
;
24 class AutoCheckCannotGC
;
27 namespace mozilla::dom::indexedDB
{
30 friend struct IPC::ParamTraits
<Key
>;
33 CopyableTArray
<uint32_t> mAutoIncrementKeyOffsets
;
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 bool operator==(const Key
& aOther
) const {
54 MOZ_ASSERT(!mBuffer
.IsVoid());
55 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
57 return mBuffer
.Equals(aOther
.mBuffer
);
60 bool operator!=(const Key
& aOther
) const {
61 MOZ_ASSERT(!mBuffer
.IsVoid());
62 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
64 return !mBuffer
.Equals(aOther
.mBuffer
);
67 bool operator<(const Key
& aOther
) const {
68 MOZ_ASSERT(!mBuffer
.IsVoid());
69 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
71 return Compare(mBuffer
, aOther
.mBuffer
) < 0;
74 bool operator>(const Key
& aOther
) const {
75 MOZ_ASSERT(!mBuffer
.IsVoid());
76 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
78 return Compare(mBuffer
, aOther
.mBuffer
) > 0;
81 bool operator<=(const Key
& aOther
) const {
82 MOZ_ASSERT(!mBuffer
.IsVoid());
83 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
85 return Compare(mBuffer
, aOther
.mBuffer
) <= 0;
88 bool operator>=(const Key
& aOther
) const {
89 MOZ_ASSERT(!mBuffer
.IsVoid());
90 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
92 return Compare(mBuffer
, aOther
.mBuffer
) >= 0;
96 mBuffer
.SetIsVoid(true);
97 mAutoIncrementKeyOffsets
.Clear();
100 bool IsUnset() const { return mBuffer
.IsVoid(); }
102 bool IsFloat() const { return !IsUnset() && *BufferStart() == eFloat
; }
104 bool IsDate() const { return !IsUnset() && *BufferStart() == eDate
; }
106 bool IsString() const { return !IsUnset() && *BufferStart() == eString
; }
108 bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary
; }
110 bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray
; }
112 double ToFloat() const {
113 MOZ_ASSERT(IsFloat());
114 const EncodedDataType
* pos
= BufferStart();
115 double res
= DecodeNumber(pos
, BufferEnd());
116 MOZ_ASSERT(pos
>= BufferEnd());
120 double ToDateMsec() const {
121 MOZ_ASSERT(IsDate());
122 const EncodedDataType
* pos
= BufferStart();
123 double res
= DecodeNumber(pos
, BufferEnd());
124 MOZ_ASSERT(pos
>= BufferEnd());
128 nsAutoString
ToString() const {
129 MOZ_ASSERT(IsString());
130 const EncodedDataType
* pos
= BufferStart();
131 auto res
= DecodeString(pos
, BufferEnd());
132 MOZ_ASSERT(pos
>= BufferEnd());
136 Result
<Ok
, nsresult
> SetFromString(const nsAString
& aString
);
138 Result
<Ok
, nsresult
> SetFromInteger(int64_t aInt
) {
140 auto ret
= EncodeNumber(double(aInt
), eFloat
);
145 // This function implements the standard algorithm "convert a value to a key".
146 // A key return value is indicated by returning `true` whereas `false` means
147 // either invalid (if `aRv.Failed()` is `false`) or an exception (otherwise).
148 IDBResult
<Ok
, IDBSpecialValue::Invalid
> SetFromJSVal(
149 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
);
151 nsresult
ToJSVal(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
) const;
153 nsresult
ToJSVal(JSContext
* aCx
, JS::Heap
<JS::Value
>& aVal
) const;
155 // See SetFromJSVal() for the meaning of values returned by this function.
156 IDBResult
<Ok
, IDBSpecialValue::Invalid
> AppendItem(
157 JSContext
* aCx
, bool aFirstOfArray
, JS::Handle
<JS::Value
> aVal
);
159 Result
<Key
, nsresult
> ToLocaleAwareKey(const nsCString
& aLocale
) const;
161 void FinishArray() { TrimBuffer(); }
163 const nsCString
& GetBuffer() const { return mBuffer
; }
165 nsresult
BindToStatement(mozIStorageStatement
* aStatement
,
166 const nsACString
& aParamName
) const;
168 nsresult
SetFromStatement(mozIStorageStatement
* aStatement
, uint32_t aIndex
);
170 nsresult
SetFromValueArray(mozIStorageValueArray
* aValues
, uint32_t aIndex
);
172 static int16_t CompareKeys(const Key
& aFirst
, const Key
& aSecond
) {
173 int32_t result
= Compare(aFirst
.mBuffer
, aSecond
.mBuffer
);
186 void ReserveAutoIncrementKey(bool aFirstOfArray
);
188 void MaybeUpdateAutoIncrementKey(int64_t aKey
);
191 class MOZ_STACK_CLASS ArrayValueEncoder
;
193 using EncodedDataType
= unsigned char;
195 const EncodedDataType
* BufferStart() const {
196 // TODO it would be nicer if mBuffer was also using EncodedDataType
197 return reinterpret_cast<const EncodedDataType
*>(mBuffer
.BeginReading());
200 const EncodedDataType
* BufferEnd() const {
201 return reinterpret_cast<const EncodedDataType
*>(mBuffer
.EndReading());
204 // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
207 const char* end
= mBuffer
.EndReading() - 1;
212 mBuffer
.Truncate(end
+ 1 - mBuffer
.BeginReading());
215 // Encoding functions. These append the encoded value to the end of mBuffer
216 IDBResult
<Ok
, IDBSpecialValue::Invalid
> EncodeJSVal(
217 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
, uint8_t aTypeOffset
);
219 Result
<Ok
, nsresult
> EncodeString(const nsAString
& aString
,
220 uint8_t aTypeOffset
);
222 template <typename T
>
223 Result
<Ok
, nsresult
> EncodeString(Span
<const T
> aInput
, uint8_t aTypeOffset
);
225 template <typename T
>
226 Result
<Ok
, nsresult
> EncodeAsString(Span
<const T
> aInput
,
227 JS::AutoCheckCannotGC
&& aNoGC
,
230 Result
<Ok
, nsresult
> EncodeLocaleString(const nsAString
& aString
,
232 const nsCString
& aLocale
);
234 Result
<Ok
, nsresult
> EncodeNumber(double aFloat
, uint8_t aType
);
236 Result
<Ok
, nsresult
> EncodeBinary(
237 const JS::ArrayBufferOrView
& aArrayBufferOrView
, uint8_t aTypeOffset
);
239 // Decoding functions. aPos points into mBuffer and is adjusted to point
240 // past the consumed value. (Note: this may be beyond aEnd).
241 static nsresult
DecodeJSVal(const EncodedDataType
*& aPos
,
242 const EncodedDataType
* aEnd
, JSContext
* aCx
,
243 JS::MutableHandle
<JS::Value
> aVal
);
245 static nsAutoString
DecodeString(const EncodedDataType
*& aPos
,
246 const EncodedDataType
* aEnd
);
248 static double DecodeNumber(const EncodedDataType
*& aPos
,
249 const EncodedDataType
* aEnd
);
251 static JSObject
* DecodeBinary(const EncodedDataType
*& aPos
,
252 const EncodedDataType
* aEnd
, JSContext
* aCx
);
254 // Returns the size of the decoded data for stringy (string or binary),
255 // excluding a null terminator.
256 // On return, aOutSectionEnd points to the last byte behind the current
257 // encoded section, i.e. either aEnd, or the eTerminator.
258 // T is the base type for the decoded data.
259 template <typename T
>
260 static uint32_t CalcDecodedStringySize(
261 const EncodedDataType
* aBegin
, const EncodedDataType
* aEnd
,
262 const EncodedDataType
** aOutEncodedSectionEnd
);
264 static uint32_t LengthOfEncodedBinary(const EncodedDataType
* aPos
,
265 const EncodedDataType
* aEnd
);
267 template <typename T
>
268 static void DecodeAsStringy(const EncodedDataType
* aEncodedSectionBegin
,
269 const EncodedDataType
* aEncodedSectionEnd
,
270 uint32_t aDecodedLength
, T
* aOut
);
272 template <EncodedDataType TypeMask
, typename T
, typename AcquireBuffer
,
273 typename AcquireEmpty
>
274 static void DecodeStringy(const EncodedDataType
*& aPos
,
275 const EncodedDataType
* aEnd
,
276 const AcquireBuffer
& acquireBuffer
,
277 const AcquireEmpty
& acquireEmpty
);
279 IDBResult
<Ok
, IDBSpecialValue::Invalid
> EncodeJSValInternal(
280 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
, uint8_t aTypeOffset
,
281 uint16_t aRecursionDepth
);
283 static nsresult
DecodeJSValInternal(const EncodedDataType
*& aPos
,
284 const EncodedDataType
* aEnd
,
285 JSContext
* aCx
, uint8_t aTypeOffset
,
286 JS::MutableHandle
<JS::Value
> aVal
,
287 uint16_t aRecursionDepth
);
289 template <typename T
>
290 nsresult
SetFromSource(T
* aSource
, uint32_t aIndex
);
292 void WriteDoubleToUint64(char* aBuffer
, double aValue
);
295 } // namespace mozilla::dom::indexedDB
297 #endif // mozilla_dom_indexeddb_key_h__