/** * Quote text contents using JSON standard quoting, and append results to a supplied {@link * StringBuilder}. */ public static void quoteAsString(final CharSequence input, final StringBuilder output) { final char[] qbuf = getQBuf(); final int[] escCodes = CharTypes.get7BitOutputEscapes(); final int escCodeCount = escCodes.length; int inPtr = 0; final int inputLen = input.length(); outer: while (inPtr < inputLen) { tight_loop: while (true) { final char c = input.charAt(inPtr); if (c < escCodeCount && escCodes[c] != 0) { break tight_loop; } output.append(c); if (++inPtr >= inputLen) { break outer; } } // something to escape; 2 or 6-char variant? final char d = input.charAt(inPtr++); final int escCode = escCodes[d]; final int length = (escCode < 0) ? _appendNumeric(d, qbuf) : _appendNamed(escCode, qbuf); output.append(qbuf, 0, length); } }
protected static void appendQuoted(StringBuilder stringbuilder, String s) { stringbuilder.append('"'); CharTypes.appendQuoted(stringbuilder, s); stringbuilder.append('"'); }
/** This class is borrowed from <a href="https://github.com/FasterXML/jackson-core">Jackson</a>. */ public final class JsonUtils { private static final char[] HC = CharTypes.copyHexChars(); /** Temporary buffer used for composing quote/escape sequences */ private static final ThreadLocal<char[]> _qbufLocal = new ThreadLocal<>(); private static char[] getQBuf() { char[] _qbuf = _qbufLocal.get(); if (_qbuf == null) { _qbuf = new char[6]; _qbuf[0] = '\\'; _qbuf[2] = '0'; _qbuf[3] = '0'; _qbufLocal.set(_qbuf); } return _qbuf; } /** * Quote text contents using JSON standard quoting, and append results to a supplied {@link * StringBuilder}. */ public static void quoteAsString(final CharSequence input, final StringBuilder output) { final char[] qbuf = getQBuf(); final int[] escCodes = CharTypes.get7BitOutputEscapes(); final int escCodeCount = escCodes.length; int inPtr = 0; final int inputLen = input.length(); outer: while (inPtr < inputLen) { tight_loop: while (true) { final char c = input.charAt(inPtr); if (c < escCodeCount && escCodes[c] != 0) { break tight_loop; } output.append(c); if (++inPtr >= inputLen) { break outer; } } // something to escape; 2 or 6-char variant? final char d = input.charAt(inPtr++); final int escCode = escCodes[d]; final int length = (escCode < 0) ? _appendNumeric(d, qbuf) : _appendNamed(escCode, qbuf); output.append(qbuf, 0, length); } } private static int _appendNumeric(final int value, final char[] qbuf) { qbuf[1] = 'u'; // We know it's a control char, so only the last 2 chars are non-0 qbuf[4] = HC[value >> 4]; qbuf[5] = HC[value & 0xF]; return 6; } private static int _appendNamed(final int esc, final char[] qbuf) { qbuf[1] = (char) esc; return 2; } }
/** * Intermediate base class shared by JSON-backed generators like {@link UTF8JsonGenerator} and * {@link WriterBasedJsonGenerator}. * * @since 2.1 */ public abstract class JsonGeneratorImpl extends GeneratorBase { /* /********************************************************** /* Constants /********************************************************** */ /** * This is the default set of escape codes, over 7-bit ASCII range (first 128 character codes), * used for single-byte UTF-8 characters. */ protected static final int[] sOutputEscapes = CharTypes.get7BitOutputEscapes(); /* /********************************************************** /* Configuration, basic I/O /********************************************************** */ protected final IOContext _ioContext; /* /********************************************************** /* Configuration, output escaping /********************************************************** */ /** * Currently active set of output escape code definitions (whether and how to escape or not) for * 7-bit ASCII range (first 128 character codes). Defined separately to make potentially * customizable */ protected int[] _outputEscapes = sOutputEscapes; /** * Value between 128 (0x80) and 65535 (0xFFFF) that indicates highest Unicode code point that will * not need escaping; or 0 to indicate that all characters can be represented without escaping. * Typically used to force escaping of some portion of character set; for example to always escape * non-ASCII characters (if value was 127). * * <p>NOTE: not all sub-classes make use of this setting. */ protected int _maximumNonEscapedChar; /** * Definition of custom character escapes to use for generators created by this factory, if any. * If null, standard data format specific escapes are used. */ protected CharacterEscapes _characterEscapes; /* /********************************************************** /* Configuration, other /********************************************************** */ /** * Separator to use, if any, between root-level values. * * @since 2.1 */ protected SerializableString _rootValueSeparator = DefaultPrettyPrinter.DEFAULT_ROOT_VALUE_SEPARATOR; /* /********************************************************** /* Life-cycle /********************************************************** */ public JsonGeneratorImpl(IOContext ctxt, int features, ObjectCodec codec) { super(features, codec); _ioContext = ctxt; if (isEnabled(Feature.ESCAPE_NON_ASCII)) { setHighestNonEscapedChar(127); } } /* /********************************************************** /* Overridden configuration methods /********************************************************** */ @Override public JsonGenerator setHighestNonEscapedChar(int charCode) { _maximumNonEscapedChar = (charCode < 0) ? 0 : charCode; return this; } @Override public int getHighestEscapedChar() { return _maximumNonEscapedChar; } @Override public JsonGenerator setCharacterEscapes(CharacterEscapes esc) { _characterEscapes = esc; if (esc == null) { // revert to standard escapes _outputEscapes = sOutputEscapes; } else { _outputEscapes = esc.getEscapeCodesForAscii(); } return this; } /** Method for accessing custom escapes factory uses for {@link JsonGenerator}s it creates. */ @Override public CharacterEscapes getCharacterEscapes() { return _characterEscapes; } @Override public JsonGenerator setRootValueSeparator(SerializableString sep) { _rootValueSeparator = sep; return this; } /* /********************************************************** /* Versioned /********************************************************** */ @Override public Version version() { return VersionUtil.versionFor(getClass()); } /* /********************************************************** /* Partial API /********************************************************** */ // // Overrides just to make things final, to possibly help with inlining @Override public final void writeStringField(String fieldName, String value) throws IOException, JsonGenerationException { writeFieldName(fieldName); writeString(value); } }