private Token pullQuotedString() throws ProblemException {
            // the open quote has already been consumed
            StringBuilder sb = new StringBuilder();

            // We need a second string builder to keep track of escape characters.
            // We want to return them exactly as they appeared in the original text,
            // which means we will need a new StringBuilder to escape escape characters
            // so we can also keep the actual value of the string. This is gross.
            StringBuilder sbOrig = new StringBuilder();
            sbOrig.appendCodePoint('"');

            while (true) {
                int c = nextCharRaw();
                if (c == -1)
                    throw problem("End of input but string quote was still open");

                if (c == '\\') {
                    pullEscapeSequence(sb, sbOrig);
                } else if (c == '"') {
                    sbOrig.appendCodePoint(c);
                    break;
                } else if (ConfigImplUtil.isC0Control(c)) {
                    throw problem(asString(c), "JSON does not allow unescaped " + asString(c)
                            + " in quoted strings, use a backslash escape");
                } else {
                    sb.appendCodePoint(c);
                    sbOrig.appendCodePoint(c);
                }
            }

            // maybe switch to triple-quoted string, sort of hacky...
            if (sb.length() == 0) {
                int third = nextCharRaw();
                if (third == '"') {
                    sbOrig.appendCodePoint(third);
                    appendTripleQuotedString(sb, sbOrig);
                } else {
                    putBack(third);
                }

            }
            return Tokens.newString(lineOrigin, sb.toString(), sbOrig.toString());
        }