tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Key.h (9528B)


      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/. */
      6 
      7 #ifndef mozilla_dom_indexeddb_key_h__
      8 #define mozilla_dom_indexeddb_key_h__
      9 
     10 #include "mozilla/dom/indexedDB/IDBResult.h"
     11 
     12 class mozIStorageStatement;
     13 class mozIStorageValueArray;
     14 
     15 namespace IPC {
     16 
     17 template <typename>
     18 struct ParamTraits;
     19 
     20 }  // namespace IPC
     21 
     22 namespace JS {
     23 class ArrayBufferOrView;
     24 class AutoCheckCannotGC;
     25 }  // namespace JS
     26 
     27 namespace mozilla::dom::indexedDB {
     28 
     29 class Key {
     30  friend struct IPC::ParamTraits<Key>;
     31 
     32  nsCString mBuffer;
     33  CopyableTArray<uint32_t> mAutoIncrementKeyOffsets;
     34 
     35 public:
     36  enum {
     37    eTerminator = 0,
     38    eFloat = 0x10,
     39    eDate = 0x20,
     40    eString = 0x30,
     41    eBinary = 0x40,
     42    eArray = 0x50,
     43    eMaxType = eArray
     44  };
     45 
     46  static const uint8_t kMaxArrayCollapse = uint8_t(3);
     47  static const uint8_t kMaxRecursionDepth = uint8_t(64);
     48 
     49  Key() { Unset(); }
     50 
     51  explicit Key(nsCString aBuffer) : mBuffer(std::move(aBuffer)) {}
     52 
     53  bool operator==(const Key& aOther) const {
     54    MOZ_ASSERT(!mBuffer.IsVoid());
     55    MOZ_ASSERT(!aOther.mBuffer.IsVoid());
     56 
     57    return mBuffer.Equals(aOther.mBuffer);
     58  }
     59 
     60  bool operator!=(const Key& aOther) const {
     61    MOZ_ASSERT(!mBuffer.IsVoid());
     62    MOZ_ASSERT(!aOther.mBuffer.IsVoid());
     63 
     64    return !mBuffer.Equals(aOther.mBuffer);
     65  }
     66 
     67  bool operator<(const Key& aOther) const {
     68    MOZ_ASSERT(!mBuffer.IsVoid());
     69    MOZ_ASSERT(!aOther.mBuffer.IsVoid());
     70 
     71    return Compare(mBuffer, aOther.mBuffer) < 0;
     72  }
     73 
     74  bool operator>(const Key& aOther) const {
     75    MOZ_ASSERT(!mBuffer.IsVoid());
     76    MOZ_ASSERT(!aOther.mBuffer.IsVoid());
     77 
     78    return Compare(mBuffer, aOther.mBuffer) > 0;
     79  }
     80 
     81  bool operator<=(const Key& aOther) const {
     82    MOZ_ASSERT(!mBuffer.IsVoid());
     83    MOZ_ASSERT(!aOther.mBuffer.IsVoid());
     84 
     85    return Compare(mBuffer, aOther.mBuffer) <= 0;
     86  }
     87 
     88  bool operator>=(const Key& aOther) const {
     89    MOZ_ASSERT(!mBuffer.IsVoid());
     90    MOZ_ASSERT(!aOther.mBuffer.IsVoid());
     91 
     92    return Compare(mBuffer, aOther.mBuffer) >= 0;
     93  }
     94 
     95  void Unset() {
     96    mBuffer.SetIsVoid(true);
     97    mAutoIncrementKeyOffsets.Clear();
     98  }
     99 
    100  bool IsUnset() const { return mBuffer.IsVoid(); }
    101 
    102  bool IsFloat() const { return !IsUnset() && *BufferStart() == eFloat; }
    103 
    104  bool IsDate() const { return !IsUnset() && *BufferStart() == eDate; }
    105 
    106  bool IsString() const { return !IsUnset() && *BufferStart() == eString; }
    107 
    108  bool IsBinary() const { return !IsUnset() && *BufferStart() == eBinary; }
    109 
    110  bool IsArray() const { return !IsUnset() && *BufferStart() >= eArray; }
    111 
    112  double ToFloat() const {
    113    MOZ_ASSERT(IsFloat());
    114    const EncodedDataType* pos = BufferStart();
    115    double res = DecodeNumber(pos, BufferEnd());
    116    MOZ_ASSERT(pos >= BufferEnd());
    117    return res;
    118  }
    119 
    120  double ToDateMsec() const {
    121    MOZ_ASSERT(IsDate());
    122    const EncodedDataType* pos = BufferStart();
    123    double res = DecodeNumber(pos, BufferEnd());
    124    MOZ_ASSERT(pos >= BufferEnd());
    125    return res;
    126  }
    127 
    128  nsAutoString ToString() const {
    129    MOZ_ASSERT(IsString());
    130    const EncodedDataType* pos = BufferStart();
    131    auto res = DecodeString(pos, BufferEnd());
    132    MOZ_ASSERT(pos >= BufferEnd());
    133    return res;
    134  }
    135 
    136  Result<Ok, nsresult> SetFromString(const nsAString& aString);
    137 
    138  Result<Ok, nsresult> SetFromInteger(int64_t aInt) {
    139    mBuffer.Truncate();
    140    auto ret = EncodeNumber(double(aInt), eFloat);
    141    TrimBuffer();
    142    return ret;
    143  }
    144 
    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);
    150 
    151  nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) const;
    152 
    153  nsresult ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aVal) const;
    154 
    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);
    158 
    159  Result<Key, nsresult> ToLocaleAwareKey(const nsCString& aLocale) const;
    160 
    161  void FinishArray() { TrimBuffer(); }
    162 
    163  const nsCString& GetBuffer() const { return mBuffer; }
    164 
    165  nsresult BindToStatement(mozIStorageStatement* aStatement,
    166                           const nsACString& aParamName) const;
    167 
    168  nsresult SetFromStatement(mozIStorageStatement* aStatement, uint32_t aIndex);
    169 
    170  nsresult SetFromValueArray(mozIStorageValueArray* aValues, uint32_t aIndex);
    171 
    172  static int16_t CompareKeys(const Key& aFirst, const Key& aSecond) {
    173    int32_t result = Compare(aFirst.mBuffer, aSecond.mBuffer);
    174 
    175    if (result < 0) {
    176      return -1;
    177    }
    178 
    179    if (result > 0) {
    180      return 1;
    181    }
    182 
    183    return 0;
    184  }
    185 
    186  void ReserveAutoIncrementKey(bool aFirstOfArray);
    187 
    188  void MaybeUpdateAutoIncrementKey(int64_t aKey);
    189 
    190 private:
    191  class MOZ_STACK_CLASS ArrayValueEncoder;
    192 
    193  using EncodedDataType = unsigned char;
    194 
    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());
    198  }
    199 
    200  const EncodedDataType* BufferEnd() const {
    201    return reinterpret_cast<const EncodedDataType*>(mBuffer.EndReading());
    202  }
    203 
    204  // Encoding helper. Trims trailing zeros off of mBuffer as a post-processing
    205  // step.
    206  void TrimBuffer() {
    207    const char* end = mBuffer.EndReading() - 1;
    208    while (!*end) {
    209      --end;
    210    }
    211 
    212    mBuffer.Truncate(end + 1 - mBuffer.BeginReading());
    213  }
    214 
    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);
    218 
    219  Result<Ok, nsresult> EncodeString(const nsAString& aString,
    220                                    uint8_t aTypeOffset);
    221 
    222  template <typename T>
    223  Result<Ok, nsresult> EncodeString(Span<const T> aInput, uint8_t aTypeOffset);
    224 
    225  template <typename T>
    226  Result<Ok, nsresult> EncodeAsString(Span<const T> aInput,
    227                                      JS::AutoCheckCannotGC&& aNoGC,
    228                                      uint8_t aType);
    229 
    230  Result<Ok, nsresult> EncodeLocaleString(const nsAString& aString,
    231                                          uint8_t aTypeOffset,
    232                                          const nsCString& aLocale);
    233 
    234  Result<Ok, nsresult> EncodeNumber(double aFloat, uint8_t aType);
    235 
    236  Result<Ok, nsresult> EncodeBinary(
    237      const JS::ArrayBufferOrView& aArrayBufferOrView, uint8_t aTypeOffset);
    238 
    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);
    244 
    245  static nsAutoString DecodeString(const EncodedDataType*& aPos,
    246                                   const EncodedDataType* aEnd);
    247 
    248  static double DecodeNumber(const EncodedDataType*& aPos,
    249                             const EncodedDataType* aEnd);
    250 
    251  static JSObject* DecodeBinary(const EncodedDataType*& aPos,
    252                                const EncodedDataType* aEnd, JSContext* aCx);
    253 
    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);
    263 
    264  static uint32_t LengthOfEncodedBinary(const EncodedDataType* aPos,
    265                                        const EncodedDataType* aEnd);
    266 
    267  template <typename T>
    268  static void DecodeAsStringy(const EncodedDataType* aEncodedSectionBegin,
    269                              const EncodedDataType* aEncodedSectionEnd,
    270                              uint32_t aDecodedLength, T* aOut);
    271 
    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);
    278 
    279  IDBResult<Ok, IDBSpecialValue::Invalid> EncodeJSValInternal(
    280      JSContext* aCx, JS::Handle<JS::Value> aVal, uint8_t aTypeOffset,
    281      uint16_t aRecursionDepth);
    282 
    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);
    288 
    289  template <typename T>
    290  nsresult SetFromSource(T* aSource, uint32_t aIndex);
    291 
    292  void WriteDoubleToUint64(char* aBuffer, double aValue);
    293 };
    294 
    295 }  // namespace mozilla::dom::indexedDB
    296 
    297 #endif  // mozilla_dom_indexeddb_key_h__