docs: def py_scanstring(s, end, encoding=None, strict=True,
          _b=BACKSLASH, _m=STRINGCHUNK.match, _join=u('').join,
          _PY3=PY3, _maxunicode=sys.maxunicode):
      """Scan the string s for a JSON string. End is the index of the
      character in s after the quote that started the JSON string.
      Unescapes all valid JSON string escape sequences and raises ValueError
      on attempt to decode an invalid string. If strict is False then literal
      control characters are allowed in the string.
  
      Returns a tuple of the decoded string and the index of the character in s
      after the end quote."""
      if encoding is None:
          encoding = DEFAULT_ENCODING
      chunks = []
      _append = chunks.append
      begin = end - 1
      while 1:
          chunk = _m(s, end)
          if chunk is None:
              raise JSONDecodeError(
                  "Unterminated string starting at", s, begin)
          end = chunk.end()
          content, terminator = chunk.groups()
          # Content is contains zero or more unescaped string characters
          if content:
              if not _PY3 and not isinstance(content, text_type):
                  content = text_type(content, encoding)
              _append(content)
          # Terminator is the end of string, a literal control character,
          # or a backslash denoting that an escape sequence follows
          if terminator == '"':
              break
          elif terminator != '\\':
              if strict:
                  msg = "Invalid control character %r at"
                  raise JSONDecodeError(msg, s, end)
              else:
                  _append(terminator)
                  continue
          try:
              esc = s[end]
          except IndexError:
              raise JSONDecodeError(
                  "Unterminated string starting at", s, begin)
          # If not a unicode escape sequence, must be in the lookup table
          if esc != 'u':
              try:
                  char = _b[esc]
              except KeyError:
                  msg = "Invalid \\X escape sequence %r"
                  raise JSONDecodeError(msg, s, end)
              end += 1
          else:
              # Unicode escape sequence
              msg = "Invalid \\uXXXX escape sequence"
              esc = s[end + 1:end + 5]
              escX = esc[1:2]
              if len(esc) != 4 or escX == 'x' or escX == 'X':
                  raise JSONDecodeError(msg, s, end - 1)
              try:
                  uni = int(esc, 16)
              except ValueError:
                  raise JSONDecodeError(msg, s, end - 1)
              end += 5
              # Check for surrogate pair on UCS-4 systems
              # Note that this will join high/low surrogate pairs
              # but will also pass unpaired surrogates through
              if (_maxunicode > 65535 and
                  uni & 0xfc00 == 0xd800 and
                  s[end:end + 2] == '\\u'):
                  esc2 = s[end + 2:end + 6]
                  escX = esc2[1:2]
                  if len(esc2) == 4 and not (escX == 'x' or escX == 'X'):
                      try:
                          uni2 = int(esc2, 16)
                      except ValueError:
                          raise JSONDecodeError(msg, s, end)
                      if uni2 & 0xfc00 == 0xdc00:
                          uni = 0x10000 + (((uni - 0xd800) << 10) |
                                           (uni2 - 0xdc00))
                          end += 6
              char = unichr(uni)
          # Append the unescaped character
          _append(char)
      return _join(chunks), end