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
;
22 namespace mozilla::dom::indexedDB
{
25 friend struct IPC::ParamTraits
<Key
>;
40 static const uint8_t kMaxArrayCollapse
= uint8_t(3);
41 static const uint8_t kMaxRecursionDepth
= uint8_t(64);
45 explicit Key(nsCString aBuffer
) : mBuffer(std::move(aBuffer
)) {}
47 bool operator==(const Key
& aOther
) const {
48 MOZ_ASSERT(!mBuffer
.IsVoid());
49 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
51 return mBuffer
.Equals(aOther
.mBuffer
);
54 bool operator!=(const Key
& aOther
) const {
55 MOZ_ASSERT(!mBuffer
.IsVoid());
56 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
58 return !mBuffer
.Equals(aOther
.mBuffer
);
61 bool operator<(const Key
& aOther
) const {
62 MOZ_ASSERT(!mBuffer
.IsVoid());
63 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
65 return Compare(mBuffer
, aOther
.mBuffer
) < 0;
68 bool operator>(const Key
& aOther
) const {
69 MOZ_ASSERT(!mBuffer
.IsVoid());
70 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
72 return Compare(mBuffer
, aOther
.mBuffer
) > 0;
75 bool operator<=(const Key
& aOther
) const {
76 MOZ_ASSERT(!mBuffer
.IsVoid());
77 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
79 return Compare(mBuffer
, aOther
.mBuffer
) <= 0;
82 bool operator>=(const Key
& aOther
) const {
83 MOZ_ASSERT(!mBuffer
.IsVoid());
84 MOZ_ASSERT(!aOther
.mBuffer
.IsVoid());
86 return Compare(mBuffer
, aOther
.mBuffer
) >= 0;
89 void Unset() { mBuffer
.SetIsVoid(true); }
91 bool IsUnset() const { return mBuffer
.IsVoid(); }
93 bool IsFloat() const { return !IsUnset() && *BufferStart() == eFloat
; }
95 bool IsDate() const { return !IsUnset() && *BufferStart() == eDate
; }
97 bool IsString() const { return !IsUnset() && *BufferStart() == eString
; }
99 bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary
; }
101 bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray
; }
103 double ToFloat() const {
104 MOZ_ASSERT(IsFloat());
105 const EncodedDataType
* pos
= BufferStart();
106 double res
= DecodeNumber(pos
, BufferEnd());
107 MOZ_ASSERT(pos
>= BufferEnd());
111 double ToDateMsec() const {
112 MOZ_ASSERT(IsDate());
113 const EncodedDataType
* pos
= BufferStart();
114 double res
= DecodeNumber(pos
, BufferEnd());
115 MOZ_ASSERT(pos
>= BufferEnd());
119 nsAutoString
ToString() const {
120 MOZ_ASSERT(IsString());
121 const EncodedDataType
* pos
= BufferStart();
122 auto res
= DecodeString(pos
, BufferEnd());
123 MOZ_ASSERT(pos
>= BufferEnd());
127 Result
<Ok
, nsresult
> SetFromString(const nsAString
& aString
);
129 Result
<Ok
, nsresult
> SetFromInteger(int64_t aInt
) {
131 auto ret
= EncodeNumber(double(aInt
), eFloat
);
136 // This function implements the standard algorithm "convert a value to a key".
137 // A key return value is indicated by returning `true` whereas `false` means
138 // either invalid (if `aRv.Failed()` is `false`) or an exception (otherwise).
139 IDBResult
<Ok
, IDBSpecialValue::Invalid
> SetFromJSVal(
140 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
);
142 nsresult
ToJSVal(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
) const;
144 nsresult
ToJSVal(JSContext
* aCx
, JS::Heap
<JS::Value
>& aVal
) const;
146 // See SetFromJSVal() for the meaning of values returned by this function.
147 IDBResult
<Ok
, IDBSpecialValue::Invalid
> AppendItem(
148 JSContext
* aCx
, bool aFirstOfArray
, JS::Handle
<JS::Value
> aVal
);
150 Result
<Key
, nsresult
> ToLocaleAwareKey(const nsCString
& aLocale
) const;
152 void FinishArray() { TrimBuffer(); }
154 const nsCString
& GetBuffer() const { return mBuffer
; }
156 nsresult
BindToStatement(mozIStorageStatement
* aStatement
,
157 const nsACString
& aParamName
) const;
159 nsresult
SetFromStatement(mozIStorageStatement
* aStatement
, uint32_t aIndex
);
161 nsresult
SetFromValueArray(mozIStorageValueArray
* aValues
, uint32_t aIndex
);
163 static int16_t CompareKeys(const Key
& aFirst
, const Key
& aSecond
) {
164 int32_t result
= Compare(aFirst
.mBuffer
, aSecond
.mBuffer
);
178 class MOZ_STACK_CLASS ArrayValueEncoder
;
180 using EncodedDataType
= unsigned char;
182 const EncodedDataType
* BufferStart() const {
183 // TODO it would be nicer if mBuffer was also using EncodedDataType
184 return reinterpret_cast<const EncodedDataType
*>(mBuffer
.BeginReading());
187 const EncodedDataType
* BufferEnd() const {
188 return reinterpret_cast<const EncodedDataType
*>(mBuffer
.EndReading());
191 // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
194 const char* end
= mBuffer
.EndReading() - 1;
199 mBuffer
.Truncate(end
+ 1 - mBuffer
.BeginReading());
202 // Encoding functions. These append the encoded value to the end of mBuffer
203 IDBResult
<Ok
, IDBSpecialValue::Invalid
> EncodeJSVal(
204 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
, uint8_t aTypeOffset
);
206 Result
<Ok
, nsresult
> EncodeString(const nsAString
& aString
,
207 uint8_t aTypeOffset
);
209 template <typename T
>
210 Result
<Ok
, nsresult
> EncodeString(Span
<const T
> aInput
, uint8_t aTypeOffset
);
212 template <typename T
>
213 Result
<Ok
, nsresult
> EncodeAsString(Span
<const T
> aInput
, uint8_t aType
);
215 Result
<Ok
, nsresult
> EncodeLocaleString(const nsAString
& aString
,
217 const nsCString
& aLocale
);
219 Result
<Ok
, nsresult
> EncodeNumber(double aFloat
, uint8_t aType
);
221 Result
<Ok
, nsresult
> EncodeBinary(JSObject
* aObject
, bool aIsViewObject
,
222 uint8_t aTypeOffset
);
224 // Decoding functions. aPos points into mBuffer and is adjusted to point
225 // past the consumed value. (Note: this may be beyond aEnd).
226 static nsresult
DecodeJSVal(const EncodedDataType
*& aPos
,
227 const EncodedDataType
* aEnd
, JSContext
* aCx
,
228 JS::MutableHandle
<JS::Value
> aVal
);
230 static nsAutoString
DecodeString(const EncodedDataType
*& aPos
,
231 const EncodedDataType
* aEnd
);
233 static double DecodeNumber(const EncodedDataType
*& aPos
,
234 const EncodedDataType
* aEnd
);
236 static JSObject
* DecodeBinary(const EncodedDataType
*& aPos
,
237 const EncodedDataType
* aEnd
, JSContext
* aCx
);
239 // Returns the size of the decoded data for stringy (string or binary),
240 // excluding a null terminator.
241 // On return, aOutSectionEnd points to the last byte behind the current
242 // encoded section, i.e. either aEnd, or the eTerminator.
243 // T is the base type for the decoded data.
244 template <typename T
>
245 static uint32_t CalcDecodedStringySize(
246 const EncodedDataType
* aBegin
, const EncodedDataType
* aEnd
,
247 const EncodedDataType
** aOutEncodedSectionEnd
);
249 static uint32_t LengthOfEncodedBinary(const EncodedDataType
* aPos
,
250 const EncodedDataType
* aEnd
);
252 template <typename T
>
253 static void DecodeAsStringy(const EncodedDataType
* aEncodedSectionBegin
,
254 const EncodedDataType
* aEncodedSectionEnd
,
255 uint32_t aDecodedLength
, T
* aOut
);
257 template <EncodedDataType TypeMask
, typename T
, typename AcquireBuffer
,
258 typename AcquireEmpty
>
259 static void DecodeStringy(const EncodedDataType
*& aPos
,
260 const EncodedDataType
* aEnd
,
261 const AcquireBuffer
& acquireBuffer
,
262 const AcquireEmpty
& acquireEmpty
);
264 IDBResult
<Ok
, IDBSpecialValue::Invalid
> EncodeJSValInternal(
265 JSContext
* aCx
, JS::Handle
<JS::Value
> aVal
, uint8_t aTypeOffset
,
266 uint16_t aRecursionDepth
);
268 static nsresult
DecodeJSValInternal(const EncodedDataType
*& aPos
,
269 const EncodedDataType
* aEnd
,
270 JSContext
* aCx
, uint8_t aTypeOffset
,
271 JS::MutableHandle
<JS::Value
> aVal
,
272 uint16_t aRecursionDepth
);
274 template <typename T
>
275 nsresult
SetFromSource(T
* aSource
, uint32_t aIndex
);
278 } // namespace mozilla::dom::indexedDB
280 #endif // mozilla_dom_indexeddb_key_h__