tor-browser

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

Printer.h (22960B)


      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 js_Printer_h
      8 #define js_Printer_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/glue/Debug.h"
     12 #include "mozilla/Range.h"
     13 #include "mozilla/Vector.h"
     14 
     15 #include <stdarg.h>
     16 #include <stddef.h>
     17 #include <stdio.h>
     18 #include <string.h>
     19 
     20 #include "js/TypeDecls.h"
     21 #include "js/Utility.h"
     22 
     23 // [SMDOC] *Printer, Sprinter, Fprinter, ...
     24 //
     25 // # Motivation
     26 //
     27 // In many places, we want to have functions which are capable of logging
     28 // various data structures. Previously, we had logging functions for each
     29 // storage, such as using `fwrite`, `printf` or `snprintf`. In additional cases,
     30 // many of these logging options were using a string serializing logging
     31 // function, only to discard the allocated string after it had been copied to a
     32 // file.
     33 //
     34 // GenericPrinter is an answer to avoid excessive amount of temporary
     35 // allocations which are used once, and a way to make logging functions work
     36 // independently of the backend they are used with.
     37 //
     38 // # Design
     39 //
     40 // The GenericPrinter implements most of `put`, `printf`, `vprintf` and
     41 // `putChar` functions, which are implemented using `put` and `putChar`
     42 // functions in the derivative classes. Thus, one does not have to reimplement
     43 // `putString` nor `printf` for each printer.
     44 //
     45 //   // Logging the value N to whatever printer is provided such as
     46 //   // a file or a string.
     47 //   void logN(GenericPrinter& out) {
     48 //     out.printf("[Logging] %d\n", this->n);
     49 //   }
     50 //
     51 // The printing functions are infallible, from the logging functions
     52 // perspective. If an issue happens while printing, this would be recorded by
     53 // the Printer, and this can be tested using `hadOutOfMemory` function by the
     54 // owner of the Printer instance.
     55 //
     56 // Even in case of failure, printing functions should remain safe to use. Thus
     57 // calling `put` twice in a row is safe even if no check for `hadOutOfMemory` is
     58 // performed. This is necessary to simplify the control flow and avoid bubble up
     59 // failures out of logging functions.
     60 //
     61 // Note, being safe to use does not imply correctness. In case of failure the
     62 // correctness of the printed characters is no longer guarantee. One should use
     63 // `hadOutOfMemory` function to know if any failure happened which might have
     64 // caused incorrect content to be saved. In some cases, such as `Sprinter`,
     65 // where the string buffer can be extracted, the returned value would account
     66 // for checking `hadOutOfMemory`.
     67 //
     68 // # Implementations
     69 //
     70 // The GenericPrinter is a base class where the derivative classes are providing
     71 // different implementations which have their own advantages and disadvantages:
     72 //
     73 //  - Fprinter: FILE* printer. Write the content directly to a file.
     74 //
     75 //  - Sprinter: System allocator C-string buffer. Write the content to a buffer
     76 //    which is reallocated as more content is added. The buffer can then be
     77 //    extracted into a C-string or a JSString, respectively using `release` and
     78 //    `releaseJS`.
     79 //
     80 //  - LSprinter: LifoAlloc C-string rope. Write the content to a list of chunks
     81 //    in a LifoAlloc buffer, no-reallocation occur but one should use
     82 //    `exportInto` to serialize its content to a Sprinter or a Fprinter. This is
     83 //    useful to avoid reallocation copies, while using an existing LifoAlloc.
     84 //
     85 //  - SEPrinter: Roughly the same as Fprinter for stderr, except it goes through
     86 //    printf_stderr, which makes sure the output goes to a useful place: the
     87 //    Android log or the Windows debug output.
     88 //
     89 //  - EscapePrinter: Wrapper around other printers, to escape characters when
     90 //    necessary.
     91 //
     92 // # Print UTF-16
     93 //
     94 // The GenericPrinter only handle `char` inputs, which is good enough for ASCII
     95 // and Latin1 character sets. However, to handle UTF-16, one should use an
     96 // EscapePrinter as well as a policy for escaping characters.
     97 //
     98 // One might require different escaping policies based on the escape sequences
     99 // and based on the set of accepted character for the content generated. For
    100 // example, JSON does not specify \x<XX> escape sequences.
    101 //
    102 // Today the following escape policies exists:
    103 //
    104 //  - StringEscape: Produce C-like escape sequences: \<c>, \x<XX> and \u<XXXX>.
    105 //  - JSONEscape: Produce JSON escape sequences: \<c> and \u<XXXX>.
    106 //
    107 // An escape policy is defined by 2 functions:
    108 //
    109 //   bool isSafeChar(char16_t c):
    110 //     Returns whether a character can be printed without being escaped.
    111 //
    112 //   void convertInto(GenericPrinter& out, char16_t c):
    113 //     Calls the printer with the escape sequence for the character given as
    114 //     argument.
    115 //
    116 // To use an escape policy, the printer should be wrapped using an EscapePrinter
    117 // as follows:
    118 //
    119 //   {
    120 //     // The escaped string is surrounded by double-quotes, escape the double
    121 //     // quotes as well.
    122 //     StringEscape esc('"');
    123 //
    124 //     // Wrap our existing `GenericPrinter& out` using the `EscapePrinter`.
    125 //     EscapePrinter ep(out, esc);
    126 //
    127 //     // Append a sequence of characters which might contain UTF-16 characters.
    128 //     ep.put(chars);
    129 //   }
    130 //
    131 
    132 namespace js {
    133 
    134 class LifoAlloc;
    135 
    136 // Generic printf interface, similar to an ostream in the standard library.
    137 //
    138 // This class is useful to make generic printers which can work either with a
    139 // file backend, with a buffer allocated with an JSContext or a link-list
    140 // of chunks allocated with a LifoAlloc.
    141 class JS_PUBLIC_API GenericPrinter {
    142 protected:
    143  bool hadOOM_;  // whether setPendingOutOfMemory() has been called.
    144 
    145  constexpr GenericPrinter() : hadOOM_(false) {}
    146 
    147 public:
    148  // Puts |len| characters from |s| at the current position. This function might
    149  // silently fail and the error can be tested using `hadOutOfMemory()`. Calling
    150  // this function or any other printing functions after a failures is accepted,
    151  // but the outcome would still remain incorrect and `hadOutOfMemory()` would
    152  // still report any of the previous errors.
    153  virtual void put(const char* s, size_t len) = 0;
    154  inline void put(const char* s) { put(s, strlen(s)); }
    155  inline void put(mozilla::Span<const char> s) { put(s.data(), s.size()); };
    156 
    157  // Put a mozilla::Span / mozilla::Range of Latin1Char or char16_t characters
    158  // in the output.
    159  //
    160  // Note that the char16_t variant is expected to crash unless putChar is
    161  // overriden to handle properly the full set of WTF-16 character set.
    162  virtual void put(mozilla::Span<const JS::Latin1Char> str);
    163  virtual void put(mozilla::Span<const char16_t> str);
    164 
    165  // Same as the various put function but only appending a single character.
    166  //
    167  // Note that the char16_t variant is expected to crash unless putChar is
    168  // overriden to handle properly the full set of WTF-16 character set.
    169  virtual inline void putChar(const char c) { put(&c, 1); }
    170  virtual inline void putChar(const JS::Latin1Char c) { putChar(char(c)); }
    171  virtual inline void putChar(const char16_t c) {
    172    MOZ_CRASH("Use an EscapePrinter to handle all characters");
    173  }
    174 
    175  virtual void putString(JSContext* cx, JSString* str);
    176 
    177  // Prints a formatted string into the buffer.
    178  void printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
    179  void vprintf(const char* fmt, va_list ap) MOZ_FORMAT_PRINTF(2, 0);
    180 
    181  // In some cases, such as handling JSRopes in a less-quadratic worse-case,
    182  // it might be useful to copy content which has already been generated.
    183  //
    184  // If the buffer is back-readable, then this function should return `true`
    185  // and `putFromIndex` should be implemented to delegate to a `put` call at
    186  // the matching index and the corresponding length. To provide the index
    187  // argument of `putFromIndex`, the `index` method should also be implemented
    188  // to return the index within the inner buffer used by the printer.
    189  virtual bool canPutFromIndex() const { return false; }
    190 
    191  // Append to the current buffer, bytes which have previously been appended
    192  // before.
    193  virtual void putFromIndex(size_t index, size_t length) {
    194    MOZ_CRASH("Calls to putFromIndex should be guarded by canPutFromIndex.");
    195  }
    196 
    197  // When the printer has a seekable buffer and `canPutFromIndex` returns
    198  // `true`, this function can return the `index` of the next character to be
    199  // added to the buffer.
    200  //
    201  // This function is monotonic. Thus, if the printer encounter an
    202  // Out-Of-Memory issue, then the returned index should be the maximal value
    203  // ever returned.
    204  virtual size_t index() const { return 0; }
    205 
    206  // In some printers, this ensure that the content is fully written.
    207  virtual void flush() { /* Do nothing */ }
    208 
    209  // Set a flag that a string operation failed to get the memory it requested.
    210  // The pending out of memory error should be handled by the consumer.
    211  virtual void setPendingOutOfMemory();
    212 
    213  // Return true if this Sprinter ran out of memory.
    214  virtual bool hadOutOfMemory() const { return hadOOM_; }
    215 };
    216 
    217 // Sprintf / JSSprintf, but with unlimited and automatically allocated
    218 // buffering.
    219 class JS_PUBLIC_API StringPrinter : public GenericPrinter {
    220 public:
    221  // Check that the invariant holds at the entry and exit of a scope.
    222  struct InvariantChecker {
    223    const StringPrinter* parent;
    224 
    225    explicit InvariantChecker(const StringPrinter* p) : parent(p) {
    226      parent->checkInvariants();
    227    }
    228 
    229    ~InvariantChecker() { parent->checkInvariants(); }
    230  };
    231 
    232  JSContext* maybeCx;
    233 
    234 private:
    235  static const size_t DefaultSize;
    236 #ifdef DEBUG
    237  bool initialized;  // true if this is initialized, use for debug builds
    238 #endif
    239  bool shouldReportOOM;  // whether to report OOM to the maybeCx
    240  char* base;            // malloc'd buffer address
    241  size_t size;           // size of buffer allocated at base
    242  ptrdiff_t offset;      // offset of next free char in buffer
    243 
    244  // The arena to be used by jemalloc to allocate the string into. This is
    245  // selected by the child classes when calling the constructor. JSStrings have
    246  // a different arena than strings which do not belong to the JS engine, and as
    247  // such when building a JSString with the intent of avoiding reallocation, the
    248  // destination arena has to be selected upfront.
    249  arena_id_t arena;
    250 
    251 private:
    252  [[nodiscard]] bool realloc_(size_t newSize);
    253 
    254 protected:
    255  // JSContext* parameter is optional and can be omitted if the following
    256  // are not used.
    257  //   * putString method with JSString
    258  //   * QuoteString function with JSString
    259  //   * JSONQuoteString function with JSString
    260  //
    261  // If JSContext* parameter is not provided, or shouldReportOOM is false,
    262  // the consumer should manually report OOM on any failure.
    263  explicit StringPrinter(arena_id_t arena, JSContext* maybeCx = nullptr,
    264                         bool shouldReportOOM = true);
    265  ~StringPrinter();
    266 
    267  JS::UniqueChars releaseChars();
    268  JSString* releaseJS(JSContext* cx);
    269 
    270 public:
    271  // Initialize this sprinter, returns false on error.
    272  [[nodiscard]] bool init();
    273 
    274  void checkInvariants() const;
    275 
    276  // Attempt to reserve len + 1 space (for a trailing nullptr byte). If the
    277  // attempt succeeds, return a pointer to the start of that space and adjust
    278  // the internal content. The caller *must* completely fill this space on
    279  // success.
    280  char* reserve(size_t len);
    281 
    282  // Puts |len| characters from |s| at the current position. May OOM, which must
    283  // be checked by testing the return value of releaseJS() at the end of
    284  // printing.
    285  virtual void put(const char* s, size_t len) final;
    286  using GenericPrinter::put;  // pick up |put(const char* s);|
    287 
    288  virtual bool canPutFromIndex() const final { return true; }
    289  virtual void putFromIndex(size_t index, size_t length) final {
    290    MOZ_ASSERT(index <= this->index());
    291    MOZ_ASSERT(index + length <= this->index());
    292    put(base + index, length);
    293  }
    294  virtual size_t index() const final { return length(); }
    295 
    296  virtual void putString(JSContext* cx, JSString* str) final;
    297 
    298  size_t length() const;
    299 
    300  // When an OOM has already been reported on the Sprinter, this function will
    301  // forward this error to the JSContext given in the Sprinter initialization.
    302  //
    303  // If no JSContext had been provided or the Sprinter is configured to not
    304  // report OOM, then nothing happens.
    305  void forwardOutOfMemory();
    306 };
    307 
    308 class JS_PUBLIC_API Sprinter : public StringPrinter {
    309 public:
    310  explicit Sprinter(JSContext* maybeCx = nullptr, bool shouldReportOOM = true)
    311      : StringPrinter(js::MallocArena, maybeCx, shouldReportOOM) {}
    312  ~Sprinter() {}
    313 
    314  JS::UniqueChars release() { return releaseChars(); }
    315 };
    316 
    317 class JS_PUBLIC_API JSSprinter : public StringPrinter {
    318 public:
    319  explicit JSSprinter(JSContext* cx)
    320      : StringPrinter(js::StringBufferArena, cx, true) {}
    321  ~JSSprinter() {}
    322 
    323  JSString* release(JSContext* cx) { return releaseJS(cx); }
    324 };
    325 
    326 // FixedBufferPrinter, print to a fixed-size buffer. The string in the buffer
    327 // will always be null-terminated after being passed to the constructor.
    328 class FixedBufferPrinter final : public GenericPrinter {
    329 private:
    330  // The first char in the buffer where put will append the next string
    331  char* buffer_;
    332  // The remaining size available in the buffer
    333  size_t size_;
    334 
    335 public:
    336  constexpr FixedBufferPrinter(char* buf, size_t size)
    337      : buffer_(buf), size_(size) {
    338    MOZ_ASSERT(buffer_);
    339    memset(buffer_, 0, size_);
    340  }
    341 
    342  // Puts |len| characters from |s| at the current position.
    343  // If the buffer fills up, this won't do anything.
    344  void put(const char* s, size_t len) override;
    345  using GenericPrinter::put;  // pick up |put(const char* s);|
    346 };
    347 
    348 // Fprinter, print a string directly into a file.
    349 class JS_PUBLIC_API Fprinter final : public GenericPrinter {
    350 private:
    351  FILE* file_;
    352  bool init_;
    353 
    354 public:
    355  explicit Fprinter(FILE* fp);
    356 
    357  constexpr Fprinter() : file_(nullptr), init_(false) {}
    358 
    359 #ifdef DEBUG
    360  ~Fprinter();
    361 #endif
    362 
    363  // Initialize this printer, returns false on error.
    364  [[nodiscard]] bool init(const char* path);
    365  void init(FILE* fp);
    366  bool isInitialized() const { return file_ != nullptr; }
    367  void flush() override;
    368  void finish();
    369 
    370  // Puts |len| characters from |s| at the current position. Errors may be
    371  // detected with hadOutOfMemory() (which will be set for any fwrite() error,
    372  // not just OOM.)
    373  void put(const char* s, size_t len) override;
    374  using GenericPrinter::put;  // pick up |put(const char* s);|
    375 };
    376 
    377 // SEprinter, print using printf_stderr (goes to Android log, Windows debug,
    378 // else just stderr).
    379 class SEprinter final : public GenericPrinter {
    380 public:
    381  constexpr SEprinter() {}
    382 
    383  // Puts |len| characters from |s| at the current position. Ignores errors.
    384  virtual void put(const char* s, size_t len) override {
    385    printf_stderr("%.*s", int(len), s);
    386  }
    387  using GenericPrinter::put;  // pick up |put(const char* s);|
    388 };
    389 
    390 // LSprinter, is similar to Sprinter except that instead of using an
    391 // JSContext to allocate strings, it use a LifoAlloc as a backend for the
    392 // allocation of the chunk of the string.
    393 class JS_PUBLIC_API LSprinter final : public GenericPrinter {
    394 private:
    395  struct Chunk {
    396    Chunk* next;
    397    size_t length;
    398 
    399    char* chars() { return reinterpret_cast<char*>(this + 1); }
    400    char* end() { return chars() + length; }
    401  };
    402 
    403 private:
    404  LifoAlloc* alloc_;  // LifoAlloc used as a backend of chunk allocations.
    405  Chunk* head_;
    406  Chunk* tail_;
    407  size_t unused_;
    408 
    409 public:
    410  explicit LSprinter(LifoAlloc* lifoAlloc);
    411  ~LSprinter();
    412 
    413  // Copy the content of the chunks into another printer, such that we can
    414  // flush the content of this printer to a file.
    415  void exportInto(GenericPrinter& out) const;
    416 
    417  // Drop the current string, and let them be free with the LifoAlloc.
    418  void clear();
    419 
    420  // Puts |len| characters from |s| at the current position.
    421  virtual void put(const char* s, size_t len) override;
    422  using GenericPrinter::put;  // pick up |put(const char* s);|
    423 };
    424 
    425 // Escaping printers work like any other printer except that any added character
    426 // are checked for escaping sequences. This one would escape a string such that
    427 // it can safely be embedded in a JS string.
    428 template <typename Delegate, typename Escape>
    429 class JS_PUBLIC_API EscapePrinter final : public GenericPrinter {
    430  size_t lengthOfSafeChars(const char* s, size_t len) {
    431    for (size_t i = 0; i < len; i++) {
    432      if (!esc.isSafeChar(uint8_t(s[i]))) {
    433        return i;
    434      }
    435    }
    436    return len;
    437  }
    438 
    439 private:
    440  Delegate& out;
    441  Escape& esc;
    442 
    443 public:
    444  EscapePrinter(Delegate& out, Escape& esc) : out(out), esc(esc) {}
    445  ~EscapePrinter() {}
    446 
    447  using GenericPrinter::put;
    448  void put(const char* s, size_t len) override {
    449    const char* b = s;
    450    while (len) {
    451      size_t index = lengthOfSafeChars(b, len);
    452      if (index) {
    453        out.put(b, index);
    454        len -= index;
    455        b += index;
    456      }
    457      if (len) {
    458        esc.convertInto(out, char16_t(uint8_t(*b)));
    459        len -= 1;
    460        b += 1;
    461      }
    462    }
    463  }
    464 
    465  inline void putChar(const char c) override {
    466    if (esc.isSafeChar(char16_t(uint8_t(c)))) {
    467      out.putChar(char(c));
    468      return;
    469    }
    470    esc.convertInto(out, char16_t(uint8_t(c)));
    471  }
    472 
    473  inline void putChar(const JS::Latin1Char c) override {
    474    if (esc.isSafeChar(char16_t(c))) {
    475      out.putChar(char(c));
    476      return;
    477    }
    478    esc.convertInto(out, char16_t(c));
    479  }
    480 
    481  inline void putChar(const char16_t c) override {
    482    if (esc.isSafeChar(c)) {
    483      out.putChar(char(c));
    484      return;
    485    }
    486    esc.convertInto(out, c);
    487  }
    488 
    489  // Forward calls to delegated printer.
    490  bool canPutFromIndex() const override { return out.canPutFromIndex(); }
    491  void putFromIndex(size_t index, size_t length) final {
    492    out.putFromIndex(index, length);
    493  }
    494  size_t index() const final { return out.index(); }
    495  void flush() final { out.flush(); }
    496  void setPendingOutOfMemory() final { out.setPendingOutOfMemory(); }
    497  bool hadOutOfMemory() const final { return out.hadOutOfMemory(); }
    498 };
    499 
    500 class JS_PUBLIC_API JSONEscape {
    501 public:
    502  bool isSafeChar(char16_t c);
    503  void convertInto(GenericPrinter& out, char16_t c);
    504 };
    505 
    506 class JS_PUBLIC_API StringEscape {
    507 private:
    508  const char quote = '\0';
    509 
    510 public:
    511  explicit StringEscape(const char quote = '\0') : quote(quote) {}
    512 
    513  bool isSafeChar(char16_t c);
    514  void convertInto(GenericPrinter& out, char16_t c);
    515 };
    516 
    517 class JS_PUBLIC_API WATStringEscape {
    518 public:
    519  bool isSafeChar(char16_t c);
    520  void convertInto(GenericPrinter& out, char16_t c);
    521 };
    522 
    523 // A GenericPrinter that can format its output in a structured way, with nice
    524 // formatting.
    525 //
    526 // Suppose you want to print wasm structs, and you want to change the
    527 // presentation depending on the number of fields:
    528 //
    529 //   (struct)
    530 //   (struct (field i32))
    531 //   (struct
    532 //     (field i32)
    533 //     (field i64)
    534 //   )
    535 //
    536 // All three of these can be handled identically with quite straightforward
    537 // code:
    538 //
    539 //   out.printf("(struct");
    540 //   {
    541 //     StructuredPrinter::Scope _(out);
    542 //
    543 //     for (auto field : fields) {
    544 //       out.brk(" ", "\n");
    545 //       out.printf("(field ");
    546 //       DumpFieldType(field.type, out);
    547 //       out.printf(")");
    548 //     }
    549 //     out.brk("", "\n");
    550 //
    551 //     if (fields.length() > 1) {
    552 //       out.expand();
    553 //     }
    554 //   }
    555 //   out.printf(")");
    556 //
    557 // The `brk` method can be used to emit one of two "break" characters depending
    558 // on whether the output is "expanded" or "collapsed". The decision about which
    559 // style to emit is made later, by conditionally calling `out.expand()`.
    560 // Additionally, the use of `StructuredPrinter::Scope` ensures that the struct
    561 // fields are indented *if* the output is expanded.
    562 //
    563 // Newlines may still be printed at any time. Newlines will force the current
    564 // scope to be expanded, along with any parent scopes.
    565 class JS_PUBLIC_API StructuredPrinter final : public GenericPrinter {
    566  GenericPrinter& out_;
    567 
    568  // The number of spaces to insert for each indent.
    569  int indentAmount_;
    570  bool pendingIndent_;
    571 
    572  // The index of the last expanded scope (or -1 if all scopes are collapsed).
    573  int expandedDepth_ = -1;
    574 
    575  struct Break {
    576    uint32_t bufferPos;
    577    bool isCollapsed;
    578    const char* collapsed;
    579    const char* expanded;
    580  };
    581 
    582  struct ScopeInfo {
    583    uint32_t startPos;
    584    int indent;
    585  };
    586 
    587  // Content is buffered while in collapsed mode in case it gets expanded later.
    588  mozilla::Vector<char, 80> buffer_;
    589  // Info about break characters in the buffer.
    590  // Cleared when the buffer is cleared.
    591  mozilla::Vector<Break, 8> breaks_;
    592  // The stack of scopes maintained by the printer.
    593  mozilla::Vector<ScopeInfo, 16> scopes_;
    594 
    595  int scopeDepth() { return int(scopes_.length()) - 1; }
    596 
    597  void putIndent(int level = -1);
    598  void putBreak(const Break& brk);
    599  void putWithMaybeIndent(const char* s, size_t len, int level = -1);
    600 
    601 public:
    602  explicit StructuredPrinter(GenericPrinter& out, int indentAmount = 2)
    603      : out_(out), indentAmount_(indentAmount) {
    604    pushScope();
    605  }
    606  ~StructuredPrinter() {
    607    popScope();
    608    flush();
    609  }
    610 
    611  void pushScope();
    612  void popScope();
    613 
    614  void brk(const char* collapsed, const char* expanded);
    615  void expand();
    616  bool isExpanded();
    617 
    618  void flush() override;
    619 
    620  class Scope {
    621    StructuredPrinter& printer_;
    622 
    623   public:
    624    explicit Scope(StructuredPrinter& printer) : printer_(printer) {
    625      printer_.pushScope();
    626    }
    627    ~Scope() { printer_.popScope(); }
    628  };
    629 
    630  virtual void put(const char* s, size_t len) override;
    631  using GenericPrinter::put;  // pick up |inline void put(const char* s);|
    632 };
    633 
    634 // Map escaped code to the letter/symbol escaped with a backslash.
    635 extern const char js_EscapeMap[];
    636 
    637 // Return a C-string containing the chars in str, with any non-printing chars
    638 // escaped. If the optional quote parameter is present and is not '\0', quotes
    639 // (as specified by the quote argument) are also escaped, and the quote
    640 // character is appended at the beginning and end of the result string.
    641 // The returned string is guaranteed to contain only ASCII characters.
    642 extern JS_PUBLIC_API JS::UniqueChars QuoteString(JSContext* cx, JSString* str,
    643                                                 char quote = '\0');
    644 
    645 // Appends the quoted string to the given Sprinter. Follows the same semantics
    646 // as QuoteString from above.
    647 extern JS_PUBLIC_API void QuoteString(Sprinter* sp, JSString* str,
    648                                      char quote = '\0');
    649 
    650 // Appends the quoted string to the given Sprinter. Follows the same
    651 // Appends the JSON quoted string to the given Sprinter.
    652 extern JS_PUBLIC_API void JSONQuoteString(StringPrinter* sp, JSString* str);
    653 
    654 // Internal implementation code for QuoteString methods above.
    655 enum class QuoteTarget { String, JSON };
    656 
    657 template <QuoteTarget target, typename CharT>
    658 void JS_PUBLIC_API QuoteString(Sprinter* sp,
    659                               const mozilla::Range<const CharT>& chars,
    660                               char quote = '\0');
    661 
    662 }  // namespace js
    663 
    664 #endif  // js_Printer_h