private String nextQuotedValue(ByteString runTerminator) throws IOException {
    StringBuilder builder = null;
    while (true) {
      long index = source.indexOfElement(runTerminator);
      if (index == -1L) {
        throw syntaxError("Unterminated string");
      }

      // If we've got an escape character, we're going to need a string builder.
      if (buffer.getByte(index) == '\\') {
        if (builder == null) {
          builder = new StringBuilder();
        }
        builder.append(buffer.readUtf8(index));
        buffer.readByte(); // '\'
        builder.append(readEscapeCharacter());
        continue;
      }

      // If it isn't the escape character, it's the quote. Return the string.
      if (builder == null) {
        String result = buffer.readUtf8(index);
        buffer.readByte(); // Consume the quote character.
        return result;
      } else {
        builder.append(buffer.readUtf8(index));
        buffer.readByte(); // Consume the quote character.
        return builder.toString();
      }
    }
  }
Returns the string up to but not including {@code quote}, unescaping any character escape
sequences encountered along the way. The opening quote should have already been read. This
consumes the closing quote, but does not include it in the returned string.

@throws IOException if any unicode escape sequences are malformed.
lottie/src/main/java/com/airbnb/lottie/parser/moshi/JsonUtf8Reader.java