tor-browser

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

nsJSUtils.h (7485B)


      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 nsJSUtils_h__
      8 #define nsJSUtils_h__
      9 
     10 /**
     11 * This is not a generated file. It contains common utility functions
     12 * invoked from the JavaScript code generated from IDL interfaces.
     13 * The goal of the utility functions is to cut down on the size of
     14 * the generated code itself.
     15 */
     16 
     17 #include "js/CompileOptions.h"
     18 #include "js/Conversions.h"
     19 #include "js/String.h"  // JS::{,Lossy}CopyLinearStringChars, JS::CopyStringChars, JS::Get{,Linear}StringLength, JS::MaxStringLength, JS::StringHasLatin1Chars
     20 #include "js/Utility.h"  // JS::FreePolicy
     21 #include "jsapi.h"
     22 #include "mozilla/Assertions.h"
     23 #include "nsString.h"
     24 #include "xpcpublic.h"
     25 
     26 class nsIScriptContext;
     27 class nsIScriptElement;
     28 class nsIScriptGlobalObject;
     29 class nsXBLPrototypeBinding;
     30 
     31 namespace JS {
     32 class JS_PUBLIC_API EnvironmentChain;
     33 };
     34 
     35 namespace mozilla {
     36 union Utf8Unit;
     37 
     38 namespace dom {
     39 class AutoJSAPI;
     40 class Element;
     41 }  // namespace dom
     42 }  // namespace mozilla
     43 
     44 class nsJSUtils {
     45 public:
     46  /**
     47   * Retrieve the inner window ID based on the given JSContext.
     48   *
     49   * @param JSContext aContext
     50   *        The JSContext from which you want to find the inner window ID.
     51   *
     52   * @returns uint64_t the inner window ID.
     53   */
     54  static uint64_t GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext);
     55 
     56  static nsresult CompileFunction(mozilla::dom::AutoJSAPI& jsapi,
     57                                  const JS::EnvironmentChain& aEnvChain,
     58                                  JS::CompileOptions& aOptions,
     59                                  const nsACString& aName, uint32_t aArgCount,
     60                                  const char** aArgArray,
     61                                  const nsAString& aBody,
     62                                  JSObject** aFunctionObject);
     63 
     64  static nsresult UpdateFunctionDebugMetadata(
     65      mozilla::dom::AutoJSAPI& jsapi, JS::Handle<JSObject*> aFun,
     66      JS::CompileOptions& aOptions, JS::Handle<JSString*> aElementAttributeName,
     67      JS::Handle<JS::Value> aPrivateValue);
     68 
     69  static bool IsScriptable(JS::Handle<JSObject*> aEvaluationGlobal);
     70 
     71  // Returns false if an exception got thrown on aCx.  Passing a null
     72  // aElement is allowed; that wil produce an empty aEnvChain.
     73  static bool GetEnvironmentChainForElement(JSContext* aCx,
     74                                            mozilla::dom::Element* aElement,
     75                                            JS::EnvironmentChain& aEnvChain);
     76 
     77  static void ResetTimeZone();
     78 
     79  static bool DumpEnabled();
     80 
     81  // A helper function that receives buffer pointer, creates ArrayBuffer, and
     82  // convert it to Uint8Array.
     83  // Note that the buffer needs to be created by JS_malloc (or at least can be
     84  // freed by JS_free), as the resulting Uint8Array takes the ownership of the
     85  // buffer.
     86  static JSObject* MoveBufferAsUint8Array(
     87      JSContext* aCx, size_t aSize,
     88      mozilla::UniquePtr<uint8_t[], JS::FreePolicy> aBuffer);
     89 };
     90 
     91 template <typename T, typename std::enable_if_t<std::is_same<
     92                          typename T::char_type, char16_t>::value>* = nullptr>
     93 inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
     94  size_t len = JS::GetStringLength(s);
     95  static_assert(JS::MaxStringLength < (1 << 30),
     96                "Shouldn't overflow here or in SetCapacity");
     97 
     98  if (XPCStringConvert::MaybeAssignUCStringChars(s, len, dest)) {
     99    return true;
    100  }
    101 
    102  // We don't bother checking for a dynamic-atom external string, because we'd
    103  // just need to copy out of it anyway.
    104 
    105  if (MOZ_UNLIKELY(!dest.SetLength(len, mozilla::fallible))) {
    106    JS_ReportOutOfMemory(cx);
    107    return false;
    108  }
    109  return JS::CopyStringChars(cx, dest.BeginWriting(), s, len);
    110 }
    111 
    112 // Specialization for UTF8String.
    113 template <typename T, typename std::enable_if_t<std::is_same<
    114                          typename T::char_type, char>::value>* = nullptr>
    115 inline bool AssignJSString(JSContext* cx, T& dest, JSString* s) {
    116  using namespace mozilla;
    117  CheckedInt<size_t> bufLen(JS::GetStringLength(s));
    118 
    119  if (XPCStringConvert::MaybeAssignUTF8StringChars(s, bufLen.value(), dest)) {
    120    return true;
    121  }
    122 
    123  // From the contract for JS_EncodeStringToUTF8BufferPartial, to guarantee that
    124  // the whole string is converted.
    125  if (JS::StringHasLatin1Chars(s)) {
    126    bufLen *= 2;
    127  } else {
    128    bufLen *= 3;
    129  }
    130 
    131  if (MOZ_UNLIKELY(!bufLen.isValid())) {
    132    JS_ReportOutOfMemory(cx);
    133    return false;
    134  }
    135 
    136  // Shouldn't really matter, but worth being safe.
    137  const bool kAllowShrinking = true;
    138 
    139  auto handleOrErr = dest.BulkWrite(bufLen.value(), 0, kAllowShrinking);
    140  if (MOZ_UNLIKELY(handleOrErr.isErr())) {
    141    JS_ReportOutOfMemory(cx);
    142    return false;
    143  }
    144 
    145  auto handle = handleOrErr.unwrap();
    146 
    147  auto maybe = JS_EncodeStringToUTF8BufferPartial(cx, s, handle.AsSpan());
    148  if (MOZ_UNLIKELY(!maybe)) {
    149    JS_ReportOutOfMemory(cx);
    150    return false;
    151  }
    152 
    153  size_t read;
    154  size_t written;
    155  std::tie(read, written) = *maybe;
    156 
    157  MOZ_ASSERT(read == JS::GetStringLength(s));
    158  handle.Finish(written, kAllowShrinking);
    159  return true;
    160 }
    161 
    162 inline void AssignJSLinearString(nsAString& dest, JSLinearString* s) {
    163  size_t len = JS::GetLinearStringLength(s);
    164  static_assert(JS::MaxStringLength < (1 << 30),
    165                "Shouldn't overflow here or in SetCapacity");
    166  dest.SetLength(len);
    167  JS::CopyLinearStringChars(dest.BeginWriting(), s, len);
    168 }
    169 
    170 inline void AssignJSLinearString(nsACString& dest, JSLinearString* s) {
    171  size_t len = JS::GetLinearStringLength(s);
    172  static_assert(JS::MaxStringLength < (1 << 30),
    173                "Shouldn't overflow here or in SetCapacity");
    174  dest.SetLength(len);
    175  JS::LossyCopyLinearStringChars(dest.BeginWriting(), s, len);
    176 }
    177 
    178 template <typename T>
    179 class nsTAutoJSLinearString : public nsTAutoString<T> {
    180 public:
    181  explicit nsTAutoJSLinearString(JSLinearString* str) {
    182    AssignJSLinearString(*this, str);
    183  }
    184 };
    185 
    186 using nsAutoJSLinearString = nsTAutoJSLinearString<char16_t>;
    187 using nsAutoJSLinearCString = nsTAutoJSLinearString<char>;
    188 
    189 template <typename T>
    190 class nsTAutoJSString : public nsTAutoString<T> {
    191 public:
    192  /**
    193   * nsTAutoJSString should be default constructed, which leaves it empty
    194   * (this->IsEmpty()), and initialized with one of the init() methods below.
    195   */
    196  nsTAutoJSString() = default;
    197 
    198  bool init(JSContext* aContext, JSString* str) {
    199    return AssignJSString(aContext, *this, str);
    200  }
    201 
    202  bool init(JSContext* aContext, const JS::Value& v) {
    203    if (v.isString()) {
    204      return init(aContext, v.toString());
    205    }
    206 
    207    // Stringify, making sure not to run script.
    208    JS::Rooted<JSString*> str(aContext);
    209    if (v.isObject()) {
    210      str = JS_NewStringCopyZ(aContext, "[Object]");
    211    } else {
    212      JS::Rooted<JS::Value> rootedVal(aContext, v);
    213      str = JS::ToString(aContext, rootedVal);
    214    }
    215 
    216    return str && init(aContext, str);
    217  }
    218 
    219  bool init(JSContext* aContext, jsid id) {
    220    JS::Rooted<JS::Value> v(aContext);
    221    return JS_IdToValue(aContext, id, &v) && init(aContext, v);
    222  }
    223 
    224  bool init(const JS::Value& v);
    225 
    226  ~nsTAutoJSString() = default;
    227 };
    228 
    229 using nsAutoJSString = nsTAutoJSString<char16_t>;
    230 
    231 // Note that this is guaranteed to be UTF-8.
    232 using nsAutoJSCString = nsTAutoJSString<char>;
    233 
    234 #endif /* nsJSUtils_h__ */