Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/Base64Variant.java =================================================================== diff -u --- 3rdParty_sources/jackson/com/fasterxml/jackson/core/Base64Variant.java (revision 0) +++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/Base64Variant.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03) @@ -0,0 +1,593 @@ +/* Jackson JSON-processor. + * + * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi + */ +package com.fasterxml.jackson.core; + +import java.util.Arrays; + +import com.fasterxml.jackson.core.util.ByteArrayBuilder; + +/** + * Abstract base class used to define specific details of which + * variant of Base64 encoding/decoding is to be used. Although there is + * somewhat standard basic version (so-called "MIME Base64"), other variants + * exists, see Base64 Wikipedia entry for details. + * + * @author Tatu Saloranta + */ +public final class Base64Variant + implements java.io.Serializable +{ + private final static int INT_SPACE = 0x20; + + // We'll only serialize name + private static final long serialVersionUID = 1L; + + /** + * Placeholder used by "no padding" variant, to be used when a character + * value is needed. + */ + final static char PADDING_CHAR_NONE = '\0'; + + /** + * Marker used to denote ascii characters that do not correspond + * to a 6-bit value (in this variant), and is not used as a padding + * character. + */ + public final static int BASE64_VALUE_INVALID = -1; + + /** + * Marker used to denote ascii character (in decoding table) that + * is the padding character using this variant (if any). + */ + public final static int BASE64_VALUE_PADDING = -2; + + /* + /********************************************************** + /* Encoding/decoding tables + /********************************************************** + */ + + /** + * Decoding table used for base 64 decoding. + */ + private final transient int[] _asciiToBase64 = new int[128]; + + /** + * Encoding table used for base 64 decoding when output is done + * as characters. + */ + private final transient char[] _base64ToAsciiC = new char[64]; + + /** + * Alternative encoding table used for base 64 decoding when output is done + * as ascii bytes. + */ + private final transient byte[] _base64ToAsciiB = new byte[64]; + + /* + /********************************************************** + /* Other configuration + /********************************************************** + */ + + /** + * Symbolic name of variant; used for diagnostics/debugging. + *
+ * Note that this is the only non-transient field; used when reading + * back from serialized state + */ + protected final String _name; + + /** + * Whether this variant uses padding or not. + */ + protected final transient boolean _usesPadding; + + /** + * Characted used for padding, if any ({@link #PADDING_CHAR_NONE} if not). + */ + protected final transient char _paddingChar; + + /** + * Maximum number of encoded base64 characters to output during encoding + * before adding a linefeed, if line length is to be limited + * ({@link java.lang.Integer#MAX_VALUE} if not limited). + *
+ * Note: for some output modes (when writing attributes) linefeeds may + * need to be avoided, and this value ignored. + */ + protected final transient int _maxLineLength; + + /* + /********************************************************** + /* Life-cycle + /********************************************************** + */ + + public Base64Variant(String name, String base64Alphabet, boolean usesPadding, char paddingChar, int maxLineLength) + { + _name = name; + _usesPadding = usesPadding; + _paddingChar = paddingChar; + _maxLineLength = maxLineLength; + + // Ok and then we need to create codec tables. + + // First the main encoding table: + int alphaLen = base64Alphabet.length(); + if (alphaLen != 64) { + throw new IllegalArgumentException("Base64Alphabet length must be exactly 64 (was "+alphaLen+")"); + } + + // And then secondary encoding table and decoding table: + base64Alphabet.getChars(0, alphaLen, _base64ToAsciiC, 0); + Arrays.fill(_asciiToBase64, BASE64_VALUE_INVALID); + for (int i = 0; i < alphaLen; ++i) { + char alpha = _base64ToAsciiC[i]; + _base64ToAsciiB[i] = (byte) alpha; + _asciiToBase64[alpha] = i; + } + + // Plus if we use padding, add that in too + if (usesPadding) { + _asciiToBase64[(int) paddingChar] = BASE64_VALUE_PADDING; + } + } + + /** + * "Copy constructor" that can be used when the base alphabet is identical + * to one used by another variant except for the maximum line length + * (and obviously, name). + */ + public Base64Variant(Base64Variant base, String name, int maxLineLength) + { + this(base, name, base._usesPadding, base._paddingChar, maxLineLength); + } + + /** + * "Copy constructor" that can be used when the base alphabet is identical + * to one used by another variant, but other details (padding, maximum + * line length) differ + */ + public Base64Variant(Base64Variant base, String name, boolean usesPadding, char paddingChar, int maxLineLength) + { + _name = name; + byte[] srcB = base._base64ToAsciiB; + System.arraycopy(srcB, 0, this._base64ToAsciiB, 0, srcB.length); + char[] srcC = base._base64ToAsciiC; + System.arraycopy(srcC, 0, this._base64ToAsciiC, 0, srcC.length); + int[] srcV = base._asciiToBase64; + System.arraycopy(srcV, 0, this._asciiToBase64, 0, srcV.length); + + _usesPadding = usesPadding; + _paddingChar = paddingChar; + _maxLineLength = maxLineLength; + } + + /* + /********************************************************** + /* Serializable overrides + /********************************************************** + */ + + /** + * Method used to "demote" deserialized instances back to + * canonical ones + */ + protected Object readResolve() { + return Base64Variants.valueOf(_name); + } + + /* + /********************************************************** + /* Public accessors + /********************************************************** + */ + + public String getName() { return _name; } + + public boolean usesPadding() { return _usesPadding; } + public boolean usesPaddingChar(char c) { return c == _paddingChar; } + public boolean usesPaddingChar(int ch) { return ch == (int) _paddingChar; } + public char getPaddingChar() { return _paddingChar; } + public byte getPaddingByte() { return (byte)_paddingChar; } + + public int getMaxLineLength() { return _maxLineLength; } + + /* + /********************************************************** + /* Decoding support + /********************************************************** + */ + + /** + * @return 6-bit decoded value, if valid character; + */ + public int decodeBase64Char(char c) + { + int ch = (int) c; + return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; + } + + public int decodeBase64Char(int ch) + { + return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; + } + + public int decodeBase64Byte(byte b) + { + int ch = (int) b; + return (ch <= 127) ? _asciiToBase64[ch] : BASE64_VALUE_INVALID; + } + + /* + /********************************************************** + /* Encoding support + /********************************************************** + */ + + public char encodeBase64BitsAsChar(int value) + { + /* Let's assume caller has done necessary checks; this + * method must be fast and inlinable + */ + return _base64ToAsciiC[value]; + } + + /** + * Method that encodes given right-aligned (LSB) 24-bit value + * into 4 base64 characters, stored in given result buffer. + */ + public int encodeBase64Chunk(int b24, char[] buffer, int ptr) + { + buffer[ptr++] = _base64ToAsciiC[(b24 >> 18) & 0x3F]; + buffer[ptr++] = _base64ToAsciiC[(b24 >> 12) & 0x3F]; + buffer[ptr++] = _base64ToAsciiC[(b24 >> 6) & 0x3F]; + buffer[ptr++] = _base64ToAsciiC[b24 & 0x3F]; + return ptr; + } + + public void encodeBase64Chunk(StringBuilder sb, int b24) + { + sb.append(_base64ToAsciiC[(b24 >> 18) & 0x3F]); + sb.append(_base64ToAsciiC[(b24 >> 12) & 0x3F]); + sb.append(_base64ToAsciiC[(b24 >> 6) & 0x3F]); + sb.append(_base64ToAsciiC[b24 & 0x3F]); + } + + /** + * Method that outputs partial chunk (which only encodes one + * or two bytes of data). Data given is still aligned same as if + * it as full data; that is, missing data is at the "right end" + * (LSB) of int. + * + * @param outputBytes Number of encoded bytes included (either 1 or 2) + */ + public int encodeBase64Partial(int bits, int outputBytes, char[] buffer, int outPtr) + { + buffer[outPtr++] = _base64ToAsciiC[(bits >> 18) & 0x3F]; + buffer[outPtr++] = _base64ToAsciiC[(bits >> 12) & 0x3F]; + if (_usesPadding) { + buffer[outPtr++] = (outputBytes == 2) ? + _base64ToAsciiC[(bits >> 6) & 0x3F] : _paddingChar; + buffer[outPtr++] = _paddingChar; + } else { + if (outputBytes == 2) { + buffer[outPtr++] = _base64ToAsciiC[(bits >> 6) & 0x3F]; + } + } + return outPtr; + } + + public void encodeBase64Partial(StringBuilder sb, int bits, int outputBytes) + { + sb.append(_base64ToAsciiC[(bits >> 18) & 0x3F]); + sb.append(_base64ToAsciiC[(bits >> 12) & 0x3F]); + if (_usesPadding) { + sb.append((outputBytes == 2) ? + _base64ToAsciiC[(bits >> 6) & 0x3F] : _paddingChar); + sb.append(_paddingChar); + } else { + if (outputBytes == 2) { + sb.append(_base64ToAsciiC[(bits >> 6) & 0x3F]); + } + } + } + + public byte encodeBase64BitsAsByte(int value) + { + // As with above, assuming it is 6-bit value + return _base64ToAsciiB[value]; + } + + /** + * Method that encodes given right-aligned (LSB) 24-bit value + * into 4 base64 bytes (ascii), stored in given result buffer. + */ + public int encodeBase64Chunk(int b24, byte[] buffer, int ptr) + { + buffer[ptr++] = _base64ToAsciiB[(b24 >> 18) & 0x3F]; + buffer[ptr++] = _base64ToAsciiB[(b24 >> 12) & 0x3F]; + buffer[ptr++] = _base64ToAsciiB[(b24 >> 6) & 0x3F]; + buffer[ptr++] = _base64ToAsciiB[b24 & 0x3F]; + return ptr; + } + + /** + * Method that outputs partial chunk (which only encodes one + * or two bytes of data). Data given is still aligned same as if + * it as full data; that is, missing data is at the "right end" + * (LSB) of int. + * + * @param outputBytes Number of encoded bytes included (either 1 or 2) + */ + public int encodeBase64Partial(int bits, int outputBytes, byte[] buffer, int outPtr) + { + buffer[outPtr++] = _base64ToAsciiB[(bits >> 18) & 0x3F]; + buffer[outPtr++] = _base64ToAsciiB[(bits >> 12) & 0x3F]; + if (_usesPadding) { + byte pb = (byte) _paddingChar; + buffer[outPtr++] = (outputBytes == 2) ? + _base64ToAsciiB[(bits >> 6) & 0x3F] : pb; + buffer[outPtr++] = pb; + } else { + if (outputBytes == 2) { + buffer[outPtr++] = _base64ToAsciiB[(bits >> 6) & 0x3F]; + } + } + return outPtr; + } + + /* + /********************************************************** + /* Convenience conversion methods for String to/from bytes + /* use case. + /********************************************************** + */ + + /** + * Convenience method for converting given byte array as base64 encoded + * String using this variant's settings. + * Resulting value is "raw", that is, not enclosed in double-quotes. + * + * @param input Byte array to encode + */ + public String encode(byte[] input) + { + return encode(input, false); + } + + /** + * Convenience method for converting given byte array as base64 encoded String + * using this variant's settings, + * optionally enclosed in double-quotes. + * + * @param input Byte array to encode + * @param addQuotes Whether to surround resulting value in double quotes or not + */ + public String encode(byte[] input, boolean addQuotes) + { + int inputEnd = input.length; + StringBuilder sb; + { + // let's approximate... 33% overhead, ~= 3/8 (0.375) + int outputLen = inputEnd + (inputEnd >> 2) + (inputEnd >> 3); + sb = new StringBuilder(outputLen); + } + if (addQuotes) { + sb.append('"'); + } + + int chunksBeforeLF = getMaxLineLength() >> 2; + + // Ok, first we loop through all full triplets of data: + int inputPtr = 0; + int safeInputEnd = inputEnd-3; // to get only full triplets + + while (inputPtr <= safeInputEnd) { + // First, mash 3 bytes into lsb of 32-bit int + int b24 = ((int) input[inputPtr++]) << 8; + b24 |= ((int) input[inputPtr++]) & 0xFF; + b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF); + encodeBase64Chunk(sb, b24); + if (--chunksBeforeLF <= 0) { + // note: must quote in JSON value, so not really useful... + sb.append('\\'); + sb.append('n'); + chunksBeforeLF = getMaxLineLength() >> 2; + } + } + + // And then we may have 1 or 2 leftover bytes to encode + int inputLeft = inputEnd - inputPtr; // 0, 1 or 2 + if (inputLeft > 0) { // yes, but do we have room for output? + int b24 = ((int) input[inputPtr++]) << 16; + if (inputLeft == 2) { + b24 |= (((int) input[inputPtr++]) & 0xFF) << 8; + } + encodeBase64Partial(sb, b24, inputLeft); + } + + if (addQuotes) { + sb.append('"'); + } + return sb.toString(); + } + + /** + * Convenience method for decoding contents of a Base64-encoded String, + * using this variant's settings. + * + * @param input + * + * @since 2.2.3 + * + * @throws IllegalArgumentException if input is not valid base64 encoded data + */ + @SuppressWarnings("resource") + public byte[] decode(String input) throws IllegalArgumentException + { + ByteArrayBuilder b = new ByteArrayBuilder(); + decode(input, b); + return b.toByteArray(); + } + + /** + * Convenience method for decoding contents of a Base64-encoded String, + * using this variant's settings + * and appending decoded binary data using provided {@link ByteArrayBuilder}. + *
+ * NOTE: builder will NOT be reset before decoding (nor cleared afterwards); + * assumption is that caller will ensure it is given in proper state, and + * used as appropriate afterwards. + * + * @since 2.2.3 + * + * @throws IllegalArgumentException if input is not valid base64 encoded data + */ + public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentException + { + int ptr = 0; + int len = str.length(); + + main_loop: + while (ptr < len) { + // first, we'll skip preceding white space, if any + char ch; + do { + ch = str.charAt(ptr++); + if (ptr >= len) { + break main_loop; + } + } while (ch <= INT_SPACE); + int bits = decodeBase64Char(ch); + if (bits < 0) { + _reportInvalidBase64(ch, 0, null); + } + int decodedData = bits; + // then second base64 char; can't get padding yet, nor ws + if (ptr >= len) { + _reportBase64EOF(); + } + ch = str.charAt(ptr++); + bits = decodeBase64Char(ch); + if (bits < 0) { + _reportInvalidBase64(ch, 1, null); + } + decodedData = (decodedData << 6) | bits; + // third base64 char; can be padding, but not ws + if (ptr >= len) { + // but as per [JACKSON-631] can be end-of-input, iff not using padding + if (!usesPadding()) { + decodedData >>= 4; + builder.append(decodedData); + break; + } + _reportBase64EOF(); + } + ch = str.charAt(ptr++); + bits = decodeBase64Char(ch); + + // First branch: can get padding (-> 1 byte) + if (bits < 0) { + if (bits != Base64Variant.BASE64_VALUE_PADDING) { + _reportInvalidBase64(ch, 2, null); + } + // Ok, must get padding + if (ptr >= len) { + _reportBase64EOF(); + } + ch = str.charAt(ptr++); + if (!usesPaddingChar(ch)) { + _reportInvalidBase64(ch, 3, "expected padding character '"+getPaddingChar()+"'"); + } + // Got 12 bits, only need 8, need to shift + decodedData >>= 4; + builder.append(decodedData); + continue; + } + // Nope, 2 or 3 bytes + decodedData = (decodedData << 6) | bits; + // fourth and last base64 char; can be padding, but not ws + if (ptr >= len) { + // but as per [JACKSON-631] can be end-of-input, iff not using padding + if (!usesPadding()) { + decodedData >>= 2; + builder.appendTwoBytes(decodedData); + break; + } + _reportBase64EOF(); + } + ch = str.charAt(ptr++); + bits = decodeBase64Char(ch); + if (bits < 0) { + if (bits != Base64Variant.BASE64_VALUE_PADDING) { + _reportInvalidBase64(ch, 3, null); + } + decodedData >>= 2; + builder.appendTwoBytes(decodedData); + } else { + // otherwise, our triple is now complete + decodedData = (decodedData << 6) | bits; + builder.appendThreeBytes(decodedData); + } + } + } + + /* + /********************************************************** + /* Overridden standard methods + /********************************************************** + */ + + @Override + public String toString() { return _name; } + + @Override + public boolean equals(Object o) { + // identity comparison should be dine + return (o == this); + } + + @Override + public int hashCode() { + return _name.hashCode(); + } + + /* + /********************************************************** + /* Internal helper methods + /********************************************************** + */ + + /** + * @param bindex Relative index within base64 character unit; between 0 + * and 3 (as unit has exactly 4 characters) + */ + protected void _reportInvalidBase64(char ch, int bindex, String msg) + throws IllegalArgumentException + { + String base; + if (ch <= INT_SPACE) { + base = "Illegal white space character (code 0x"+Integer.toHexString(ch)+") as character #"+(bindex+1)+" of 4-char base64 unit: can only used between units"; + } else if (usesPaddingChar(ch)) { + base = "Unexpected padding character ('"+getPaddingChar()+"') as character #"+(bindex+1)+" of 4-char base64 unit: padding only legal as 3rd or 4th character"; + } else if (!Character.isDefined(ch) || Character.isISOControl(ch)) { + // Not sure if we can really get here... ? (most illegal xml chars are caught at lower level) + base = "Illegal character (code 0x"+Integer.toHexString(ch)+") in base64 content"; + } else { + base = "Illegal character '"+ch+"' (code 0x"+Integer.toHexString(ch)+") in base64 content"; + } + if (msg != null) { + base = base + ": " + msg; + } + throw new IllegalArgumentException(base); + } + + protected void _reportBase64EOF() throws IllegalArgumentException { + throw new IllegalArgumentException("Unexpected end-of-String in base64 content"); + } +} + Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/Base64Variants.java =================================================================== diff -u --- 3rdParty_sources/jackson/com/fasterxml/jackson/core/Base64Variants.java (revision 0) +++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/Base64Variants.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03) @@ -0,0 +1,111 @@ +/* Jackson JSON-processor. + * + * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi + */ +package com.fasterxml.jackson.core; + +/** + * Container for commonly used Base64 variants: + *
+ * See wikipedia Base64 entry for details. + *
+ * Note that although this can be thought of as the standard variant,
+ * it is not the default for Jackson: no-linefeeds alternative
+ * is because of JSON requirement of escaping all linefeeds.
+ */
+ public final static Base64Variant MIME;
+ static {
+ MIME = new Base64Variant("MIME", STD_BASE64_ALPHABET, true, '=', 76);
+ }
+
+ /**
+ * Slightly non-standard modification of {@link #MIME} which does not
+ * use linefeeds (max line length set to infinite). Useful when linefeeds
+ * wouldn't work well (possibly in attributes), or for minor space savings
+ * (save 1 linefeed per 76 data chars, ie. ~1.4% savings).
+ */
+ public final static Base64Variant MIME_NO_LINEFEEDS;
+ static {
+ MIME_NO_LINEFEEDS = new Base64Variant(MIME, "MIME-NO-LINEFEEDS", Integer.MAX_VALUE);
+ }
+
+ /**
+ * This variant is the one that predates {@link #MIME}: it is otherwise
+ * identical, except that it mandates shorter line length.
+ */
+ public final static Base64Variant PEM = new Base64Variant(MIME, "PEM", true, '=', 64);
+
+ /**
+ * This non-standard variant is usually used when encoded data needs to be
+ * passed via URLs (such as part of GET request). It differs from the
+ * base {@link #MIME} variant in multiple ways.
+ * First, no padding is used: this also means that it generally can not
+ * be written in multiple separate but adjacent chunks (which would not
+ * be the usual use case in any case). Also, no linefeeds are used (max
+ * line length set to infinite). And finally, two characters (plus and
+ * slash) that would need quoting in URLs are replaced with more
+ * optimal alternatives (hyphen and underscore, respectively).
+ */
+ public final static Base64Variant MODIFIED_FOR_URL;
+ static {
+ StringBuilder sb = new StringBuilder(STD_BASE64_ALPHABET);
+ // Replace plus with hyphen, slash with underscore (and no padding)
+ sb.setCharAt(sb.indexOf("+"), '-');
+ sb.setCharAt(sb.indexOf("/"), '_');
+ /* And finally, let's not split lines either, wouldn't work too
+ * well with URLs
+ */
+ MODIFIED_FOR_URL = new Base64Variant("MODIFIED-FOR-URL", sb.toString(), false, Base64Variant.PADDING_CHAR_NONE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Method used to get the default variant ("MIME_NO_LINEFEEDS") for cases
+ * where caller does not explicitly specify the variant.
+ * We will prefer no-linefeed version because linefeeds in JSON values
+ * must be escaped, making linefeed-containing variants sub-optimal.
+ */
+ public static Base64Variant getDefaultVariant() {
+ return MIME_NO_LINEFEEDS;
+ }
+
+ /**
+ * @since 2.1
+ */
+ public static Base64Variant valueOf(String name) throws IllegalArgumentException
+ {
+ if (MIME._name.equals(name)) {
+ return MIME;
+ }
+ if (MIME_NO_LINEFEEDS._name.equals(name)) {
+ return MIME_NO_LINEFEEDS;
+ }
+ if (PEM._name.equals(name)) {
+ return PEM;
+ }
+ if (MODIFIED_FOR_URL._name.equals(name)) {
+ return MODIFIED_FOR_URL;
+ }
+ if (name == null) {
+ name = "
+ * Note that this type is only implemented by non-JSON formats:
+ * types {@link JsonParser.Feature} and {@link JsonGenerator.Feature} do NOT
+ * implement it. This is to make it easier to avoid ambiguity with method
+ * calls.
+ *
+ * @since 2.6 (to be fully used in 2.7 and beyond)
+ */
+public interface FormatFeature
+{
+ /**
+ * Accessor for checking whether this feature is enabled by default.
+ */
+ public boolean enabledByDefault();
+
+ /**
+ * Returns bit mask for this feature instance; must be a single bit,
+ * that is of form
+ * Since there is little commonality between schemas for different data formats,
+ * this interface does not define much meaningful functionality for accessing
+ * schema details; rather, specific parser and generator implementations need
+ * to cast to schema implementations they use. This marker interface is mostly
+ * used for tagging "some kind of schema" -- instead of passing opaque
+ * {@link java.lang.Object} -- for documentation purposes.
+ */
+public interface FormatSchema
+{
+ /**
+ * Method that can be used to get an identifier that can be used for diagnostics
+ * purposes, to indicate what kind of data format this schema is used for: typically
+ * it is a short name of format itself, but it can also contain additional information
+ * in cases where data format supports multiple types of schemas.
+ */
+ String getSchemaType();
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonEncoding.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonEncoding.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonEncoding.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,57 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Enumeration that defines legal encodings that can be used
+ * for JSON content, based on list of allowed encodings from
+ * JSON specification.
+ *
+ * Note: if application want to explicitly disregard Encoding
+ * limitations (to read in JSON encoded using an encoding not
+ * listed as allowed), they can use {@link java.io.Reader} /
+ * {@link java.io.Writer} instances as input
+ */
+public enum JsonEncoding {
+ UTF8("UTF-8", false, 8), // N/A for big-endian, really
+ UTF16_BE("UTF-16BE", true, 16),
+ UTF16_LE("UTF-16LE", false, 16),
+ UTF32_BE("UTF-32BE", true, 32),
+ UTF32_LE("UTF-32LE", false, 32)
+ ;
+
+ protected final String _javaName;
+
+ protected final boolean _bigEndian;
+
+ protected final int _bits;
+
+ JsonEncoding(String javaName, boolean bigEndian, int bits)
+ {
+ _javaName = javaName;
+ _bigEndian = bigEndian;
+ _bits = bits;
+ }
+
+ /**
+ * Method for accessing encoding name that JDK will support.
+ *
+ * @return Matching encoding name that JDK will support.
+ */
+ public String getJavaName() { return _javaName; }
+
+ /**
+ * Whether encoding is big-endian (if encoding supports such
+ * notion). If no such distinction is made (as is the case for
+ * {@link #UTF8}), return value is undefined.
+ *
+ * @return True for big-endian encodings; false for little-endian
+ * (or if not applicable)
+ */
+ public boolean isBigEndian() { return _bigEndian; }
+
+ public int bits() { return _bits; }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonFactory.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonFactory.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonFactory.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,1479 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+package com.fasterxml.jackson.core;
+
+import java.io.*;
+import java.lang.ref.SoftReference;
+import java.net.URL;
+
+import com.fasterxml.jackson.core.format.InputAccessor;
+import com.fasterxml.jackson.core.format.MatchStrength;
+import com.fasterxml.jackson.core.io.*;
+import com.fasterxml.jackson.core.json.*;
+import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
+import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
+import com.fasterxml.jackson.core.util.BufferRecycler;
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+
+/**
+ * The main factory class of Jackson package, used to configure and
+ * construct reader (aka parser, {@link JsonParser})
+ * and writer (aka generator, {@link JsonGenerator})
+ * instances.
+ *
+ * Factory instances are thread-safe and reusable after configuration
+ * (if any). Typically applications and services use only a single
+ * globally shared factory instance, unless they need differently
+ * configured factories. Factory reuse is important if efficiency matters;
+ * most recycling of expensive construct is done on per-factory basis.
+ *
+ * Creation of a factory instance is a light-weight operation,
+ * and since there is no need for pluggable alternative implementations
+ * (as there is no "standard" JSON processor API to implement),
+ * the default constructor is used for constructing factory
+ * instances.
+ *
+ * @author Tatu Saloranta
+ */
+@SuppressWarnings("resource")
+public class JsonFactory
+ implements Versioned,
+ java.io.Serializable // since 2.1 (for Android, mostly)
+{
+ private static final long serialVersionUID = 1; // since 2.6.0
+
+ /*
+ /**********************************************************
+ /* Helper types
+ /**********************************************************
+ */
+
+ /**
+ * Enumeration that defines all on/off features that can only be
+ * changed for {@link JsonFactory}.
+ */
+ public enum Feature {
+
+ // // // Symbol handling (interning etc)
+
+ /**
+ * Feature that determines whether JSON object field names are
+ * to be canonicalized using {@link String#intern} or not:
+ * if enabled, all field names will be intern()ed (and caller
+ * can count on this being true for all such names); if disabled,
+ * no intern()ing is done. There may still be basic
+ * canonicalization (that is, same String will be used to represent
+ * all identical object property names for a single document).
+ *
+ * Note: this setting only has effect if
+ * {@link #CANONICALIZE_FIELD_NAMES} is true -- otherwise no
+ * canonicalization of any sort is done.
+ *
+ * This setting is enabled by default.
+ */
+ INTERN_FIELD_NAMES(true),
+
+ /**
+ * Feature that determines whether JSON object field names are
+ * to be canonicalized (details of how canonicalization is done
+ * then further specified by
+ * {@link #INTERN_FIELD_NAMES}).
+ *
+ * This setting is enabled by default.
+ */
+ CANONICALIZE_FIELD_NAMES(true),
+
+ /**
+ * Feature that determines what happens if we encounter a case in symbol
+ * handling where number of hash collisions exceeds a safety threshold
+ * -- which almost certainly means a denial-of-service attack via generated
+ * duplicate hash codes.
+ * If feature is enabled, an {@link IllegalStateException} is
+ * thrown to indicate the suspected denial-of-service attack; if disabled, processing continues but
+ * canonicalization (and thereby
+ * This setting is enabled by default.
+ *
+ * @since 2.4
+ */
+ FAIL_ON_SYMBOL_HASH_OVERFLOW(true),
+
+ /**
+ * Feature that determines whether we will use {@link BufferRecycler} with
+ * {@link ThreadLocal} and {@link SoftReference}, for efficient reuse of
+ * underlying input/output buffers.
+ * This usually makes sense on normal J2SE/J2EE server-side processing;
+ * but may not make sense on platforms where {@link SoftReference} handling
+ * is broken (like Android), or if there are retention issues due to
+ * {@link ThreadLocal} (see
+ * Issue #189
+ * for a possible case)
+ *
+ * @since 2.6
+ */
+ USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING(true)
+
+ ;
+
+ /**
+ * Whether feature is enabled or disabled by default.
+ */
+ private final boolean _defaultState;
+
+ /**
+ * Method that calculates bit set (flags) of all features that
+ * are enabled by default.
+ */
+ public static int collectDefaults() {
+ int flags = 0;
+ for (Feature f : values()) {
+ if (f.enabledByDefault()) { flags |= f.getMask(); }
+ }
+ return flags;
+ }
+
+ private Feature(boolean defaultState) { _defaultState = defaultState; }
+
+ public boolean enabledByDefault() { return _defaultState; }
+ public boolean enabledIn(int flags) { return (flags & getMask()) != 0; }
+ public int getMask() { return (1 << ordinal()); }
+ }
+
+ /*
+ /**********************************************************
+ /* Constants
+ /**********************************************************
+ */
+
+ /**
+ * Name used to identify JSON format
+ * (and returned by {@link #getFormatName()}
+ */
+ public final static String FORMAT_NAME_JSON = "JSON";
+
+ /**
+ * Bitfield (set of flags) of all factory features that are enabled by default.
+ */
+ protected final static int DEFAULT_FACTORY_FEATURE_FLAGS = JsonFactory.Feature.collectDefaults();
+
+ /**
+ * Bitfield (set of flags) of all parser features that are enabled
+ * by default.
+ */
+ protected final static int DEFAULT_PARSER_FEATURE_FLAGS = JsonParser.Feature.collectDefaults();
+
+ /**
+ * Bitfield (set of flags) of all generator features that are enabled
+ * by default.
+ */
+ protected final static int DEFAULT_GENERATOR_FEATURE_FLAGS = JsonGenerator.Feature.collectDefaults();
+
+ private final static SerializableString DEFAULT_ROOT_VALUE_SEPARATOR = DefaultPrettyPrinter.DEFAULT_ROOT_VALUE_SEPARATOR;
+
+ /*
+ /**********************************************************
+ /* Buffer, symbol table management
+ /**********************************************************
+ */
+
+ /**
+ * This
+ * TODO: should clean up this; looks messy having 2 alternatives
+ * with not very clear differences.
+ *
+ * @since 2.6.0
+ */
+ protected final transient ByteQuadsCanonicalizer _byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot();
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Object that implements conversion functionality between
+ * Java objects and JSON content. For base JsonFactory implementation
+ * usually not set by default, but can be explicitly set.
+ * Sub-classes (like @link org.codehaus.jackson.map.MappingJsonFactory}
+ * usually provide an implementation.
+ */
+ protected ObjectCodec _objectCodec;
+
+ /**
+ * Currently enabled factory features.
+ */
+ protected int _factoryFeatures = DEFAULT_FACTORY_FEATURE_FLAGS;
+
+ /**
+ * Currently enabled parser features.
+ */
+ protected int _parserFeatures = DEFAULT_PARSER_FEATURE_FLAGS;
+
+ /**
+ * Currently enabled generator features.
+ */
+ protected int _generatorFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS;
+
+ /**
+ * 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;
+
+ /**
+ * Optional helper object that may decorate input sources, to do
+ * additional processing on input during parsing.
+ */
+ protected InputDecorator _inputDecorator;
+
+ /**
+ * Optional helper object that may decorate output object, to do
+ * additional processing on output during content generation.
+ */
+ protected OutputDecorator _outputDecorator;
+
+ /**
+ * Separator used between root-level values, if any; null indicates
+ * "do not add separator".
+ * Default separator is a single space character.
+ *
+ * @since 2.1
+ */
+ protected SerializableString _rootValueSeparator = DEFAULT_ROOT_VALUE_SEPARATOR;
+
+ /*
+ /**********************************************************
+ /* Construction
+ /**********************************************************
+ */
+
+ /**
+ * Default constructor used to create factory instances.
+ * Creation of a factory instance is a light-weight operation,
+ * but it is still a good idea to reuse limited number of
+ * factory instances (and quite often just a single instance):
+ * factories are used as context for storing some reused
+ * processing objects (such as symbol tables parsers use)
+ * and this reuse only works within context of a single
+ * factory instance.
+ */
+ public JsonFactory() { this(null); }
+
+ public JsonFactory(ObjectCodec oc) { _objectCodec = oc; }
+
+ /**
+ * Constructor used when copy()ing a factory instance.
+ *
+ * @since 2.2.1
+ */
+ protected JsonFactory(JsonFactory src, ObjectCodec codec)
+ {
+ _objectCodec = null;
+ _factoryFeatures = src._factoryFeatures;
+ _parserFeatures = src._parserFeatures;
+ _generatorFeatures = src._generatorFeatures;
+ _characterEscapes = src._characterEscapes;
+ _inputDecorator = src._inputDecorator;
+ _outputDecorator = src._outputDecorator;
+ _rootValueSeparator = src._rootValueSeparator;
+
+ /* 27-Apr-2013, tatu: How about symbol table; should we try to
+ * reuse shared symbol tables? Could be more efficient that way;
+ * although can slightly add to concurrency overhead.
+ */
+ }
+
+ /**
+ * Method for constructing a new {@link JsonFactory} that has
+ * the same settings as this instance, but is otherwise
+ * independent (i.e. nothing is actually shared, symbol tables
+ * are separate).
+ * Note that {@link ObjectCodec} reference is not copied but is
+ * set to null; caller typically needs to set it after calling
+ * this method. Reason for this is that the codec is used for
+ * callbacks, and assumption is that there is strict 1-to-1
+ * mapping between codec, factory. Caller has to, then, explicitly
+ * set codec after making the copy.
+ *
+ * @since 2.1
+ */
+ public JsonFactory copy()
+ {
+ _checkInvalidCopy(JsonFactory.class);
+ // as per above, do clear ObjectCodec
+ return new JsonFactory(this, null);
+ }
+
+ /**
+ * @since 2.1
+ * @param exp
+ */
+ protected void _checkInvalidCopy(Class> exp)
+ {
+ if (getClass() != exp) {
+ throw new IllegalStateException("Failed copy(): "+getClass().getName()
+ +" (version: "+version()+") does not override copy(); it has to");
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Serializable overrides
+ /**********************************************************
+ */
+
+ /**
+ * Method that we need to override to actually make restoration go
+ * through constructors etc.
+ * Also: must be overridden by sub-classes as well.
+ */
+ protected Object readResolve() {
+ return new JsonFactory(this, _objectCodec);
+ }
+
+ /*
+ /**********************************************************
+ /* Capability introspection
+ /**********************************************************
+ */
+
+ /**
+ * Introspection method that higher-level functionality may call
+ * to see whether underlying data format requires a stable ordering
+ * of object properties or not.
+ * This is usually used for determining
+ * whether to force a stable ordering (like alphabetic ordering by name)
+ * if no ordering if explicitly specified.
+ *
+ * Default implementation returns
+ * Default implementation returns
+ * Note: sub-classes should override this method; default
+ * implementation will return null for all sub-classes
+ */
+ public String getFormatName()
+ {
+ /* Somewhat nasty check: since we can't make this abstract
+ * (due to backwards compatibility concerns), need to prevent
+ * format name "leakage"
+ */
+ if (getClass() == JsonFactory.class) {
+ return FORMAT_NAME_JSON;
+ }
+ return null;
+ }
+
+ /**
+ * Convenience method for trying to determine whether input via given accessor
+ * is of format type supported by this factory.
+ */
+ public MatchStrength hasFormat(InputAccessor acc) throws IOException
+ {
+ // since we can't keep this abstract, only implement for "vanilla" instance
+ if (getClass() == JsonFactory.class) {
+ return hasJSONFormat(acc);
+ }
+ return null;
+ }
+
+ /**
+ * Method that can be called to determine if a custom
+ * {@link ObjectCodec} is needed for binding data parsed
+ * using {@link JsonParser} constructed by this factory
+ * (which typically also implies the same for serialization
+ * with {@link JsonGenerator}).
+ *
+ * @return True if custom codec is needed with parsers and
+ * generators created by this factory; false if a general
+ * {@link ObjectCodec} is enough
+ *
+ * @since 2.1
+ */
+ public boolean requiresCustomCodec() {
+ return false;
+ }
+
+ /**
+ * Helper method that can be called to determine if content accessed
+ * using given accessor seems to be JSON content.
+ */
+ protected MatchStrength hasJSONFormat(InputAccessor acc) throws IOException
+ {
+ return ByteSourceJsonBootstrapper.hasJSONFormat(acc);
+ }
+
+ /*
+ /**********************************************************
+ /* Versioned
+ /**********************************************************
+ */
+
+ @Override
+ public Version version() {
+ return PackageVersion.VERSION;
+ }
+
+ /*
+ /**********************************************************
+ /* Configuration, factory features
+ /**********************************************************
+ */
+
+ /**
+ * Method for enabling or disabling specified parser feature
+ * (check {@link JsonParser.Feature} for list of features)
+ */
+ public final JsonFactory configure(JsonFactory.Feature f, boolean state) {
+ return state ? enable(f) : disable(f);
+ }
+
+ /**
+ * Method for enabling specified parser feature
+ * (check {@link JsonFactory.Feature} for list of features)
+ */
+ public JsonFactory enable(JsonFactory.Feature f) {
+ _factoryFeatures |= f.getMask();
+ return this;
+ }
+
+ /**
+ * Method for disabling specified parser features
+ * (check {@link JsonFactory.Feature} for list of features)
+ */
+ public JsonFactory disable(JsonFactory.Feature f) {
+ _factoryFeatures &= ~f.getMask();
+ return this;
+ }
+
+ /**
+ * Checked whether specified parser feature is enabled.
+ */
+ public final boolean isEnabled(JsonFactory.Feature f) {
+ return (_factoryFeatures & f.getMask()) != 0;
+ }
+
+ /*
+ /**********************************************************
+ /* Configuration, parser configuration
+ /**********************************************************
+ */
+
+ /**
+ * Method for enabling or disabling specified parser feature
+ * (check {@link JsonParser.Feature} for list of features)
+ */
+ public final JsonFactory configure(JsonParser.Feature f, boolean state) {
+ return state ? enable(f) : disable(f);
+ }
+
+ /**
+ * Method for enabling specified parser feature
+ * (check {@link JsonParser.Feature} for list of features)
+ */
+ public JsonFactory enable(JsonParser.Feature f) {
+ _parserFeatures |= f.getMask();
+ return this;
+ }
+
+ /**
+ * Method for disabling specified parser features
+ * (check {@link JsonParser.Feature} for list of features)
+ */
+ public JsonFactory disable(JsonParser.Feature f) {
+ _parserFeatures &= ~f.getMask();
+ return this;
+ }
+
+ /**
+ * Checked whether specified parser feature is enabled.
+ */
+ public final boolean isEnabled(JsonParser.Feature f) {
+ return (_parserFeatures & f.getMask()) != 0;
+ }
+
+ /**
+ * Method for getting currently configured input decorator (if any;
+ * there is no default decorator).
+ */
+ public InputDecorator getInputDecorator() {
+ return _inputDecorator;
+ }
+
+ /**
+ * Method for overriding currently configured input decorator
+ */
+ public JsonFactory setInputDecorator(InputDecorator d) {
+ _inputDecorator = d;
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* Configuration, generator settings
+ /**********************************************************
+ */
+
+ /**
+ * Method for enabling or disabling specified generator feature
+ * (check {@link JsonGenerator.Feature} for list of features)
+ */
+ public final JsonFactory configure(JsonGenerator.Feature f, boolean state) {
+ return state ? enable(f) : disable(f);
+ }
+
+
+ /**
+ * Method for enabling specified generator features
+ * (check {@link JsonGenerator.Feature} for list of features)
+ */
+ public JsonFactory enable(JsonGenerator.Feature f) {
+ _generatorFeatures |= f.getMask();
+ return this;
+ }
+
+ /**
+ * Method for disabling specified generator feature
+ * (check {@link JsonGenerator.Feature} for list of features)
+ */
+ public JsonFactory disable(JsonGenerator.Feature f) {
+ _generatorFeatures &= ~f.getMask();
+ return this;
+ }
+
+ /**
+ * Check whether specified generator feature is enabled.
+ */
+ public final boolean isEnabled(JsonGenerator.Feature f) {
+ return (_generatorFeatures & f.getMask()) != 0;
+ }
+
+ /**
+ * Method for accessing custom escapes factory uses for {@link JsonGenerator}s
+ * it creates.
+ */
+ public CharacterEscapes getCharacterEscapes() { return _characterEscapes; }
+
+ /**
+ * Method for defining custom escapes factory uses for {@link JsonGenerator}s
+ * it creates.
+ */
+ public JsonFactory setCharacterEscapes(CharacterEscapes esc) {
+ _characterEscapes = esc;
+ return this;
+ }
+
+ /**
+ * Method for getting currently configured output decorator (if any;
+ * there is no default decorator).
+ */
+ public OutputDecorator getOutputDecorator() {
+ return _outputDecorator;
+ }
+
+ /**
+ * Method for overriding currently configured output decorator
+ */
+ public JsonFactory setOutputDecorator(OutputDecorator d) {
+ _outputDecorator = d;
+ return this;
+ }
+
+ /**
+ * Method that allows overriding String used for separating root-level
+ * JSON values (default is single space character)
+ *
+ * @param sep Separator to use, if any; null means that no separator is
+ * automatically added
+ *
+ * @since 2.1
+ */
+ public JsonFactory setRootValueSeparator(String sep) {
+ _rootValueSeparator = (sep == null) ? null : new SerializedString(sep);
+ return this;
+ }
+
+ /**
+ * @since 2.1
+ */
+ public String getRootValueSeparator() {
+ return (_rootValueSeparator == null) ? null : _rootValueSeparator.getValue();
+ }
+
+ /*
+ /**********************************************************
+ /* Configuration, other
+ /**********************************************************
+ */
+
+ /**
+ * Method for associating a {@link ObjectCodec} (typically
+ * a
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
+ *
+ * Underlying input stream (needed for reading contents)
+ * will be owned (and managed, i.e. closed as need be) by
+ * the parser, since caller has no access to it.
+ *
+ * @param f File that contains JSON content to parse
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(File f) throws IOException, JsonParseException {
+ // true, since we create InputStream from File
+ IOContext ctxt = _createContext(f, true);
+ InputStream in = new FileInputStream(f);
+ return _createParser(_decorate(in, ctxt), ctxt);
+ }
+
+ /**
+ * Method for constructing JSON parser instance to parse
+ * contents of resource reference by given URL.
+ *
+ *
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
+ *
+ * Underlying input stream (needed for reading contents)
+ * will be owned (and managed, i.e. closed as need be) by
+ * the parser, since caller has no access to it.
+ *
+ * @param url URL pointing to resource that contains JSON content to parse
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(URL url) throws IOException, JsonParseException {
+ // true, since we create InputStream from URL
+ IOContext ctxt = _createContext(url, true);
+ InputStream in = _optimizedStreamFromURL(url);
+ return _createParser(_decorate(in, ctxt), ctxt);
+ }
+
+ /**
+ * Method for constructing JSON parser instance to parse
+ * the contents accessed via specified input stream.
+ *
+ * The input stream will not be owned by
+ * the parser, it will still be managed (i.e. closed if
+ * end-of-stream is reacher, or parser close method called)
+ * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
+ * is enabled.
+ *
+ *
+ * Note: no encoding argument is taken since it can always be
+ * auto-detected as suggested by JSON RFC. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
+ * @param in InputStream to use for reading JSON content to parse
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(InputStream in) throws IOException, JsonParseException {
+ IOContext ctxt = _createContext(in, false);
+ return _createParser(_decorate(in, ctxt), ctxt);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * the contents accessed via specified Reader.
+
+ * The read stream will not be owned by
+ * the parser, it will still be managed (i.e. closed if
+ * end-of-stream is reacher, or parser close method called)
+ * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
+ * is enabled.
+ *
+ * @param r Reader to use for reading JSON content to parse
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(Reader r) throws IOException, JsonParseException {
+ // false -> we do NOT own Reader (did not create it)
+ IOContext ctxt = _createContext(r, false);
+ return _createParser(_decorate(r, ctxt), ctxt);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * the contents of given byte array.
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(byte[] data) throws IOException, JsonParseException {
+ IOContext ctxt = _createContext(data, true);
+ if (_inputDecorator != null) {
+ InputStream in = _inputDecorator.decorate(ctxt, data, 0, data.length);
+ if (in != null) {
+ return _createParser(in, ctxt);
+ }
+ }
+ return _createParser(data, 0, data.length, ctxt);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * the contents of given byte array.
+ *
+ * @param data Buffer that contains data to parse
+ * @param offset Offset of the first data byte within buffer
+ * @param len Length of contents to parse within buffer
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(byte[] data, int offset, int len) throws IOException, JsonParseException {
+ IOContext ctxt = _createContext(data, true);
+ // [JACKSON-512]: allow wrapping with InputDecorator
+ if (_inputDecorator != null) {
+ InputStream in = _inputDecorator.decorate(ctxt, data, offset, len);
+ if (in != null) {
+ return _createParser(in, ctxt);
+ }
+ }
+ return _createParser(data, offset, len, ctxt);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * contents of given String.
+ *
+ * @since 2.1
+ */
+ public JsonParser createParser(String content) throws IOException, JsonParseException {
+ final int strLen = content.length();
+ // Actually, let's use this for medium-sized content, up to 64kB chunk (32kb char)
+ if (_inputDecorator != null || strLen > 0x8000 || !canUseCharArrays()) {
+ // easier to just wrap in a Reader than extend InputDecorator; or, if content
+ // is too long for us to copy it over
+ return createParser(new StringReader(content));
+ }
+ IOContext ctxt = _createContext(content, true);
+ char[] buf = ctxt.allocTokenBuffer(strLen);
+ content.getChars(0, strLen, buf, 0);
+ return _createParser(buf, 0, strLen, ctxt, true);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * contents of given char array.
+ *
+ * @since 2.4
+ */
+ public JsonParser createParser(char[] content) throws IOException {
+ return createParser(content, 0, content.length);
+ }
+
+ /**
+ * Method for constructing parser for parsing contents of given char array.
+ *
+ * @since 2.4
+ */
+ public JsonParser createParser(char[] content, int offset, int len) throws IOException {
+ if (_inputDecorator != null) { // easier to just wrap in a Reader than extend InputDecorator
+ return createParser(new CharArrayReader(content, offset, len));
+ }
+ return _createParser(content, offset, len, _createContext(content, true),
+ // important: buffer is NOT recyclable, as it's from caller
+ false);
+ }
+
+ /*
+ /**********************************************************
+ /* Parser factories (old ones, pre-2.2)
+ /**********************************************************
+ */
+
+ /**
+ * Method for constructing JSON parser instance to parse
+ * contents of specified file.
+ *
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
+ *
+ * Underlying input stream (needed for reading contents)
+ * will be owned (and managed, i.e. closed as need be) by
+ * the parser, since caller has no access to it.
+ *
+ * @param f File that contains JSON content to parse
+ *
+ * @deprecated Since 2.2, use {@link #createParser(File)} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(File f) throws IOException, JsonParseException {
+ return createParser(f);
+ }
+
+ /**
+ * Method for constructing JSON parser instance to parse
+ * contents of resource reference by given URL.
+ *
+ *
+ * Encoding is auto-detected from contents according to JSON
+ * specification recommended mechanism. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
+ *
+ * Underlying input stream (needed for reading contents)
+ * will be owned (and managed, i.e. closed as need be) by
+ * the parser, since caller has no access to it.
+ *
+ * @param url URL pointing to resource that contains JSON content to parse
+ *
+ * @deprecated Since 2.2, use {@link #createParser(URL)} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(URL url) throws IOException, JsonParseException {
+ return createParser(url);
+ }
+
+ /**
+ * Method for constructing JSON parser instance to parse
+ * the contents accessed via specified input stream.
+ *
+ * The input stream will not be owned by
+ * the parser, it will still be managed (i.e. closed if
+ * end-of-stream is reacher, or parser close method called)
+ * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
+ * is enabled.
+ *
+ *
+ * Note: no encoding argument is taken since it can always be
+ * auto-detected as suggested by JSON RFC. Json specification
+ * supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
+ * so auto-detection implemented only for this charsets.
+ * For other charsets use {@link #createParser(java.io.Reader)}.
+ *
+ * @param in InputStream to use for reading JSON content to parse
+ *
+ * @deprecated Since 2.2, use {@link #createParser(InputStream)} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(InputStream in) throws IOException, JsonParseException {
+ return createParser(in);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * the contents accessed via specified Reader.
+
+ * The read stream will not be owned by
+ * the parser, it will still be managed (i.e. closed if
+ * end-of-stream is reacher, or parser close method called)
+ * if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
+ * is enabled.
+ *
+ * @param r Reader to use for reading JSON content to parse
+ *
+ * @deprecated Since 2.2, use {@link #createParser(Reader)} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(Reader r) throws IOException, JsonParseException {
+ return createParser(r);
+ }
+
+ /**
+ * Method for constructing parser for parsing the contents of given byte array.
+ *
+ * @deprecated Since 2.2, use {@link #createParser(byte[])} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(byte[] data) throws IOException, JsonParseException {
+ return createParser(data);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * the contents of given byte array.
+ *
+ * @param data Buffer that contains data to parse
+ * @param offset Offset of the first data byte within buffer
+ * @param len Length of contents to parse within buffer
+ *
+ * @deprecated Since 2.2, use {@link #createParser(byte[],int,int)} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(byte[] data, int offset, int len) throws IOException, JsonParseException {
+ return createParser(data, offset, len);
+ }
+
+ /**
+ * Method for constructing parser for parsing
+ * contents of given String.
+ *
+ * @deprecated Since 2.2, use {@link #createParser(String)} instead.
+ */
+ @Deprecated
+ public JsonParser createJsonParser(String content) throws IOException, JsonParseException {
+ return createParser(content);
+ }
+
+ /*
+ /**********************************************************
+ /* Generator factories, new (as per [Issue-25]
+ /**********************************************************
+ */
+
+ /**
+ * Method for constructing JSON generator for writing JSON content
+ * using specified output stream.
+ * Encoding to use must be specified, and needs to be one of available
+ * types (as per JSON specification).
+ *
+ * Underlying stream is NOT owned by the generator constructed,
+ * so that generator will NOT close the output stream when
+ * {@link JsonGenerator#close} is called (unless auto-closing
+ * feature,
+ * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET}
+ * is enabled).
+ * Using application needs to close it explicitly if this is the case.
+ *
+ * Note: there are formats that use fixed encoding (like most binary data formats)
+ * and that ignore passed in encoding.
+ *
+ * @param out OutputStream to use for writing JSON content
+ * @param enc Character encoding to use
+ *
+ * @since 2.1
+ */
+ public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc)
+ throws IOException
+ {
+ // false -> we won't manage the stream unless explicitly directed to
+ IOContext ctxt = _createContext(out, false);
+ ctxt.setEncoding(enc);
+ if (enc == JsonEncoding.UTF8) {
+ return _createUTF8Generator(_decorate(out, ctxt), ctxt);
+ }
+ Writer w = _createWriter(out, enc, ctxt);
+ return _createGenerator(_decorate(w, ctxt), ctxt);
+ }
+
+ /**
+ * Convenience method for constructing generator that uses default
+ * encoding of the format (UTF-8 for JSON and most other data formats).
+ *
+ * Note: there are formats that use fixed encoding (like most binary data formats).
+ *
+ * @since 2.1
+ */
+ public JsonGenerator createGenerator(OutputStream out) throws IOException {
+ return createGenerator(out, JsonEncoding.UTF8);
+ }
+
+ /**
+ * Method for constructing JSON generator for writing JSON content
+ * using specified Writer.
+ *
+ * Underlying stream is NOT owned by the generator constructed,
+ * so that generator will NOT close the Reader when
+ * {@link JsonGenerator#close} is called (unless auto-closing
+ * feature,
+ * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled).
+ * Using application needs to close it explicitly.
+ *
+ * @since 2.1
+ *
+ * @param w Writer to use for writing JSON content
+ */
+ public JsonGenerator createGenerator(Writer w) throws IOException {
+ IOContext ctxt = _createContext(w, false);
+ return _createGenerator(_decorate(w, ctxt), ctxt);
+ }
+
+ /**
+ * Method for constructing JSON generator for writing JSON content
+ * to specified file, overwriting contents it might have (or creating
+ * it if such file does not yet exist).
+ * Encoding to use must be specified, and needs to be one of available
+ * types (as per JSON specification).
+ *
+ * Underlying stream is owned by the generator constructed,
+ * i.e. generator will handle closing of file when
+ * {@link JsonGenerator#close} is called.
+ *
+ * @param f File to write contents to
+ * @param enc Character encoding to use
+ *
+ * @since 2.1
+ */
+ public JsonGenerator createGenerator(File f, JsonEncoding enc) throws IOException
+ {
+ OutputStream out = new FileOutputStream(f);
+ // true -> yes, we have to manage the stream since we created it
+ IOContext ctxt = _createContext(out, true);
+ ctxt.setEncoding(enc);
+ if (enc == JsonEncoding.UTF8) {
+ return _createUTF8Generator(_decorate(out, ctxt), ctxt);
+ }
+ Writer w = _createWriter(out, enc, ctxt);
+ return _createGenerator(_decorate(w, ctxt), ctxt);
+ }
+
+ /*
+ /**********************************************************
+ /* Generator factories, old (pre-2.2)
+ /**********************************************************
+ */
+
+ /**
+ * Method for constructing JSON generator for writing JSON content
+ * using specified output stream.
+ * Encoding to use must be specified, and needs to be one of available
+ * types (as per JSON specification).
+ *
+ * Underlying stream is NOT owned by the generator constructed,
+ * so that generator will NOT close the output stream when
+ * {@link JsonGenerator#close} is called (unless auto-closing
+ * feature,
+ * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET}
+ * is enabled).
+ * Using application needs to close it explicitly if this is the case.
+ *
+ * Note: there are formats that use fixed encoding (like most binary data formats)
+ * and that ignore passed in encoding.
+ *
+ * @param out OutputStream to use for writing JSON content
+ * @param enc Character encoding to use
+ *
+ * @deprecated Since 2.2, use {@link #createGenerator(OutputStream, JsonEncoding)} instead.
+ */
+ @Deprecated
+ public JsonGenerator createJsonGenerator(OutputStream out, JsonEncoding enc) throws IOException {
+ return createGenerator(out, enc);
+ }
+
+ /**
+ * Method for constructing JSON generator for writing JSON content
+ * using specified Writer.
+ *
+ * Underlying stream is NOT owned by the generator constructed,
+ * so that generator will NOT close the Reader when
+ * {@link JsonGenerator#close} is called (unless auto-closing
+ * feature,
+ * {@link com.fasterxml.jackson.core.JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled).
+ * Using application needs to close it explicitly.
+ *
+ * @param out Writer to use for writing JSON content
+ *
+ * @deprecated Since 2.2, use {@link #createGenerator(Writer)} instead.
+ */
+ @Deprecated
+ public JsonGenerator createJsonGenerator(Writer out) throws IOException {
+ return createGenerator(out);
+ }
+
+ /**
+ * Convenience method for constructing generator that uses default
+ * encoding of the format (UTF-8 for JSON and most other data formats).
+ *
+ * Note: there are formats that use fixed encoding (like most binary data formats).
+ *
+ * @deprecated Since 2.2, use {@link #createGenerator(OutputStream)} instead.
+ */
+ @Deprecated
+ public JsonGenerator createJsonGenerator(OutputStream out) throws IOException {
+ return createGenerator(out, JsonEncoding.UTF8);
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods used by factory for creating parser instances,
+ /* overridable by sub-classes
+ /**********************************************************
+ */
+
+ /**
+ * Overridable factory method that actually instantiates desired parser
+ * given {@link InputStream} and context object.
+ *
+ * This method is specifically designed to remain
+ * compatible between minor versions so that sub-classes can count
+ * on it being called as expected. That is, it is part of official
+ * interface from sub-class perspective, although not a public
+ * method available to users of factory implementations.
+ *
+ * @since 2.1
+ */
+ protected JsonParser _createParser(InputStream in, IOContext ctxt) throws IOException {
+ // As per [JACKSON-259], may want to fully disable canonicalization:
+ return new ByteSourceJsonBootstrapper(ctxt, in).constructParser(_parserFeatures,
+ _objectCodec, _byteSymbolCanonicalizer, _rootCharSymbols, _factoryFeatures);
+ }
+
+ /**
+ * Overridable factory method that actually instantiates parser
+ * using given {@link Reader} object for reading content.
+ *
+ * This method is specifically designed to remain
+ * compatible between minor versions so that sub-classes can count
+ * on it being called as expected. That is, it is part of official
+ * interface from sub-class perspective, although not a public
+ * method available to users of factory implementations.
+ *
+ * @since 2.1
+ */
+ protected JsonParser _createParser(Reader r, IOContext ctxt) throws IOException {
+ return new ReaderBasedJsonParser(ctxt, _parserFeatures, r, _objectCodec,
+ _rootCharSymbols.makeChild(_factoryFeatures));
+ }
+
+ /**
+ * Overridable factory method that actually instantiates parser
+ * using given
+ * This method is specifically designed to remain
+ * compatible between minor versions so that sub-classes can count
+ * on it being called as expected. That is, it is part of official
+ * interface from sub-class perspective, although not a public
+ * method available to users of factory implementations.
+ */
+ protected JsonParser _createParser(byte[] data, int offset, int len, IOContext ctxt) throws IOException
+ {
+ return new ByteSourceJsonBootstrapper(ctxt, data, offset, len).constructParser(_parserFeatures,
+ _objectCodec, _byteSymbolCanonicalizer, _rootCharSymbols, _factoryFeatures);
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods used by factory for creating generator instances,
+ /* overridable by sub-classes
+ /**********************************************************
+ */
+
+ /**
+ * Overridable factory method that actually instantiates generator for
+ * given {@link Writer} and context object.
+ *
+ * This method is specifically designed to remain
+ * compatible between minor versions so that sub-classes can count
+ * on it being called as expected. That is, it is part of official
+ * interface from sub-class perspective, although not a public
+ * method available to users of factory implementations.
+ */
+ protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException
+ {
+ WriterBasedJsonGenerator gen = new WriterBasedJsonGenerator(ctxt,
+ _generatorFeatures, _objectCodec, out);
+ if (_characterEscapes != null) {
+ gen.setCharacterEscapes(_characterEscapes);
+ }
+ SerializableString rootSep = _rootValueSeparator;
+ if (rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) {
+ gen.setRootValueSeparator(rootSep);
+ }
+ return gen;
+ }
+
+ /**
+ * Overridable factory method that actually instantiates generator for
+ * given {@link OutputStream} and context object, using UTF-8 encoding.
+ *
+ * This method is specifically designed to remain
+ * compatible between minor versions so that sub-classes can count
+ * on it being called as expected. That is, it is part of official
+ * interface from sub-class perspective, although not a public
+ * method available to users of factory implementations.
+ */
+ protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) throws IOException {
+ UTF8JsonGenerator gen = new UTF8JsonGenerator(ctxt,
+ _generatorFeatures, _objectCodec, out);
+ if (_characterEscapes != null) {
+ gen.setCharacterEscapes(_characterEscapes);
+ }
+ SerializableString rootSep = _rootValueSeparator;
+ if (rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) {
+ gen.setRootValueSeparator(rootSep);
+ }
+ return gen;
+ }
+
+ protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException
+ {
+ // note: this should not get called any more (caller checks, dispatches)
+ if (enc == JsonEncoding.UTF8) { // We have optimized writer for UTF-8
+ return new UTF8Writer(ctxt, out);
+ }
+ // not optimal, but should do unless we really care about UTF-16/32 encoding speed
+ return new OutputStreamWriter(out, enc.getJavaName());
+ }
+
+ /*
+ /**********************************************************
+ /* Internal factory methods, decorator handling
+ /**********************************************************
+ */
+
+ /**
+ * @since 2.4
+ */
+ protected final InputStream _decorate(InputStream in, IOContext ctxt) throws IOException {
+ if (_inputDecorator != null) {
+ InputStream in2 = _inputDecorator.decorate(ctxt, in);
+ if (in2 != null) {
+ return in2;
+ }
+ }
+ return in;
+ }
+
+ /**
+ * @since 2.4
+ */
+ protected final Reader _decorate(Reader in, IOContext ctxt) throws IOException {
+ if (_inputDecorator != null) {
+ Reader in2 = _inputDecorator.decorate(ctxt, in);
+ if (in2 != null) {
+ return in2;
+ }
+ }
+ return in;
+ }
+
+ /**
+ * @since 2.4
+ */
+ protected final OutputStream _decorate(OutputStream out, IOContext ctxt) throws IOException {
+ if (_outputDecorator != null) {
+ OutputStream out2 = _outputDecorator.decorate(ctxt, out);
+ if (out2 != null) {
+ return out2;
+ }
+ }
+ return out;
+ }
+
+ /**
+ * @since 2.4
+ */
+ protected final Writer _decorate(Writer out, IOContext ctxt) throws IOException {
+ if (_outputDecorator != null) {
+ Writer out2 = _outputDecorator.decorate(ctxt, out);
+ if (out2 != null) {
+ return out2;
+ }
+ }
+ return out;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal factory methods, other
+ /**********************************************************
+ */
+
+ /**
+ * Method used by factory to create buffer recycler instances
+ * for parsers and generators.
+ *
+ * Note: only public to give access for
+ * Feature is enabled by default.
+ */
+ AUTO_CLOSE_TARGET(true),
+
+ /**
+ * Feature that determines what happens when the generator is
+ * closed while there are still unmatched
+ * {@link JsonToken#START_ARRAY} or {@link JsonToken#START_OBJECT}
+ * entries in output content. If enabled, such Array(s) and/or
+ * Object(s) are automatically closed; if disabled, nothing
+ * specific is done.
+ *
+ * Feature is enabled by default.
+ */
+ AUTO_CLOSE_JSON_CONTENT(true),
+
+ /**
+ * Feature that specifies that calls to {@link #flush} will cause
+ * matching
+ * Feature is enabled by default.
+ */
+ FLUSH_PASSED_TO_STREAM(true),
+
+ // // Quoting-related features
+
+ /**
+ * Feature that determines whether JSON Object field names are
+ * quoted using double-quotes, as specified by JSON specification
+ * or not. Ability to disable quoting was added to support use
+ * cases where they are not usually expected, which most commonly
+ * occurs when used straight from Javascript.
+ *
+ * Feature is enabled by default (since it is required by JSON specification).
+ */
+ QUOTE_FIELD_NAMES(true),
+
+ /**
+ * Feature that determines whether "exceptional" (not real number)
+ * float/double values are output as quoted strings.
+ * The values checked are Double.Nan,
+ * Double.POSITIVE_INFINITY and Double.NEGATIVE_INIFINTY (and
+ * associated Float values).
+ * If feature is disabled, these numbers are still output using
+ * associated literal values, resulting in non-conformant
+ * output.
+ *
+ * Feature is enabled by default.
+ */
+ QUOTE_NON_NUMERIC_NUMBERS(true),
+
+ /**
+ * Feature that forces all Java numbers to be written as JSON strings.
+ * Default state is 'false', meaning that Java numbers are to
+ * be serialized using basic numeric serialization (as JSON
+ * numbers, integral or floating point). If enabled, all such
+ * numeric values are instead written out as JSON Strings.
+ *
+ * One use case is to avoid problems with Javascript limitations:
+ * since Javascript standard specifies that all number handling
+ * should be done using 64-bit IEEE 754 floating point values,
+ * result being that some 64-bit integer values can not be
+ * accurately represent (as mantissa is only 51 bit wide).
+ *
+ * Feature is disabled by default.
+ */
+ WRITE_NUMBERS_AS_STRINGS(false),
+
+ /**
+ * Feature that determines whether {@link java.math.BigDecimal} entries are
+ * serialized using {@link java.math.BigDecimal#toPlainString()} to prevent
+ * values to be written using scientific notation.
+ *
+ * Feature is disabled by default, so default output mode is used; this generally
+ * depends on how {@link BigDecimal} has been created.
+ *
+ * @since 2.3
+ */
+ WRITE_BIGDECIMAL_AS_PLAIN(false),
+
+ /**
+ * Feature that specifies that all characters beyond 7-bit ASCII
+ * range (i.e. code points of 128 and above) need to be output
+ * using format-specific escapes (for JSON, backslash escapes),
+ * if format uses escaping mechanisms (which is generally true
+ * for textual formats but not for binary formats).
+ *
+ * Note that this setting may not necessarily make sense for all
+ * data formats (for example, binary formats typically do not use
+ * any escaping mechanisms; and some textual formats do not have
+ * general-purpose escaping); if so, settings is simply ignored.
+ * Put another way, effects of this feature are data-format specific.
+ *
+ * Feature is disabled by default.
+ */
+ ESCAPE_NON_ASCII(false),
+
+// 23-Nov-2015, tatu: for [core#223], if and when it gets implemented
+ /**
+ * Feature that specifies handling of UTF-8 content that contains
+ * characters beyond BMP (Basic Multilingual Plane), which are
+ * represented in UCS-2 (Java internal character encoding) as two
+ * "surrogate" characters. If feature is enabled, these surrogate
+ * pairs are separately escaped using backslash escapes; if disabled,
+ * native output (4-byte UTF-8 sequence, or, with char-backed output
+ * targets, writing of surrogates as is which is typically converted
+ * by {@link java.io.Writer} into 4-byte UTF-8 sequence eventually)
+ * is used.
+ *
+ * Note that the original JSON specification suggests use of escaping;
+ * but that this is not correct from standard UTF-8 handling perspective.
+ * Because of two competing goals, this feature was added to allow either
+ * behavior to be used, but defaulting to UTF-8 specification compliant
+ * mode.
+ *
+ * Feature is disabled by default.
+ *
+ * @since Xxx
+ */
+// ESCAPE_UTF8_SURROGATES(false),
+
+ // // Schema/Validity support features
+
+ /**
+ * Feature that determines whether {@link JsonGenerator} will explicitly
+ * check that no duplicate JSON Object field names are written.
+ * If enabled, generator will check all names within context and report
+ * duplicates by throwing a {@link JsonGenerationException}; if disabled,
+ * no such checking will be done. Assumption in latter case is
+ * that caller takes care of not trying to write duplicate names.
+ *
+ * Note that enabling this feature will incur performance overhead
+ * due to having to store and check additional information.
+ *
+ * Feature is disabled by default.
+ *
+ * @since 2.3
+ */
+ STRICT_DUPLICATE_DETECTION(false),
+
+ /**
+ * Feature that determines what to do if the underlying data format requires knowledge
+ * of all properties to output, and if no definition is found for a property that
+ * caller tries to write. If enabled, such properties will be quietly ignored;
+ * if disabled, a {@link JsonProcessingException} will be thrown to indicate the
+ * problem.
+ * Typically most textual data formats do NOT require schema information (although
+ * some do, such as CSV), whereas many binary data formats do require definitions
+ * (such as Avro, protobuf), although not all (Smile, CBOR, BSON and MessagePack do not).
+ *
+ * Note that support for this feature is implemented by individual data format
+ * module, if (and only if) it makes sense for the format in question. For JSON,
+ * for example, this feature has no effect as properties need not be pre-defined.
+ *
+ * Feature is disabled by default, meaning that if the underlying data format
+ * requires knowledge of all properties to output, attempts to write an unknown
+ * property will result in a {@link JsonProcessingException}
+ *
+ * @since 2.5
+ */
+ IGNORE_UNKNOWN(false),
+ ;
+
+ private final boolean _defaultState;
+ private final int _mask;
+
+ /**
+ * Method that calculates bit set (flags) of all features that
+ * are enabled by default.
+ */
+ public static int collectDefaults()
+ {
+ int flags = 0;
+ for (Feature f : values()) {
+ if (f.enabledByDefault()) {
+ flags |= f.getMask();
+ }
+ }
+ return flags;
+ }
+
+ private Feature(boolean defaultState) {
+ _defaultState = defaultState;
+ _mask = (1 << ordinal());
+ }
+
+ public boolean enabledByDefault() { return _defaultState; }
+
+ /**
+ * @since 2.3
+ */
+ public boolean enabledIn(int flags) { return (flags & _mask) != 0; }
+
+ public int getMask() { return _mask; }
+ }
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Object that handles pretty-printing (usually additional
+ * white space to make results more human-readable) during
+ * output. If null, no pretty-printing is done.
+ */
+ protected PrettyPrinter _cfgPrettyPrinter;
+
+ /*
+ /**********************************************************
+ /* Construction, initialization
+ /**********************************************************
+ */
+
+ protected JsonGenerator() { }
+
+ /**
+ * Method that can be called to set or reset the object to
+ * use for writing Java objects as JsonContent
+ * (using method {@link #writeObject}).
+ *
+ * @return Generator itself (this), to allow chaining
+ */
+ public abstract JsonGenerator setCodec(ObjectCodec oc);
+
+ /**
+ * Method for accessing the object used for writing Java
+ * object as JSON content
+ * (using method {@link #writeObject}).
+ */
+ public abstract ObjectCodec getCodec();
+
+ /**
+ * Accessor for finding out version of the bundle that provided this generator instance.
+ */
+ @Override
+ public abstract Version version();
+
+ /*
+ /**********************************************************
+ /* Public API, Feature configuration
+ /**********************************************************
+ */
+
+ /**
+ * Method for enabling specified parser features:
+ * check {@link Feature} for list of available features.
+ *
+ * @return Generator itself (this), to allow chaining
+ */
+ public abstract JsonGenerator enable(Feature f);
+
+ /**
+ * Method for disabling specified features
+ * (check {@link Feature} for list of features)
+ *
+ * @return Generator itself (this), to allow chaining
+ */
+ public abstract JsonGenerator disable(Feature f);
+
+ /**
+ * Method for enabling or disabling specified feature:
+ * check {@link Feature} for list of available features.
+ *
+ * @return Generator itself (this), to allow chaining
+ */
+ public final JsonGenerator configure(Feature f, boolean state) {
+ if (state) enable(f); else disable(f);
+ return this;
+ }
+
+ /**
+ * Method for checking whether given feature is enabled.
+ * Check {@link Feature} for list of available features.
+ */
+ public abstract boolean isEnabled(Feature f);
+
+ /**
+ * Bulk access method for getting state of all standard (non-dataformat-specific)
+ * {@link JsonGenerator.Feature}s.
+ *
+ * @return Bit mask that defines current states of all standard {@link JsonGenerator.Feature}s.
+ *
+ * @since 2.3
+ */
+ public abstract int getFeatureMask();
+
+ /**
+ * Bulk set method for (re)setting states of all standard {@link Feature}s
+ *
+ * @since 2.3
+ *
+ * @param values Bitmask that defines which {@link Feature}s are enabled
+ * and which disabled
+ *
+ * @return This parser object, to allow chaining of calls
+ *
+ * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
+ */
+ @Deprecated
+ public abstract JsonGenerator setFeatureMask(int values);
+
+ /**
+ * Bulk set method for (re)setting states of features specified by
+ * Default implementation will simply throw an exception to indicate that
+ * the generator implementation does not support any {@link FormatFeature}s.
+ *
+ * @param values Bit mask of set/clear state for features to change
+ * @param mask Bit mask of features to change
+ *
+ * @since 2.6
+ */
+ public JsonGenerator overrideFormatFeatures(int values, int mask) {
+ throw new IllegalArgumentException("No FormatFeatures defined for generator of type "+getClass().getName());
+ /*
+ int oldState = getFeatureMask();
+ int newState = (oldState & ~mask) | (values & mask);
+ return setFeatureMask(newState);
+ */
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, Schema configuration
+ /**********************************************************
+ */
+
+ /**
+ * Method to call to make this generator use specified schema.
+ * Method must be called before generating any content, right after instance
+ * has been created.
+ * Note that not all generators support schemas; and those that do usually only
+ * accept specific types of schemas: ones defined for data format this generator
+ * produces.
+ *
+ * If generator does not support specified schema, {@link UnsupportedOperationException}
+ * is thrown.
+ *
+ * @param schema Schema to use
+ *
+ * @throws UnsupportedOperationException if generator does not support schema
+ */
+ public void setSchema(FormatSchema schema) {
+ throw new UnsupportedOperationException("Generator of type "+getClass().getName()+" does not support schema of type '"
+ +schema.getSchemaType()+"'");
+ }
+
+ /**
+ * Method for accessing Schema that this parser uses, if any.
+ * Default implementation returns null.
+ *
+ * @since 2.1
+ */
+ public FormatSchema getSchema() { return null; }
+
+ /*
+ /**********************************************************
+ /* Public API, other configuration
+ /**********************************************************
+ */
+
+ /**
+ * Method for setting a custom pretty printer, which is usually
+ * used to add indentation for improved human readability.
+ * By default, generator does not do pretty printing.
+ *
+ * To use the default pretty printer that comes with core
+ * Jackson distribution, call {@link #useDefaultPrettyPrinter}
+ * instead.
+ *
+ * @return Generator itself (this), to allow chaining
+ */
+ public JsonGenerator setPrettyPrinter(PrettyPrinter pp) {
+ _cfgPrettyPrinter = pp;
+ return this;
+ }
+
+ /**
+ * Accessor for checking whether this generator has a configured
+ * {@link PrettyPrinter}; returns it if so, null if none configured.
+ *
+ * @since 2.1
+ */
+ public PrettyPrinter getPrettyPrinter() {
+ return _cfgPrettyPrinter;
+ }
+
+ /**
+ * Convenience method for enabling pretty-printing using
+ * the default pretty printer
+ * ({@link com.fasterxml.jackson.core.util.DefaultPrettyPrinter}).
+ *
+ * @return Generator itself (this), to allow chaining
+ */
+ public abstract JsonGenerator useDefaultPrettyPrinter();
+
+ /**
+ * Method that can be called to request that generator escapes
+ * all character codes above specified code point (if positive value);
+ * or, to not escape any characters except for ones that must be
+ * escaped for the data format (if -1).
+ * To force escaping of all non-ASCII characters, for example,
+ * this method would be called with value of 127.
+ *
+ * Note that generators are NOT required to support setting of value
+ * higher than 127, because there are other ways to affect quoting
+ * (or lack thereof) of character codes between 0 and 127.
+ * Not all generators support concept of escaping, either; if so,
+ * calling this method will have no effect.
+ *
+ * Default implementation does nothing; sub-classes need to redefine
+ * it according to rules of supported data format.
+ *
+ * @param charCode Either -1 to indicate that no additional escaping
+ * is to be done; or highest code point not to escape (meaning higher
+ * ones will be), if positive value.
+ */
+ public JsonGenerator setHighestNonEscapedChar(int charCode) { return this; }
+
+ /**
+ * Accessor method for testing what is the highest unescaped character
+ * configured for this generator. This may be either positive value
+ * (when escaping configuration has been set and is in effect), or
+ * 0 to indicate that no additional escaping is in effect.
+ * Some generators may not support additional escaping: for example,
+ * generators for binary formats that do not use escaping should
+ * simply return 0.
+ *
+ * @return Currently active limitation for highest non-escaped character,
+ * if defined; or -1 to indicate no additional escaping is performed.
+ */
+ public int getHighestEscapedChar() { return 0; }
+
+ /**
+ * Method for accessing custom escapes factory uses for {@link JsonGenerator}s
+ * it creates.
+ */
+ public CharacterEscapes getCharacterEscapes() { return null; }
+
+ /**
+ * Method for defining custom escapes factory uses for {@link JsonGenerator}s
+ * it creates.
+ *
+ * Default implementation does nothing and simply returns this instance.
+ */
+ public JsonGenerator setCharacterEscapes(CharacterEscapes esc) { return this; }
+
+ /**
+ * Method that allows overriding String used for separating root-level
+ * JSON values (default is single space character)
+ *
+ * Default implementation throws {@link UnsupportedOperationException}.
+ *
+ * @param sep Separator to use, if any; null means that no separator is
+ * automatically added
+ *
+ * @since 2.1
+ */
+ public JsonGenerator setRootValueSeparator(SerializableString sep) {
+ throw new UnsupportedOperationException();
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, output state access
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to get access to object that is used
+ * as target for generated output; this is usually either
+ * {@link OutputStream} or {@link Writer}, depending on what
+ * generator was constructed with.
+ * Note that returned value may be null in some cases; including
+ * case where implementation does not want to exposed raw
+ * source to caller.
+ * In cases where output has been decorated, object returned here
+ * is the decorated version; this allows some level of interaction
+ * between users of generator and decorator object.
+ *
+ * In general use of this accessor should be considered as
+ * "last effort", i.e. only used if no other mechanism is applicable.
+ */
+ public Object getOutputTarget() {
+ return null;
+ }
+
+ /**
+ * Method for verifying amount of content that is buffered by generator
+ * but not yet flushed to the underlying target (stream, writer),
+ * in units (byte, char) that the generator implementation uses for buffering;
+ * or -1 if this information is not available.
+ * Unit used is often the same as the unit of underlying target (that is,
+ * `byte` for {@link java.io.OutputStream}, `char` for {@link java.io.Writer}),
+ * but may differ if buffering is done before encoding.
+ * Default JSON-backed implementations do use matching units.
+ *
+ * Note: non-JSON implementations will be retrofitted for 2.6 and beyond;
+ * please report if you see -1 (missing override)
+ *
+ * @return Amount of content buffered in internal units, if amount known and
+ * accessible; -1 if not accessible.
+ *
+ * @since 2.6
+ */
+ public int getOutputBuffered() {
+ return -1;
+ }
+
+ /**
+ * Helper method, usually equivalent to:
+ *
+ * Note that "current value" is NOT populated (or used) by Streaming parser;
+ * it is only used by higher-level data-binding functionality.
+ * The reason it is included here is that it can be stored and accessed hierarchically,
+ * and gets passed through data-binding.
+ *
+ * @since 2.5
+ */
+ public Object getCurrentValue() {
+ JsonStreamContext ctxt = getOutputContext();
+ return (ctxt == null) ? null : ctxt.getCurrentValue();
+ }
+
+ /**
+ * Helper method, usually equivalent to:
+ *
+ * Default implementation returns false; overridden by data formats
+ * that do support native Object Ids. Caller is expected to either
+ * use a non-native notation (explicit property or such), or fail,
+ * in case it can not use native object ids.
+ *
+ * @since 2.3
+ */
+ public boolean canWriteObjectId() { return false; }
+
+ /**
+ * Introspection method that may be called to see if the underlying
+ * data format supports some kind of Type Ids natively (many do not;
+ * for example, JSON doesn't).
+ * This method must be called prior to calling
+ * {@link #writeTypeId}.
+ *
+ * Default implementation returns false; overridden by data formats
+ * that do support native Type Ids. Caller is expected to either
+ * use a non-native notation (explicit property or such), or fail,
+ * in case it can not use native type ids.
+ *
+ * @since 2.3
+ */
+ public boolean canWriteTypeId() { return false; }
+
+ /**
+ * Introspection method that may be called to see if the underlying
+ * data format supports "native" binary data; that is, an efficient
+ * output of binary content without encoding.
+ *
+ * Default implementation returns false; overridden by data formats
+ * that do support native binary content.
+ *
+ * @since 2.3
+ */
+ public boolean canWriteBinaryNatively() { return false; }
+
+ /**
+ * Introspection method to call to check whether it is ok to omit
+ * writing of Object fields or not. Most formats do allow omission,
+ * but certain positional formats (such as CSV) require output of
+ * placeholders, even if no real values are to be emitted.
+ *
+ * @since 2.3
+ */
+ public boolean canOmitFields() { return true; }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, structural
+ /**********************************************************
+ */
+
+ /**
+ * Method for writing starting marker of a Array value
+ * (for JSON this is character '['; plus possible white space decoration
+ * if pretty-printing is enabled).
+ *
+ * Array values can be written in any context where values
+ * are allowed: meaning everywhere except for when
+ * a field name is expected.
+ */
+ public abstract void writeStartArray() throws IOException;
+
+ /**
+ * Method for writing start marker of an Array value, similar
+ * to {@link #writeStartArray()}, but also specifying how many
+ * elements will be written for the array before calling
+ * {@link #writeEndArray()}.
+ *
+ * Default implementation simply calls {@link #writeStartArray()}.
+ *
+ * @param size Number of elements this array will have: actual
+ * number of values written (before matching call to
+ * {@link #writeEndArray()} MUST match; generator MAY verify
+ * this is the case.
+ *
+ * @since 2.4
+ */
+ public void writeStartArray(int size) throws IOException {
+ writeStartArray();
+ }
+
+ /**
+ * Method for writing closing marker of a JSON Array value
+ * (character ']'; plus possible white space decoration
+ * if pretty-printing is enabled).
+ *
+ * Marker can be written if the innermost structured type
+ * is Array.
+ */
+ public abstract void writeEndArray() throws IOException;
+
+ /**
+ * Method for writing starting marker of a JSON Object value
+ * (character '{'; plus possible white space decoration
+ * if pretty-printing is enabled).
+ *
+ * Object values can be written in any context where values
+ * are allowed: meaning everywhere except for when
+ * a field name is expected.
+ */
+ public abstract void writeStartObject() throws IOException;
+
+ /**
+ * Method for writing closing marker of a JSON Object value
+ * (character '}'; plus possible white space decoration
+ * if pretty-printing is enabled).
+ *
+ * Marker can be written if the innermost structured type
+ * is Object, and the last written event was either a
+ * complete value, or START-OBJECT marker (see JSON specification
+ * for more details).
+ */
+ public abstract void writeEndObject() throws IOException;
+
+ /**
+ * Method for writing a field name (JSON String surrounded by
+ * double quotes: syntactically identical to a JSON String value),
+ * possibly decorated by white space if pretty-printing is enabled.
+ *
+ * Field names can only be written in Object context (check out
+ * JSON specification for details), when field name is expected
+ * (field names alternate with values).
+ */
+ public abstract void writeFieldName(String name) throws IOException;
+
+ /**
+ * Method similar to {@link #writeFieldName(String)}, main difference
+ * being that it may perform better as some of processing (such as
+ * quoting of certain characters, or encoding into external encoding
+ * if supported by generator) can be done just once and reused for
+ * later calls.
+ *
+ * Default implementation simple uses unprocessed name container in
+ * serialized String; implementations are strongly encouraged to make
+ * use of more efficient methods argument object has.
+ */
+ public abstract void writeFieldName(SerializableString name) throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, text/String values
+ /**********************************************************
+ */
+
+ /**
+ * Method for outputting a String value. Depending on context
+ * this means either array element, (object) field value or
+ * a stand alone String; but in all cases, String will be
+ * surrounded in double quotes, and contents will be properly
+ * escaped as required by JSON specification.
+ */
+ public abstract void writeString(String text) throws IOException;
+
+ /**
+ * Method for outputting a String value. Depending on context
+ * this means either array element, (object) field value or
+ * a stand alone String; but in all cases, String will be
+ * surrounded in double quotes, and contents will be properly
+ * escaped as required by JSON specification.
+ */
+ public abstract void writeString(char[] text, int offset, int len) throws IOException;
+
+ /**
+ * Method similar to {@link #writeString(String)}, but that takes
+ * {@link SerializableString} which can make this potentially
+ * more efficient to call as generator may be able to reuse
+ * quoted and/or encoded representation.
+ *
+ * Default implementation just calls {@link #writeString(String)};
+ * sub-classes should override it with more efficient implementation
+ * if possible.
+ */
+ public abstract void writeString(SerializableString text) throws IOException;
+
+ /**
+ * Method similar to {@link #writeString(String)} but that takes as
+ * its input a UTF-8 encoded String that is to be output as-is, without additional
+ * escaping (type of which depends on data format; backslashes for JSON).
+ * However, quoting that data format requires (like double-quotes for JSON) will be added
+ * around the value if and as necessary.
+ *
+ * Note that some backends may choose not to support this method: for
+ * example, if underlying destination is a {@link java.io.Writer}
+ * using this method would require UTF-8 decoding.
+ * If so, implementation may instead choose to throw a
+ * {@link UnsupportedOperationException} due to ineffectiveness
+ * of having to decode input.
+ */
+ public abstract void writeRawUTF8String(byte[] text, int offset, int length)
+ throws IOException;
+
+ /**
+ * Method similar to {@link #writeString(String)} but that takes as its input
+ * a UTF-8 encoded String which has not been escaped using whatever
+ * escaping scheme data format requires (for JSON that is backslash-escaping
+ * for control characters and double-quotes; for other formats something else).
+ * This means that textual JSON backends need to check if value needs
+ * JSON escaping, but otherwise can just be copied as is to output.
+ * Also, quoting that data format requires (like double-quotes for JSON) will be added
+ * around the value if and as necessary.
+ *
+ * Note that some backends may choose not to support this method: for
+ * example, if underlying destination is a {@link java.io.Writer}
+ * using this method would require UTF-8 decoding.
+ * In this case
+ * generator implementation may instead choose to throw a
+ * {@link UnsupportedOperationException} due to ineffectiveness
+ * of having to decode input.
+ */
+ public abstract void writeUTF8String(byte[] text, int offset, int length)
+ throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, binary/raw content
+ /**********************************************************
+ */
+
+ /**
+ * Method that will force generator to copy
+ * input text verbatim with no modifications (including
+ * that no escaping is done and no separators are added even
+ * if context [array, object] would otherwise require such).
+ * If such separators are desired, use
+ * {@link #writeRawValue(String)} instead.
+ *
+ * Note that not all generator implementations necessarily support
+ * such by-pass methods: those that do not will throw
+ * {@link UnsupportedOperationException}.
+ */
+ public abstract void writeRaw(String text) throws IOException;
+
+ /**
+ * Method that will force generator to copy
+ * input text verbatim with no modifications (including
+ * that no escaping is done and no separators are added even
+ * if context [array, object] would otherwise require such).
+ * If such separators are desired, use
+ * {@link #writeRawValue(String)} instead.
+ *
+ * Note that not all generator implementations necessarily support
+ * such by-pass methods: those that do not will throw
+ * {@link UnsupportedOperationException}.
+ */
+ public abstract void writeRaw(String text, int offset, int len) throws IOException;
+
+ /**
+ * Method that will force generator to copy
+ * input text verbatim with no modifications (including
+ * that no escaping is done and no separators are added even
+ * if context [array, object] would otherwise require such).
+ * If such separators are desired, use
+ * {@link #writeRawValue(String)} instead.
+ *
+ * Note that not all generator implementations necessarily support
+ * such by-pass methods: those that do not will throw
+ * {@link UnsupportedOperationException}.
+ */
+ public abstract void writeRaw(char[] text, int offset, int len) throws IOException;
+
+ /**
+ * Method that will force generator to copy
+ * input text verbatim with no modifications (including
+ * that no escaping is done and no separators are added even
+ * if context [array, object] would otherwise require such).
+ * If such separators are desired, use
+ * {@link #writeRawValue(String)} instead.
+ *
+ * Note that not all generator implementations necessarily support
+ * such by-pass methods: those that do not will throw
+ * {@link UnsupportedOperationException}.
+ */
+ public abstract void writeRaw(char c) throws IOException;
+
+ /**
+ * Method that will force generator to copy
+ * input text verbatim with no modifications (including
+ * that no escaping is done and no separators are added even
+ * if context [array, object] would otherwise require such).
+ * If such separators are desired, use
+ * {@link #writeRawValue(String)} instead.
+ *
+ * Note that not all generator implementations necessarily support
+ * such by-pass methods: those that do not will throw
+ * {@link UnsupportedOperationException}.
+ *
+ * The default implementation delegates to {@link #writeRaw(String)};
+ * other backends that support raw inclusion of text are encouraged
+ * to implement it in more efficient manner (especially if they
+ * use UTF-8 encoding).
+ *
+ * @since 2.1
+ */
+ public void writeRaw(SerializableString raw) throws IOException {
+ writeRaw(raw.getValue());
+ }
+
+ /**
+ * Method that will force generator to copy
+ * input text verbatim without any modifications, but assuming
+ * it must constitute a single legal JSON value (number, string,
+ * boolean, null, Array or List). Assuming this, proper separators
+ * are added if and as needed (comma or colon), and generator
+ * state updated to reflect this.
+ */
+ public abstract void writeRawValue(String text) throws IOException;
+
+ public abstract void writeRawValue(String text, int offset, int len) throws IOException;
+
+ public abstract void writeRawValue(char[] text, int offset, int len) throws IOException;
+
+ /**
+ * Method similar to {@link #writeRawValue(String)}, but potentially more
+ * efficient as it may be able to use pre-encoded content (similar to
+ * {@link #writeRaw(SerializableString)}.
+ *
+ * @since 2.5
+ */
+ public void writeRawValue(SerializableString raw) throws IOException {
+ writeRawValue(raw.getValue());
+ }
+
+ /**
+ * Method that will output given chunk of binary data as base64
+ * encoded, as a complete String value (surrounded by double quotes).
+ * This method defaults
+ *
+ * Note: because JSON Strings can not contain unescaped linefeeds,
+ * if linefeeds are included (as per last argument), they must be
+ * escaped. This adds overhead for decoding without improving
+ * readability.
+ * Alternatively if linefeeds are not included,
+ * resulting String value may violate the requirement of base64
+ * RFC which mandates line-length of 76 characters and use of
+ * linefeeds. However, all {@link JsonParser} implementations
+ * are required to accept such "long line base64"; as do
+ * typical production-level base64 decoders.
+ *
+ * @param bv Base64 variant to use: defines details such as
+ * whether padding is used (and if so, using which character);
+ * what is the maximum line length before adding linefeed,
+ * and also the underlying alphabet to use.
+ */
+ public abstract void writeBinary(Base64Variant bv,
+ byte[] data, int offset, int len) throws IOException;
+
+ /**
+ * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)},
+ * but default to using the Jackson default Base64 variant
+ * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}).
+ */
+ public void writeBinary(byte[] data, int offset, int len) throws IOException {
+ writeBinary(Base64Variants.getDefaultVariant(), data, offset, len);
+ }
+
+ /**
+ * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)},
+ * but assumes default to using the Jackson default Base64 variant
+ * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}). Also
+ * assumes that whole byte array is to be output.
+ */
+ public void writeBinary(byte[] data) throws IOException {
+ writeBinary(Base64Variants.getDefaultVariant(), data, 0, data.length);
+ }
+
+ /**
+ * Similar to {@link #writeBinary(Base64Variant,InputStream,int)},
+ * but assumes default to using the Jackson default Base64 variant
+ * (which is {@link Base64Variants#MIME_NO_LINEFEEDS}).
+ *
+ * @param data InputStream to use for reading binary data to write.
+ * Will not be closed after successful write operation
+ * @param dataLength (optional) number of bytes that will be available;
+ * or -1 to be indicate it is not known. Note that implementations
+ * need not support cases where length is not known in advance; this
+ * depends on underlying data format: JSON output does NOT require length,
+ * other formats may
+ */
+ public int writeBinary(InputStream data, int dataLength)
+ throws IOException {
+ return writeBinary(Base64Variants.getDefaultVariant(), data, dataLength);
+ }
+
+ /**
+ * Method similar to {@link #writeBinary(Base64Variant,byte[],int,int)},
+ * but where input is provided through a stream, allowing for incremental
+ * writes without holding the whole input in memory.
+ *
+ * @param bv Base64 variant to use
+ * @param data InputStream to use for reading binary data to write.
+ * Will not be closed after successful write operation
+ * @param dataLength (optional) number of bytes that will be available;
+ * or -1 to be indicate it is not known.
+ * If a positive length is given,
+ * Note: because of lack of type safety, some generator
+ * implementations may not be able to implement this
+ * method. For example, if a binary JSON format is used,
+ * it may require type information for encoding; similarly
+ * for generator-wrappers around Java objects or JSON nodes.
+ * If implementation does not implement this method,
+ * it needs to throw {@link UnsupportedOperationException}.
+ *
+ * @throws UnsupportedOperationException If underlying data format does not
+ * support numbers serialized textually AND if generator is not allowed
+ * to just output a String instead (Schema-based formats may require actual
+ * number, for example)
+ */
+ public abstract void writeNumber(String encodedValue) throws IOException;
+
+ /**
+ * Method for outputting literal JSON boolean value (one of
+ * Strings 'true' and 'false').
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ */
+ public abstract void writeBoolean(boolean state) throws IOException;
+
+ /**
+ * Method for outputting literal JSON null value.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ */
+ public abstract void writeNull() throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, Native Ids (type, object)
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be called to output so-called native Object Id.
+ * Note that it may only be called after ensuring this is legal
+ * (with {@link #canWriteObjectId()}), as not all data formats
+ * have native type id support; and some may only allow them in
+ * certain positions or locations.
+ * If output is not allowed by the data format in this position,
+ * a {@link JsonGenerationException} will be thrown.
+ *
+ * @since 2.3
+ */
+ public void writeObjectId(Object id) throws IOException {
+ throw new JsonGenerationException("No native support for writing Object Ids", this);
+ }
+
+ /**
+ * Method that can be called to output references to native Object Ids.
+ * Note that it may only be called after ensuring this is legal
+ * (with {@link #canWriteObjectId()}), as not all data formats
+ * have native type id support; and some may only allow them in
+ * certain positions or locations.
+ * If output is not allowed by the data format in this position,
+ * a {@link JsonGenerationException} will be thrown.
+ */
+ public void writeObjectRef(Object id) throws IOException {
+ throw new JsonGenerationException("No native support for writing Object Ids", this);
+ }
+
+ /**
+ * Method that can be called to output so-called native Type Id.
+ * Note that it may only be called after ensuring this is legal
+ * (with {@link #canWriteTypeId()}), as not all data formats
+ * have native type id support; and some may only allow them in
+ * certain positions or locations.
+ * If output is not allowed by the data format in this position,
+ * a {@link JsonGenerationException} will be thrown.
+ *
+ * @since 2.3
+ */
+ public void writeTypeId(Object id) throws IOException {
+ throw new JsonGenerationException("No native support for writing Type Ids", this);
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, serializing Java objects
+ /**********************************************************
+ */
+
+ /**
+ * Method for writing given Java object (POJO) as Json.
+ * Exactly how the object gets written depends on object
+ * in question (ad on codec, its configuration); for most
+ * beans it will result in JSON Object, but for others JSON
+ * Array, or String or numeric value (and for nulls, JSON
+ * null literal.
+ * NOTE: generator must have its object codec
+ * set to non-null value; for generators created by a mapping
+ * factory this is the case, for others not.
+ */
+ public abstract void writeObject(Object pojo) throws IOException;
+
+ /**
+ * Method for writing given JSON tree (expressed as a tree
+ * where given JsonNode is the root) using this generator.
+ * This will generally just call
+ * {@link #writeObject} with given node, but is added
+ * for convenience and to make code more explicit in cases
+ * where it deals specifically with trees.
+ */
+ public abstract void writeTree(TreeNode rootNode) throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, convenience field write methods
+ /**********************************************************
+ */
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has a String value. Equivalent to:
+ *
+ * Note: many performance-sensitive implementations override this method
+ */
+ public void writeStringField(String fieldName, String value) throws IOException {
+ writeFieldName(fieldName);
+ writeString(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has a boolean value. Equivalent to:
+ *
+ * Note: caller still has to take care to close the array
+ * (by calling {#link #writeEndArray}) after writing all values
+ * of the value Array.
+ */
+ public final void writeArrayFieldStart(String fieldName) throws IOException {
+ writeFieldName(fieldName);
+ writeStartArray();
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * (that will contain a JSON Object value), and the START_OBJECT marker.
+ * Equivalent to:
+ *
+ * Note: caller still has to take care to close the Object
+ * (by calling {#link #writeEndObject}) after writing all
+ * entries of the value Object.
+ */
+ public final void writeObjectFieldStart(String fieldName) throws IOException {
+ writeFieldName(fieldName);
+ writeStartObject();
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has contents of specific Java object as its value.
+ * Equivalent to:
+ *
+ * Default implementation does nothing.
+ *
+ * @since 2.3
+ */
+ public void writeOmittedField(String fieldName) throws IOException { }
+
+ /*
+ /**********************************************************
+ /* Public API, copy-through methods
+ /**********************************************************
+ */
+
+ /**
+ * Method for copying contents of the current event that
+ * the given parser instance points to.
+ * Note that the method will not copy any other events,
+ * such as events contained within JSON Array or Object structures.
+ *
+ * Calling this method will not advance the given
+ * parser, although it may cause parser to internally process
+ * more data (if it lazy loads contents of value events, for example)
+ */
+ public void copyCurrentEvent(JsonParser p) throws IOException
+ {
+ JsonToken t = p.getCurrentToken();
+ // sanity check; what to do?
+ if (t == null) {
+ _reportError("No current event to copy");
+ }
+ switch (t.id()) {
+ case ID_NOT_AVAILABLE:
+ _reportError("No current event to copy");
+ case ID_START_OBJECT:
+ writeStartObject();
+ break;
+ case ID_END_OBJECT:
+ writeEndObject();
+ break;
+ case ID_START_ARRAY:
+ writeStartArray();
+ break;
+ case ID_END_ARRAY:
+ writeEndArray();
+ break;
+ case ID_FIELD_NAME:
+ writeFieldName(p.getCurrentName());
+ break;
+ case ID_STRING:
+ if (p.hasTextCharacters()) {
+ writeString(p.getTextCharacters(), p.getTextOffset(), p.getTextLength());
+ } else {
+ writeString(p.getText());
+ }
+ break;
+ case ID_NUMBER_INT:
+ {
+ NumberType n = p.getNumberType();
+ if (n == NumberType.INT) {
+ writeNumber(p.getIntValue());
+ } else if (n == NumberType.BIG_INTEGER) {
+ writeNumber(p.getBigIntegerValue());
+ } else {
+ writeNumber(p.getLongValue());
+ }
+ break;
+ }
+ case ID_NUMBER_FLOAT:
+ {
+ NumberType n = p.getNumberType();
+ if (n == NumberType.BIG_DECIMAL) {
+ writeNumber(p.getDecimalValue());
+ } else if (n == NumberType.FLOAT) {
+ writeNumber(p.getFloatValue());
+ } else {
+ writeNumber(p.getDoubleValue());
+ }
+ break;
+ }
+ case ID_TRUE:
+ writeBoolean(true);
+ break;
+ case ID_FALSE:
+ writeBoolean(false);
+ break;
+ case ID_NULL:
+ writeNull();
+ break;
+ case ID_EMBEDDED_OBJECT:
+ writeObject(p.getEmbeddedObject());
+ break;
+ default:
+ _throwInternal();
+ }
+ }
+
+ /**
+ * Method for copying contents of the current event
+ * and following events that it encloses
+ * the given parser instance points to.
+ *
+ * So what constitutes enclosing? Here is the list of
+ * events that have associated enclosed events that will
+ * get copied:
+ *
+ * After calling this method, parser will point to the
+ * last event that was copied. This will either be
+ * the event parser already pointed to (if there were no
+ * enclosed events), or the last enclosed event copied.
+ */
+ public void copyCurrentStructure(JsonParser p) throws IOException
+ {
+ JsonToken t = p.getCurrentToken();
+ if (t == null) {
+ _reportError("No current event to copy");
+ }
+ // Let's handle field-name separately first
+ int id = t.id();
+ if (id == ID_FIELD_NAME) {
+ writeFieldName(p.getCurrentName());
+ t = p.nextToken();
+ id = t.id();
+ // fall-through to copy the associated value
+ }
+ switch (id) {
+ case ID_START_OBJECT:
+ writeStartObject();
+ while (p.nextToken() != JsonToken.END_OBJECT) {
+ copyCurrentStructure(p);
+ }
+ writeEndObject();
+ break;
+ case ID_START_ARRAY:
+ writeStartArray();
+ while (p.nextToken() != JsonToken.END_ARRAY) {
+ copyCurrentStructure(p);
+ }
+ writeEndArray();
+ break;
+ default:
+ copyCurrentEvent(p);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, context access
+ /**********************************************************
+ */
+
+ /**
+ * @return Context object that can give information about logical
+ * position within generated json content.
+ */
+ public abstract JsonStreamContext getOutputContext();
+
+ /*
+ /**********************************************************
+ /* Public API, buffer handling
+ /**********************************************************
+ */
+
+ /**
+ * Method called to flush any buffered content to the underlying
+ * target (output stream, writer), and to flush the target itself
+ * as well.
+ */
+ @Override
+ public abstract void flush() throws IOException;
+
+ /**
+ * Method that can be called to determine whether this generator
+ * is closed or not. If it is closed, no more output can be done.
+ */
+ public abstract boolean isClosed();
+
+ /*
+ /**********************************************************
+ /* Closeable implementation
+ /**********************************************************
+ */
+
+ /**
+ * Method called to close this generator, so that no more content
+ * can be written.
+ *
+ * Whether the underlying target (stream, writer) gets closed depends
+ * on whether this generator either manages the target (i.e. is the
+ * only one with access to the target -- case if caller passes a
+ * reference to the resource such as File, but not stream); or
+ * has feature {@link Feature#AUTO_CLOSE_TARGET} enabled.
+ * If either of above is true, the target is also closed. Otherwise
+ * (not managing, feature not enabled), target is not closed.
+ */
+ @Override
+ public abstract void close() throws IOException;
+
+ /*
+ /**********************************************************
+ /* Helper methods for sub-classes
+ /**********************************************************
+ */
+
+ /**
+ * Helper method used for constructing and throwing
+ * {@link JsonGenerationException} with given base message.
+ *
+ * Note that sub-classes may override this method to add more detail
+ * or use a {@link JsonGenerationException} sub-class.
+ */
+ protected void _reportError(String msg) throws JsonGenerationException {
+ throw new JsonGenerationException(msg, this);
+ }
+
+ protected final void _throwInternal() { VersionUtil.throwInternal(); }
+
+ protected void _reportUnsupportedOperation() {
+ throw new UnsupportedOperationException("Operation not supported by generator of type "+getClass().getName());
+ }
+
+ /**
+ * Helper method to try to call appropriate write method for given
+ * untyped Object. At this point, no structural conversions should be done,
+ * only simple basic types are to be coerced as necessary.
+ *
+ * @param value Non-null value to write
+ */
+ protected void _writeSimpleObject(Object value) throws IOException
+ {
+ /* 31-Dec-2009, tatu: Actually, we could just handle some basic
+ * types even without codec. This can improve interoperability,
+ * and specifically help with TokenBuffer.
+ */
+ if (value == null) {
+ writeNull();
+ return;
+ }
+ if (value instanceof String) {
+ writeString((String) value);
+ return;
+ }
+ if (value instanceof Number) {
+ Number n = (Number) value;
+ if (n instanceof Integer) {
+ writeNumber(n.intValue());
+ return;
+ } else if (n instanceof Long) {
+ writeNumber(n.longValue());
+ return;
+ } else if (n instanceof Double) {
+ writeNumber(n.doubleValue());
+ return;
+ } else if (n instanceof Float) {
+ writeNumber(n.floatValue());
+ return;
+ } else if (n instanceof Short) {
+ writeNumber(n.shortValue());
+ return;
+ } else if (n instanceof Byte) {
+ writeNumber(n.byteValue());
+ return;
+ } else if (n instanceof BigInteger) {
+ writeNumber((BigInteger) n);
+ return;
+ } else if (n instanceof BigDecimal) {
+ writeNumber((BigDecimal) n);
+ return;
+
+ // then Atomic types
+ } else if (n instanceof AtomicInteger) {
+ writeNumber(((AtomicInteger) n).get());
+ return;
+ } else if (n instanceof AtomicLong) {
+ writeNumber(((AtomicLong) n).get());
+ return;
+ }
+ } else if (value instanceof byte[]) {
+ writeBinary((byte[]) value);
+ return;
+ } else if (value instanceof Boolean) {
+ writeBoolean((Boolean) value);
+ return;
+ } else if (value instanceof AtomicBoolean) {
+ writeBoolean(((AtomicBoolean) value).get());
+ return;
+ }
+ throw new IllegalStateException("No ObjectCodec defined for the generator, can only serialize simple wrapper types (type passed "
+ +value.getClass().getName()+")");
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonLocation.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonLocation.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonLocation.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,139 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Object that encapsulates Location information used for reporting
+ * parsing (or potentially generation) errors, as well as current location
+ * within input streams.
+ */
+public class JsonLocation
+ implements java.io.Serializable // as per [JACKSON-168]
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Shared immutable "N/A location" that can be returned to indicate
+ * that no location information is available
+ */
+ public final static JsonLocation NA = new JsonLocation("N/A", -1L, -1L, -1, -1);
+
+ final long _totalBytes;
+ final long _totalChars;
+
+ final int _lineNr;
+ final int _columnNr;
+
+ /**
+ * Displayable description for input source: file path, URL.
+ *
+ * NOTE:
+ * Feature is enabled by default.
+ */
+ AUTO_CLOSE_SOURCE(true),
+
+ // // // Support for non-standard data format constructs
+
+ /**
+ * Feature that determines whether parser will allow use
+ * of Java/C++ style comments (both '/'+'*' and
+ * '//' varieties) within parsed content or not.
+ *
+ * Since JSON specification does not mention comments as legal
+ * construct,
+ * this is a non-standard feature; however, in the wild
+ * this is extensively used. As such, feature is
+ * disabled by default for parsers and must be
+ * explicitly enabled.
+ */
+ ALLOW_COMMENTS(false),
+
+ /**
+ * Feature that determines whether parser will allow use
+ * of YAML comments, ones starting with '#' and continuing
+ * until the end of the line. This commenting style is common
+ * with scripting languages as well.
+ *
+ * Since JSON specification does not mention comments as legal
+ * construct,
+ * this is a non-standard feature. As such, feature is
+ * disabled by default for parsers and must be
+ * explicitly enabled.
+ */
+ ALLOW_YAML_COMMENTS(false),
+
+ /**
+ * Feature that determines whether parser will allow use
+ * of unquoted field names (which is allowed by Javascript,
+ * but not by JSON specification).
+ *
+ * Since JSON specification requires use of double quotes for
+ * field names,
+ * this is a non-standard feature, and as such disabled by default.
+ */
+ ALLOW_UNQUOTED_FIELD_NAMES(false),
+
+ /**
+ * Feature that determines whether parser will allow use
+ * of single quotes (apostrophe, character '\'') for
+ * quoting Strings (names and String values). If so,
+ * this is in addition to other acceptable markers.
+ * but not by JSON specification).
+ *
+ * Since JSON specification requires use of double quotes for
+ * field names,
+ * this is a non-standard feature, and as such disabled by default.
+ */
+ ALLOW_SINGLE_QUOTES(false),
+
+ /**
+ * Feature that determines whether parser will allow
+ * JSON Strings to contain unquoted control characters
+ * (ASCII characters with value less than 32, including
+ * tab and line feed characters) or not.
+ * If feature is set false, an exception is thrown if such a
+ * character is encountered.
+ *
+ * Since JSON specification requires quoting for all control characters,
+ * this is a non-standard feature, and as such disabled by default.
+ */
+ ALLOW_UNQUOTED_CONTROL_CHARS(false),
+
+ /**
+ * Feature that can be enabled to accept quoting of all character
+ * using backslash quoting mechanism: if not enabled, only characters
+ * that are explicitly listed by JSON specification can be thus
+ * escaped (see JSON spec for small list of these characters)
+ *
+ * Since JSON specification requires quoting for all control characters,
+ * this is a non-standard feature, and as such disabled by default.
+ */
+ ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false),
+
+ /**
+ * Feature that determines whether parser will allow
+ * JSON integral numbers to start with additional (ignorable)
+ * zeroes (like: 000001). If enabled, no exception is thrown, and extra
+ * nulls are silently ignored (and not included in textual representation
+ * exposed via {@link JsonParser#getText}).
+ *
+ * Since JSON specification does not allow leading zeroes,
+ * this is a non-standard feature, and as such disabled by default.
+ */
+ ALLOW_NUMERIC_LEADING_ZEROS(false),
+
+ /**
+ * Feature that allows parser to recognize set of
+ * "Not-a-Number" (NaN) tokens as legal floating number
+ * values (similar to how many other data formats and
+ * programming language source code allows it).
+ * Specific subset contains values that
+ * XML Schema
+ * (see section 3.2.4.1, Lexical Representation)
+ * allows (tokens are quoted contents, not including quotes):
+ *
+ * Since JSON specification does not allow use of such values,
+ * this is a non-standard feature, and as such disabled by default.
+ */
+ ALLOW_NON_NUMERIC_NUMBERS(false),
+
+ /**
+ * Feature that determines whether {@link JsonParser} will explicitly
+ * check that no duplicate JSON Object field names are encountered.
+ * If enabled, parser will check all names within context and report
+ * duplicates by throwing a {@link JsonParseException}; if disabled,
+ * parser will not do such checking. Assumption in latter case is
+ * that caller takes care of handling duplicates at a higher level:
+ * data-binding, for example, has features to specify detection to
+ * be done there.
+ *
+ * Note that enabling this feature will incur performance overhead
+ * due to having to store and check additional information: this typically
+ * adds 20-30% to execution time for basic parsing.
+ *
+ * @since 2.3
+ */
+ STRICT_DUPLICATE_DETECTION(false),
+
+ /**
+ * Feature that determines what to do if the underlying data format requires knowledge
+ * of all properties to decode (usually via a Schema), and if no definition is
+ * found for a property that input content contains.
+ * Typically most textual data formats do NOT require schema information (although
+ * some do, such as CSV), whereas many binary data formats do require definitions
+ * (such as Avro, protobuf), although not all (Smile, CBOR, BSON and MessagePack do not).
+ * Further note that some formats that do require schema information will not be able
+ * to ignore undefined properties: for example, Avro is fully positional and there is
+ * no possibility of undefined data. This leaves formats like Protobuf that have identifiers
+ * that may or may not map; and as such Protobuf format does make use of this feature.
+ *
+ * Note that support for this feature is implemented by individual data format
+ * module, if (and only if) it makes sense for the format in question. For JSON,
+ * for example, this feature has no effect as properties need not be pre-defined.
+ *
+ * Feature is disabled by default, meaning that if the underlying data format
+ * requires knowledge of all properties to output, attempts to read an unknown
+ * property will result in a {@link JsonProcessingException}
+ *
+ * @since 2.6
+ */
+ IGNORE_UNDEFINED(false)
+ ;
+
+ /**
+ * Whether feature is enabled or disabled by default.
+ */
+ private final boolean _defaultState;
+
+ private final int _mask;
+
+ /**
+ * Method that calculates bit set (flags) of all features that
+ * are enabled by default.
+ */
+ public static int collectDefaults()
+ {
+ int flags = 0;
+ for (Feature f : values()) {
+ if (f.enabledByDefault()) {
+ flags |= f.getMask();
+ }
+ }
+ return flags;
+ }
+
+ private Feature(boolean defaultState) {
+ _mask = (1 << ordinal());
+ _defaultState = defaultState;
+ }
+
+ public boolean enabledByDefault() { return _defaultState; }
+
+ /**
+ * @since 2.3
+ */
+ public boolean enabledIn(int flags) { return (flags & _mask) != 0; }
+
+ public int getMask() { return _mask; }
+ }
+
+ /*
+ /**********************************************************
+ /* Minimal configuration state
+ /**********************************************************
+ */
+
+ /**
+ * Bit flag composed of bits that indicate which
+ * {@link com.fasterxml.jackson.core.JsonParser.Feature}s
+ * are enabled.
+ */
+ protected int _features;
+
+ /*
+ /**********************************************************
+ /* Construction, configuration, initialization
+ /**********************************************************
+ */
+
+ protected JsonParser() { }
+ protected JsonParser(int features) { _features = features; }
+
+ /**
+ * Accessor for {@link ObjectCodec} associated with this
+ * parser, if any. Codec is used by {@link #readValueAs(Class)}
+ * method (and its variants).
+ */
+ public abstract ObjectCodec getCodec();
+
+ /**
+ * Setter that allows defining {@link ObjectCodec} associated with this
+ * parser, if any. Codec is used by {@link #readValueAs(Class)}
+ * method (and its variants).
+ */
+ public abstract void setCodec(ObjectCodec c);
+
+ /**
+ * Method that can be used to get access to object that is used
+ * to access input being parsed; this is usually either
+ * {@link InputStream} or {@link Reader}, depending on what
+ * parser was constructed with.
+ * Note that returned value may be null in some cases; including
+ * case where parser implementation does not want to exposed raw
+ * source to caller.
+ * In cases where input has been decorated, object returned here
+ * is the decorated version; this allows some level of interaction
+ * between users of parser and decorator object.
+ *
+ * In general use of this accessor should be considered as
+ * "last effort", i.e. only used if no other mechanism is applicable.
+ */
+ public Object getInputSource() { return null; }
+
+ /**
+ * Helper method, usually equivalent to:
+ *
+ * Note that "current value" is NOT populated (or used) by Streaming parser;
+ * it is only used by higher-level data-binding functionality.
+ * The reason it is included here is that it can be stored and accessed hierarchically,
+ * and gets passed through data-binding.
+ *
+ * @since 2.5
+ */
+ public Object getCurrentValue() {
+ JsonStreamContext ctxt = getParsingContext();
+ return (ctxt == null) ? null : ctxt.getCurrentValue();
+ }
+
+ /**
+ * Helper method, usually equivalent to:
+ *
+ * If parser does not support specified schema, {@link UnsupportedOperationException}
+ * is thrown.
+ *
+ * @param schema Schema to use
+ *
+ * @throws UnsupportedOperationException if parser does not support schema
+ */
+ public void setSchema(FormatSchema schema) {
+ throw new UnsupportedOperationException("Parser of type "+getClass().getName()+" does not support schema of type '"
+ +schema.getSchemaType()+"'");
+ }
+
+ /**
+ * Method for accessing Schema that this parser uses, if any.
+ * Default implementation returns null.
+ *
+ * @since 2.1
+ */
+ public FormatSchema getSchema() { return null; }
+
+ /**
+ * Method that can be used to verify that given schema can be used with
+ * this parser (using {@link #setSchema}).
+ *
+ * @param schema Schema to check
+ *
+ * @return True if this parser can use given schema; false if not
+ */
+ public boolean canUseSchema(FormatSchema schema) { return false; }
+
+ /*
+ /**********************************************************
+ /* Capability introspection
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be called to determine if a custom
+ * {@link ObjectCodec} is needed for binding data parsed
+ * using {@link JsonParser} constructed by this factory
+ * (which typically also implies the same for serialization
+ * with {@link JsonGenerator}).
+ *
+ * @return True if custom codec is needed with parsers and
+ * generators created by this factory; false if a general
+ * {@link ObjectCodec} is enough
+ *
+ * @since 2.1
+ */
+ public boolean requiresCustomCodec() { return false;}
+
+ /*
+ /**********************************************************
+ /* Versioned
+ /**********************************************************
+ */
+
+ /**
+ * Accessor for getting version of the core package, given a parser instance.
+ * Left for sub-classes to implement.
+ */
+ @Override
+ public abstract Version version();
+
+ /*
+ /**********************************************************
+ /* Closeable implementation
+ /**********************************************************
+ */
+
+ /**
+ * Closes the parser so that no further iteration or data access
+ * can be made; will also close the underlying input source
+ * if parser either owns the input source, or feature
+ * {@link Feature#AUTO_CLOSE_SOURCE} is enabled.
+ * Whether parser owns the input source depends on factory
+ * method that was used to construct instance (so check
+ * {@link com.fasterxml.jackson.core.JsonFactory} for details,
+ * but the general
+ * idea is that if caller passes in closable resource (such
+ * as {@link InputStream} or {@link Reader}) parser does NOT
+ * own the source; but if it passes a reference (such as
+ * {@link java.io.File} or {@link java.net.URL} and creates
+ * stream or reader it does own them.
+ */
+ @Override
+ public abstract void close() throws IOException;
+
+ /*
+ /**********************************************************
+ /* Buffer handling
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be called to push back any content that
+ * has been read but not consumed by the parser. This is usually
+ * done after reading all content of interest using parser.
+ * Content is released by writing it to given stream if possible;
+ * if underlying input is byte-based it can released, if not (char-based)
+ * it can not.
+ *
+ * @return -1 if the underlying content source is not byte based
+ * (that is, input can not be sent to {@link OutputStream};
+ * otherwise number of bytes released (0 if there was nothing to release)
+ *
+ * @throws IOException if write to stream threw exception
+ */
+ public int releaseBuffered(OutputStream out) throws IOException {
+ return -1;
+ }
+
+ /**
+ * Method that can be called to push back any content that
+ * has been read but not consumed by the parser.
+ * This is usually
+ * done after reading all content of interest using parser.
+ * Content is released by writing it to given writer if possible;
+ * if underlying input is char-based it can released, if not (byte-based)
+ * it can not.
+ *
+ * @return -1 if the underlying content source is not char-based
+ * (that is, input can not be sent to {@link Writer};
+ * otherwise number of chars released (0 if there was nothing to release)
+ *
+ * @throws IOException if write using Writer threw exception
+ */
+ public int releaseBuffered(Writer w) throws IOException { return -1; }
+
+ /*
+ /***************************************************
+ /* Public API, configuration
+ /***************************************************
+ */
+
+ /**
+ * Method for enabling specified parser feature
+ * (check {@link Feature} for list of features)
+ */
+ public JsonParser enable(Feature f) {
+ _features |= f.getMask();
+ return this;
+ }
+
+ /**
+ * Method for disabling specified feature
+ * (check {@link Feature} for list of features)
+ */
+ public JsonParser disable(Feature f) {
+ _features &= ~f.getMask();
+ return this;
+ }
+
+ /**
+ * Method for enabling or disabling specified feature
+ * (check {@link Feature} for list of features)
+ */
+ public JsonParser configure(Feature f, boolean state) {
+ if (state) enable(f); else disable(f);
+ return this;
+ }
+
+ /**
+ * Method for checking whether specified {@link Feature} is enabled.
+ */
+ public boolean isEnabled(Feature f) { return f.enabledIn(_features); }
+
+ /**
+ * Bulk access method for getting state of all standard {@link Feature}s.
+ *
+ * @return Bit mask that defines current states of all standard {@link Feature}s.
+ *
+ * @since 2.3
+ */
+ public int getFeatureMask() { return _features; }
+
+ /**
+ * Bulk set method for (re)setting states of all standard {@link Feature}s
+ *
+ * @return This parser object, to allow chaining of calls
+ *
+ * @since 2.3
+ *
+ * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead
+ */
+ @Deprecated
+ public JsonParser setFeatureMask(int mask) {
+ _features = mask;
+ return this;
+ }
+
+ /**
+ * Bulk set method for (re)setting states of features specified by
+ * Default implementation will simply throw an exception to indicate that
+ * the generator implementation does not support any {@link FormatFeature}s.
+ *
+ * @param values Bit mask of set/clear state for features to change
+ * @param mask Bit mask of features to change
+ *
+ * @since 2.6
+ */
+ public JsonParser overrideFormatFeatures(int values, int mask) {
+ throw new IllegalArgumentException("No FormatFeatures defined for parser of type "+getClass().getName());
+ /*
+ _formatFeatures = (_formatFeatures & ~mask) | (values & mask);
+ */
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, traversal
+ /**********************************************************
+ */
+
+ /**
+ * Main iteration method, which will advance stream enough
+ * to determine type of the next token, if any. If none
+ * remaining (stream has no content other than possible
+ * white space before ending), null will be returned.
+ *
+ * @return Next token from the stream, if any found, or null
+ * to indicate end-of-input
+ */
+ public abstract JsonToken nextToken() throws IOException, JsonParseException;
+
+ /**
+ * Iteration method that will advance stream enough
+ * to determine type of the next token that is a value type
+ * (including JSON Array and Object start/end markers).
+ * Or put another way, nextToken() will be called once,
+ * and if {@link JsonToken#FIELD_NAME} is returned, another
+ * time to get the value for the field.
+ * Method is most useful for iterating over value entries
+ * of JSON objects; field name will still be available
+ * by calling {@link #getCurrentName} when parser points to
+ * the value.
+ *
+ * @return Next non-field-name token from the stream, if any found,
+ * or null to indicate end-of-input (or, for non-blocking
+ * parsers, {@link JsonToken#NOT_AVAILABLE} if no tokens were
+ * available yet)
+ */
+ public abstract JsonToken nextValue() throws IOException, JsonParseException;
+
+ /**
+ * Method that fetches next token (as if calling {@link #nextToken}) and
+ * verifies whether it is {@link JsonToken#FIELD_NAME} with specified name
+ * and returns result of that comparison.
+ * It is functionally equivalent to:
+ *
+ * Use of int directly is typically more efficient on switch statements,
+ * so this method may be useful when building low-overhead codecs.
+ * Note, however, that effect may not be big enough to matter: make sure
+ * to profile performance before deciding to use this method.
+ *
+ * @since 2.3
+ *
+ * @return
+ * Note that no traversal or conversion is performed; so in some
+ * cases calling method like {@link #isExpectedStartArrayToken()}
+ * is necessary instead.
+ *
+ * @since 2.5
+ */
+ public abstract boolean hasTokenId(int id);
+
+ /**
+ * Method that is functionally equivalent to:
+ *
+ * Note that no traversal or conversion is performed; so in some
+ * cases calling method like {@link #isExpectedStartArrayToken()}
+ * is necessary instead.
+ *
+ * @since 2.6
+ */
+ public abstract boolean hasToken(JsonToken t);
+
+ /**
+ * Method that can be called to get the name associated with
+ * the current token: for {@link JsonToken#FIELD_NAME}s it will
+ * be the same as what {@link #getText} returns;
+ * for field values it will be preceding field name;
+ * and for others (array values, root-level values) null.
+ */
+ public abstract String getCurrentName() throws IOException;
+
+ /**
+ * Method that can be used to access current parsing context reader
+ * is in. There are 3 different types: root, array and object contexts,
+ * with slightly different available information. Contexts are
+ * hierarchically nested, and can be used for example for figuring
+ * out part of the input document that correspond to specific
+ * array or object (for highlighting purposes, or error reporting).
+ * Contexts can also be used for simple xpath-like matching of
+ * input, if so desired.
+ */
+ public abstract JsonStreamContext getParsingContext();
+
+ /**
+ * Method that return the starting location of the current
+ * token; that is, position of the first character from input
+ * that starts the current token.
+ */
+ public abstract JsonLocation getTokenLocation();
+
+ /**
+ * Method that returns location of the last processed character;
+ * usually for error reporting purposes.
+ */
+ public abstract JsonLocation getCurrentLocation();
+
+ /**
+ * Specialized accessor that can be used to verify that the current
+ * token indicates start array (usually meaning that current token
+ * is {@link JsonToken#START_ARRAY}) when start array is expected.
+ * For some specialized parsers this can return true for other cases
+ * as well; this is usually done to emulate arrays in cases underlying
+ * format is ambiguous (XML, for example, has no format-level difference
+ * between Objects and Arrays; it just has elements).
+ *
+ * Default implementation is equivalent to:
+ *
+ * Method was added to be used by the optional data binder, since
+ * it has to be able to consume last token used for binding (so that
+ * it will not be used again).
+ */
+ public abstract void clearCurrentToken();
+
+ /**
+ * Method that can be called to get the last token that was
+ * cleared using {@link #clearCurrentToken}. This is not necessarily
+ * the latest token read.
+ * Will return null if no tokens have been cleared,
+ * or if parser has been closed.
+ */
+ public abstract JsonToken getLastClearedToken();
+
+ /**
+ * Method that can be used to change what is considered to be
+ * the current (field) name.
+ * May be needed to support non-JSON data formats or unusual binding
+ * conventions; not needed for typical processing.
+ *
+ * Note that use of this method should only be done as sort of last
+ * resort, as it is a work-around for regular operation.
+ *
+ * @param name Name to use as the current name; may be null.
+ */
+ public abstract void overrideCurrentName(String name);
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, text
+ /**********************************************************
+ */
+
+ /**
+ * Method for accessing textual representation of the current token;
+ * if no current token (before first call to {@link #nextToken}, or
+ * after encountering end-of-input), returns null.
+ * Method can be called for any token type.
+ */
+ public abstract String getText() throws IOException;
+
+ /**
+ * Method similar to {@link #getText}, but that will return
+ * underlying (unmodifiable) character array that contains
+ * textual value, instead of constructing a String object
+ * to contain this information.
+ * Note, however, that:
+ *
+ * Note that caller MUST NOT modify the returned
+ * character array in any way -- doing so may corrupt
+ * current parser state and render parser instance useless.
+ *
+ * The only reason to call this method (over {@link #getText})
+ * is to avoid construction of a String object (which
+ * will make a copy of contents).
+ */
+ public abstract char[] getTextCharacters() throws IOException;
+
+ /**
+ * Accessor used with {@link #getTextCharacters}, to know length
+ * of String stored in returned buffer.
+ *
+ * @return Number of characters within buffer returned
+ * by {@link #getTextCharacters} that are part of
+ * textual content of the current token.
+ */
+ public abstract int getTextLength() throws IOException;
+
+ /**
+ * Accessor used with {@link #getTextCharacters}, to know offset
+ * of the first text content character within buffer.
+ *
+ * @return Offset of the first character within buffer returned
+ * by {@link #getTextCharacters} that is part of
+ * textual content of the current token.
+ */
+ public abstract int getTextOffset() throws IOException;
+
+ /**
+ * Method that can be used to determine whether calling of
+ * {@link #getTextCharacters} would be the most efficient
+ * way to access textual content for the event parser currently
+ * points to.
+ *
+ * Default implementation simply returns false since only actual
+ * implementation class has knowledge of its internal buffering
+ * state.
+ * Implementations are strongly encouraged to properly override
+ * this method, to allow efficient copying of content by other
+ * code.
+ *
+ * @return True if parser currently has character array that can
+ * be efficiently returned via {@link #getTextCharacters}; false
+ * means that it may or may not exist
+ */
+ public abstract boolean hasTextCharacters();
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, numeric
+ /**********************************************************
+ */
+
+ /**
+ * Generic number value accessor method that will work for
+ * all kinds of numeric values. It will return the optimal
+ * (simplest/smallest possible) wrapper object that can
+ * express the numeric value just parsed.
+ */
+ public abstract Number getNumberValue() throws IOException;
+
+ /**
+ * If current token is of type
+ * {@link JsonToken#VALUE_NUMBER_INT} or
+ * {@link JsonToken#VALUE_NUMBER_FLOAT}, returns
+ * one of {@link NumberType} constants; otherwise returns null.
+ */
+ public abstract NumberType getNumberType() throws IOException;
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_INT} and
+ * it can be expressed as a value of Java byte primitive type.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT};
+ * if so, it is equivalent to calling {@link #getDoubleValue}
+ * and then casting; except for possible overflow/underflow
+ * exception.
+ *
+ * Note: if the resulting integer value falls outside range of
+ * Java byte, a {@link JsonParseException}
+ * will be thrown to indicate numeric overflow/underflow.
+ */
+ public byte getByteValue() throws IOException {
+ int value = getIntValue();
+ // So far so good: but does it fit?
+ // [JACKSON-804]: Let's actually allow range of [-128, 255], as those are uniquely mapped
+ // (instead of just signed range of [-128, 127])
+ if (value < MIN_BYTE_I || value > MAX_BYTE_I) {
+ throw _constructError("Numeric value ("+getText()+") out of range of Java byte");
+ }
+ return (byte) value;
+ }
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_INT} and
+ * it can be expressed as a value of Java short primitive type.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT};
+ * if so, it is equivalent to calling {@link #getDoubleValue}
+ * and then casting; except for possible overflow/underflow
+ * exception.
+ *
+ * Note: if the resulting integer value falls outside range of
+ * Java short, a {@link JsonParseException}
+ * will be thrown to indicate numeric overflow/underflow.
+ */
+ public short getShortValue() throws IOException
+ {
+ int value = getIntValue();
+ if (value < MIN_SHORT_I || value > MAX_SHORT_I) {
+ throw _constructError("Numeric value ("+getText()+") out of range of Java short");
+ }
+ return (short) value;
+ }
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_INT} and
+ * it can be expressed as a value of Java int primitive type.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT};
+ * if so, it is equivalent to calling {@link #getDoubleValue}
+ * and then casting; except for possible overflow/underflow
+ * exception.
+ *
+ * Note: if the resulting integer value falls outside range of
+ * Java int, a {@link JsonParseException}
+ * may be thrown to indicate numeric overflow/underflow.
+ */
+ public abstract int getIntValue() throws IOException;
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_INT} and
+ * it can be expressed as a Java long primitive type.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT};
+ * if so, it is equivalent to calling {@link #getDoubleValue}
+ * and then casting to int; except for possible overflow/underflow
+ * exception.
+ *
+ * Note: if the token is an integer, but its value falls
+ * outside of range of Java long, a {@link JsonParseException}
+ * may be thrown to indicate numeric overflow/underflow.
+ */
+ public abstract long getLongValue() throws IOException;
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_INT} and
+ * it can not be used as a Java long primitive type due to its
+ * magnitude.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_FLOAT};
+ * if so, it is equivalent to calling {@link #getDecimalValue}
+ * and then constructing a {@link BigInteger} from that value.
+ */
+ public abstract BigInteger getBigIntegerValue() throws IOException;
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} and
+ * it can be expressed as a Java float primitive type.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_INT};
+ * if so, it is equivalent to calling {@link #getLongValue}
+ * and then casting; except for possible overflow/underflow
+ * exception.
+ *
+ * Note: if the value falls
+ * outside of range of Java float, a {@link JsonParseException}
+ * will be thrown to indicate numeric overflow/underflow.
+ */
+ public abstract float getFloatValue() throws IOException;
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} and
+ * it can be expressed as a Java double primitive type.
+ * It can also be called for {@link JsonToken#VALUE_NUMBER_INT};
+ * if so, it is equivalent to calling {@link #getLongValue}
+ * and then casting; except for possible overflow/underflow
+ * exception.
+ *
+ * Note: if the value falls
+ * outside of range of Java double, a {@link JsonParseException}
+ * will be thrown to indicate numeric overflow/underflow.
+ */
+ public abstract double getDoubleValue() throws IOException;
+
+ /**
+ * Numeric accessor that can be called when the current
+ * token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} or
+ * {@link JsonToken#VALUE_NUMBER_INT}. No under/overflow exceptions
+ * are ever thrown.
+ */
+ public abstract BigDecimal getDecimalValue() throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, other
+ /**********************************************************
+ */
+
+ /**
+ * Convenience accessor that can be called when the current
+ * token is {@link JsonToken#VALUE_TRUE} or
+ * {@link JsonToken#VALUE_FALSE}.
+ *
+ * Note: if the token is not of above-mentioned boolean types,
+ an integer, but its value falls
+ * outside of range of Java long, a {@link JsonParseException}
+ * may be thrown to indicate numeric overflow/underflow.
+ */
+ public boolean getBooleanValue() throws IOException {
+ JsonToken t = getCurrentToken();
+ if (t == JsonToken.VALUE_TRUE) return true;
+ if (t == JsonToken.VALUE_FALSE) return false;
+ throw new JsonParseException(this,
+ String.format("Current token (%s) not of boolean type", t));
+ }
+
+ /**
+ * Accessor that can be called if (and only if) the current token
+ * is {@link JsonToken#VALUE_EMBEDDED_OBJECT}. For other token types,
+ * null is returned.
+ *
+ * Note: only some specialized parser implementations support
+ * embedding of objects (usually ones that are facades on top
+ * of non-streaming sources, such as object trees).
+ */
+ public abstract Object getEmbeddedObject() throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, binary
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to read (and consume -- results
+ * may not be accessible using other methods after the call)
+ * base64-encoded binary data
+ * included in the current textual JSON value.
+ * It works similar to getting String value via {@link #getText}
+ * and decoding result (except for decoding part),
+ * but should be significantly more performant.
+ *
+ * Note that non-decoded textual contents of the current token
+ * are not guaranteed to be accessible after this method
+ * is called. Current implementation, for example, clears up
+ * textual content during decoding.
+ * Decoded binary content, however, will be retained until
+ * parser is advanced to the next event.
+ *
+ * @param bv Expected variant of base64 encoded
+ * content (see {@link Base64Variants} for definitions
+ * of "standard" variants).
+ *
+ * @return Decoded binary data
+ */
+ public abstract byte[] getBinaryValue(Base64Variant bv) throws IOException;
+
+ /**
+ * Convenience alternative to {@link #getBinaryValue(Base64Variant)}
+ * that defaults to using
+ * {@link Base64Variants#getDefaultVariant} as the default encoding.
+ */
+ public byte[] getBinaryValue() throws IOException {
+ return getBinaryValue(Base64Variants.getDefaultVariant());
+ }
+
+ /**
+ * Method that can be used as an alternative to {@link #getBigIntegerValue()},
+ * especially when value can be large. The main difference (beyond method
+ * of returning content using {@link OutputStream} instead of as byte array)
+ * is that content will NOT remain accessible after method returns: any content
+ * processed will be consumed and is not buffered in any way. If caller needs
+ * buffering, it has to implement it.
+ *
+ * @param out Output stream to use for passing decoded binary data
+ *
+ * @return Number of bytes that were decoded and written via {@link OutputStream}
+ *
+ * @since 2.1
+ */
+ public int readBinaryValue(OutputStream out) throws IOException {
+ return readBinaryValue(Base64Variants.getDefaultVariant(), out);
+ }
+
+ /**
+ * Similar to {@link #readBinaryValue(OutputStream)} but allows explicitly
+ * specifying base64 variant to use.
+ *
+ * @param bv base64 variant to use
+ * @param out Output stream to use for passing decoded binary data
+ *
+ * @return Number of bytes that were decoded and written via {@link OutputStream}
+ *
+ * @since 2.1
+ */
+ public int readBinaryValue(Base64Variant bv, OutputStream out) throws IOException {
+ _reportUnsupportedOperation();
+ return 0; // never gets here
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, coercion/conversion
+ /**********************************************************
+ */
+
+ /**
+ * Method that will try to convert value of current token to a
+ * int.
+ * Numbers are coerced using default Java rules; booleans convert to 0 (false)
+ * and 1 (true), and Strings are parsed using default Java language integer
+ * parsing rules.
+ *
+ * If representation can not be converted to an int (including structured type
+ * markers like start/end Object/Array)
+ * default value of 0 will be returned; no exceptions are thrown.
+ */
+ public int getValueAsInt() throws IOException {
+ return getValueAsInt(0);
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * int.
+ * Numbers are coerced using default Java rules; booleans convert to 0 (false)
+ * and 1 (true), and Strings are parsed using default Java language integer
+ * parsing rules.
+ *
+ * If representation can not be converted to an int (including structured type
+ * markers like start/end Object/Array)
+ * specified def will be returned; no exceptions are thrown.
+ */
+ public int getValueAsInt(int def) throws IOException { return def; }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * long.
+ * Numbers are coerced using default Java rules; booleans convert to 0 (false)
+ * and 1 (true), and Strings are parsed using default Java language integer
+ * parsing rules.
+ *
+ * If representation can not be converted to an int (including structured type
+ * markers like start/end Object/Array)
+ * default value of 0 will be returned; no exceptions are thrown.
+ */
+ public long getValueAsLong() throws IOException {
+ return getValueAsLong(0);
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * long.
+ * Numbers are coerced using default Java rules; booleans convert to 0 (false)
+ * and 1 (true), and Strings are parsed using default Java language integer
+ * parsing rules.
+ *
+ * If representation can not be converted to an int (including structured type
+ * markers like start/end Object/Array)
+ * specified def will be returned; no exceptions are thrown.
+ */
+ public long getValueAsLong(long def) throws IOException {
+ return def;
+ }
+
+ /**
+ * Method that will try to convert value of current token to a Java
+ * double.
+ * Numbers are coerced using default Java rules; booleans convert to 0.0 (false)
+ * and 1.0 (true), and Strings are parsed using default Java language integer
+ * parsing rules.
+ *
+ * If representation can not be converted to an int (including structured types
+ * like Objects and Arrays),
+ * default value of 0.0 will be returned; no exceptions are thrown.
+ */
+ public double getValueAsDouble() throws IOException {
+ return getValueAsDouble(0.0);
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * Java double.
+ * Numbers are coerced using default Java rules; booleans convert to 0.0 (false)
+ * and 1.0 (true), and Strings are parsed using default Java language integer
+ * parsing rules.
+ *
+ * If representation can not be converted to an int (including structured types
+ * like Objects and Arrays),
+ * specified def will be returned; no exceptions are thrown.
+ */
+ public double getValueAsDouble(double def) throws IOException {
+ return def;
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * boolean.
+ * JSON booleans map naturally; integer numbers other than 0 map to true, and
+ * 0 maps to false
+ * and Strings 'true' and 'false' map to corresponding values.
+ *
+ * If representation can not be converted to a boolean value (including structured types
+ * like Objects and Arrays),
+ * default value of false will be returned; no exceptions are thrown.
+ */
+ public boolean getValueAsBoolean() throws IOException {
+ return getValueAsBoolean(false);
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * boolean.
+ * JSON booleans map naturally; integer numbers other than 0 map to true, and
+ * 0 maps to false
+ * and Strings 'true' and 'false' map to corresponding values.
+ *
+ * If representation can not be converted to a boolean value (including structured types
+ * like Objects and Arrays),
+ * specified def will be returned; no exceptions are thrown.
+ */
+ public boolean getValueAsBoolean(boolean def) throws IOException {
+ return def;
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * {@link java.lang.String}.
+ * JSON Strings map naturally; scalar values get converted to
+ * their textual representation.
+ * If representation can not be converted to a String value (including structured types
+ * like Objects and Arrays and null token), default value of
+ * null will be returned; no exceptions are thrown.
+ *
+ * @since 2.1
+ */
+ public String getValueAsString() throws IOException {
+ return getValueAsString(null);
+ }
+
+ /**
+ * Method that will try to convert value of current token to a
+ * {@link java.lang.String}.
+ * JSON Strings map naturally; scalar values get converted to
+ * their textual representation.
+ * If representation can not be converted to a String value (including structured types
+ * like Objects and Arrays and null token), specified default value
+ * will be returned; no exceptions are thrown.
+ *
+ * @since 2.1
+ */
+ public abstract String getValueAsString(String def) throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, Native Ids (type, object)
+ /**********************************************************
+ */
+
+ /**
+ * Introspection method that may be called to see if the underlying
+ * data format supports some kind of Object Ids natively (many do not;
+ * for example, JSON doesn't).
+ *
+ * Default implementation returns true; overridden by data formats
+ * that do support native Object Ids. Caller is expected to either
+ * use a non-native notation (explicit property or such), or fail,
+ * in case it can not use native object ids.
+ *
+ * @since 2.3
+ */
+ public boolean canReadObjectId() { return false; }
+
+ /**
+ * Introspection method that may be called to see if the underlying
+ * data format supports some kind of Type Ids natively (many do not;
+ * for example, JSON doesn't).
+ *
+ * Default implementation returns true; overridden by data formats
+ * that do support native Type Ids. Caller is expected to either
+ * use a non-native notation (explicit property or such), or fail,
+ * in case it can not use native type ids.
+ *
+ * @since 2.3
+ */
+ public boolean canReadTypeId() { return false; }
+
+ /**
+ * Method that can be called to check whether current token
+ * (one that was just read) has an associated Object id, and if
+ * so, return it.
+ * Note that while typically caller should check with {@link #canReadObjectId}
+ * first, it is not illegal to call this method even if that method returns
+ * true; but if so, it will return null. This may be used to simplify calling
+ * code.
+ *
+ * Default implementation will simply return null.
+ *
+ * @since 2.3
+ */
+ public Object getObjectId() throws IOException { return null; }
+
+ /**
+ * Method that can be called to check whether current token
+ * (one that was just read) has an associated type id, and if
+ * so, return it.
+ * Note that while typically caller should check with {@link #canReadTypeId}
+ * first, it is not illegal to call this method even if that method returns
+ * true; but if so, it will return null. This may be used to simplify calling
+ * code.
+ *
+ * Default implementation will simply return null.
+ *
+ * @since 2.3
+ */
+ public Object getTypeId() throws IOException { return null; }
+
+ /*
+ /**********************************************************
+ /* Public API, optional data binding functionality
+ /**********************************************************
+ */
+
+ /**
+ * Method to deserialize JSON content into a non-container
+ * type (it can be an array type, however): typically a bean, array
+ * or a wrapper type (like {@link java.lang.Boolean}).
+ * Note: method can only be called if the parser has
+ * an object codec assigned; this is true for parsers constructed
+ * by
+ * This method may advance the event stream, for structured types
+ * the current token will be the closing end marker (END_ARRAY,
+ * END_OBJECT) of the bound structure. For non-structured Json types
+ * (and for {@link JsonToken#VALUE_EMBEDDED_OBJECT})
+ * stream is not advanced.
+ *
+ * Note: this method should NOT be used if the result type is a
+ * container ({@link java.util.Collection} or {@link java.util.Map}.
+ * The reason is that due to type erasure, key and value types
+ * can not be introspected when using this method.
+ */
+ public
+ * This method may advance the event stream, for structured types
+ * the current token will be the closing end marker (END_ARRAY,
+ * END_OBJECT) of the bound structure. For non-structured Json types
+ * (and for {@link JsonToken#VALUE_EMBEDDED_OBJECT})
+ * stream is not advanced.
+ */
+ @SuppressWarnings("unchecked")
+ public
+ * Instances are fully immutable and can be shared, cached.
+ *
+ * @author Tatu Saloranta
+ *
+ * @since 2.3
+ */
+public class JsonPointer
+{
+ /**
+ * Marker instance used to represent segment that matches current
+ * node or position (that is, returns true for
+ * {@link #matches()}).
+ */
+ protected final static JsonPointer EMPTY = new JsonPointer();
+
+ /**
+ * Reference to rest of the pointer beyond currently matching
+ * segment (if any); null if this pointer refers to the matching
+ * segment.
+ */
+ protected final JsonPointer _nextSegment;
+
+ /**
+ * Reference from currently matching segment (if any) to node
+ * before leaf.
+ * Lazily constructed if/as needed.
+ *
+ * NOTE: we'll use `volatile` here assuming that this is unlikely to
+ * become a performance bottleneck. If it becomes one we can probably
+ * just drop it and things still should work (despite warnings as per JMM
+ * regarding visibility (and lack thereof) of unguarded changes).
+ *
+ * @since 2.5
+ */
+ protected volatile JsonPointer _head;
+
+ /**
+ * We will retain representation of the pointer, as a String,
+ * so that {@link #toString} should be as efficient as possible.
+ */
+ protected final String _asString;
+
+ protected final String _matchingPropertyName;
+
+ protected final int _matchingElementIndex;
+
+ /*
+ /**********************************************************
+ /* Construction
+ /**********************************************************
+ */
+
+ /**
+ * Constructor used for creating "empty" instance, used to represent
+ * state that matches current node.
+ */
+ protected JsonPointer() {
+ _nextSegment = null;
+ _matchingPropertyName = "";
+ _matchingElementIndex = -1;
+ _asString = "";
+ }
+
+ /**
+ * Constructor used for creating non-empty Segments
+ */
+ protected JsonPointer(String fullString, String segment, JsonPointer next) {
+ _asString = fullString;
+ _nextSegment = next;
+ // Ok; may always be a property
+ _matchingPropertyName = segment;
+ // but could be an index, if parsable
+ _matchingElementIndex = _parseIndex(segment);
+ }
+
+ /**
+ * @since 2.5
+ */
+ protected JsonPointer(String fullString, String segment, int matchIndex, JsonPointer next) {
+ _asString = fullString;
+ _nextSegment = next;
+ _matchingPropertyName = segment;
+ _matchingElementIndex = matchIndex;
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods
+ /**********************************************************
+ */
+
+ /**
+ * Factory method that parses given input and construct matching pointer
+ * instance, if it represents a valid JSON Pointer: if not, a
+ * {@link IllegalArgumentException} is thrown.
+ *
+ * @throws IllegalArgumentException Thrown if the input does not present a valid JSON Pointer
+ * expression: currently the only such expression is one that does NOT start with
+ * a slash ('/').
+ */
+ public static JsonPointer compile(String input) throws IllegalArgumentException
+ {
+ // First quick checks for well-known 'empty' pointer
+ if ((input == null) || input.length() == 0) {
+ return EMPTY;
+ }
+ // And then quick validity check:
+ if (input.charAt(0) != '/') {
+ throw new IllegalArgumentException("Invalid input: JSON Pointer expression must start with '/': "+"\""+input+"\"");
+ }
+ return _parseTail(input);
+ }
+
+ /**
+ * Alias for {@link #compile}; added to make instances automatically
+ * deserializable by Jackson databind.
+ */
+ public static JsonPointer valueOf(String input) { return compile(input); }
+
+ /* Factory method that composes a pointer instance, given a set
+ * of 'raw' segments: raw meaning that no processing will be done,
+ * no escaping may is present.
+ *
+ * @param segments
+ *
+ * @return Constructed path instance
+ */
+ /* TODO!
+ public static JsonPointer fromSegment(String... segments)
+ {
+ if (segments.length == 0) {
+ return EMPTY;
+ }
+ JsonPointer prev = null;
+
+ for (String segment : segments) {
+ JsonPointer next = new JsonPointer()
+ }
+ }
+ */
+
+ /*
+ /**********************************************************
+ /* Public API
+ /**********************************************************
+ */
+
+ public boolean matches() { return _nextSegment == null; }
+ public String getMatchingProperty() { return _matchingPropertyName; }
+ public int getMatchingIndex() { return _matchingElementIndex; }
+ public boolean mayMatchProperty() { return _matchingPropertyName != null; }
+ public boolean mayMatchElement() { return _matchingElementIndex >= 0; }
+
+ /**
+ * Returns the leaf of current JSON Pointer expression.
+ * Leaf is the last non-null segment of current JSON Pointer.
+ *
+ * @since 2.5
+ */
+ public JsonPointer last() {
+ JsonPointer current = this;
+ if (current == EMPTY) {
+ return null;
+ }
+ JsonPointer next;
+ while ((next = current._nextSegment) != JsonPointer.EMPTY) {
+ current = next;
+ }
+ return current;
+ }
+
+ public JsonPointer append(JsonPointer tail) {
+ if (this == EMPTY) {
+ return tail;
+ }
+ if (tail == EMPTY) {
+ return this;
+ }
+ String currentJsonPointer = _asString;
+ if (currentJsonPointer.endsWith("/")) {
+ //removes final slash
+ currentJsonPointer = currentJsonPointer.substring(0, currentJsonPointer.length()-1);
+ }
+ return compile(currentJsonPointer + tail._asString);
+ }
+
+ /**
+ * Method that may be called to see if the pointer would match property
+ * (of a JSON Object) with given name.
+ *
+ * @since 2.5
+ */
+ public boolean matchesProperty(String name) {
+ return (_nextSegment != null) && _matchingPropertyName.equals(name);
+ }
+
+ public JsonPointer matchProperty(String name) {
+ if ((_nextSegment != null) && _matchingPropertyName.equals(name)) {
+ return _nextSegment;
+ }
+ return null;
+ }
+
+ /**
+ * Method that may be called to see if the pointer would match
+ * array element (of a JSON Array) with given index.
+ *
+ * @since 2.5
+ */
+ public boolean matchesElement(int index) {
+ return (index == _matchingElementIndex) && (index >= 0);
+ }
+
+ /**
+ * @since 2.6
+ */
+ public JsonPointer matchElement(int index) {
+ if ((index != _matchingElementIndex) || (index < 0)) {
+ return null;
+ }
+ return _nextSegment;
+ }
+
+ /**
+ * Accessor for getting a "sub-pointer", instance where current segment
+ * has been removed and pointer includes rest of segments.
+ * For matching state, will return null.
+ */
+ public JsonPointer tail() {
+ return _nextSegment;
+ }
+
+ /**
+ * Accessor for getting a pointer instance that is identical to this
+ * instance except that the last segment has been dropped.
+ * For example, for JSON Point "/root/branch/leaf", this method would
+ * return pointer "/root/branch" (compared to {@link #tail()} that
+ * would return "/branch/leaf").
+ * For leaf
+ *
+ * @since 2.5
+ */
+ public JsonPointer head() {
+ JsonPointer h = _head;
+ if (h == null) {
+ if (this != EMPTY) {
+ h = _constructHead();
+ }
+ _head = h;
+ }
+ return h;
+ }
+
+ /*
+ /**********************************************************
+ /* Standard method overrides
+ /**********************************************************
+ */
+
+ @Override public String toString() { return _asString; }
+ @Override public int hashCode() { return _asString.hashCode(); }
+
+ @Override public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null) return false;
+ if (!(o instanceof JsonPointer)) return false;
+ return _asString.equals(((JsonPointer) o)._asString);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods
+ /**********************************************************
+ */
+
+ private final static int _parseIndex(String str) {
+ final int len = str.length();
+ // [core#133]: beware of super long indexes; assume we never
+ // have arrays over 2 billion entries so ints are fine.
+ if (len == 0 || len > 10) {
+ return -1;
+ }
+ // [core#176]: no leading zeroes allowed
+ char c = str.charAt(0);
+ if (c <= '0') {
+ return (len == 1 && c == '0') ? 0 : -1;
+ }
+ if (c > '9') {
+ return -1;
+ }
+ for (int i = 1; i < len; ++i) {
+ c = str.charAt(i);
+ if (c > '9' || c < '0') {
+ return -1;
+ }
+ }
+ if (len == 10) {
+ long l = NumberInput.parseLong(str);
+ if (l > Integer.MAX_VALUE) {
+ return -1;
+ }
+ }
+ return NumberInput.parseInt(str);
+ }
+
+ protected static JsonPointer _parseTail(String input) {
+ final int end = input.length();
+
+ // first char is the contextual slash, skip
+ for (int i = 1; i < end; ) {
+ char c = input.charAt(i);
+ if (c == '/') { // common case, got a segment
+ return new JsonPointer(input, input.substring(1, i),
+ _parseTail(input.substring(i)));
+ }
+ ++i;
+ // quoting is different; offline this case
+ if (c == '~' && i < end) { // possibly, quote
+ return _parseQuotedTail(input, i);
+ }
+ // otherwise, loop on
+ }
+ // end of the road, no escapes
+ return new JsonPointer(input, input.substring(1), EMPTY);
+ }
+
+ /**
+ * Method called to parse tail of pointer path, when a potentially
+ * escaped character has been seen.
+ *
+ * @param input Full input for the tail being parsed
+ * @param i Offset to character after tilde
+ */
+ protected static JsonPointer _parseQuotedTail(String input, int i) {
+ final int end = input.length();
+ StringBuilder sb = new StringBuilder(Math.max(16, end));
+ if (i > 2) {
+ sb.append(input, 1, i-1);
+ }
+ _appendEscape(sb, input.charAt(i++));
+ while (i < end) {
+ char c = input.charAt(i);
+ if (c == '/') { // end is nigh!
+ return new JsonPointer(input, sb.toString(),
+ _parseTail(input.substring(i)));
+ }
+ ++i;
+ if (c == '~' && i < end) {
+ _appendEscape(sb, input.charAt(i++));
+ continue;
+ }
+ sb.append(c);
+ }
+ // end of the road, last segment
+ return new JsonPointer(input, sb.toString(), EMPTY);
+ }
+
+ protected JsonPointer _constructHead()
+ {
+ // ok; find out who we are to drop
+ JsonPointer last = last();
+ if (last == this) {
+ return EMPTY;
+ }
+ // and from that, length of suffix to drop
+ int suffixLength = last._asString.length();
+ JsonPointer next = _nextSegment;
+ return new JsonPointer(_asString.substring(0, _asString.length() - suffixLength), _matchingPropertyName,
+ _matchingElementIndex, next._constructHead(suffixLength, last));
+ }
+
+ protected JsonPointer _constructHead(int suffixLength, JsonPointer last)
+ {
+ if (this == last) {
+ return EMPTY;
+ }
+ JsonPointer next = _nextSegment;
+ String str = _asString;
+ return new JsonPointer(str.substring(0, str.length() - suffixLength), _matchingPropertyName,
+ _matchingElementIndex, next._constructHead(suffixLength, last));
+ }
+
+ private static void _appendEscape(StringBuilder sb, char c) {
+ if (c == '0') {
+ c = '~';
+ } else if (c == '1') {
+ c = '/';
+ } else {
+ sb.append('~');
+ }
+ sb.append(c);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonProcessingException.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonProcessingException.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonProcessingException.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,128 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Intermediate base class for all problems encountered when
+ * processing (parsing, generating) JSON content
+ * that are not pure I/O problems.
+ * Regular {@link java.io.IOException}s will be passed through as is.
+ * Sub-class of {@link java.io.IOException} for convenience.
+ */
+public class JsonProcessingException extends java.io.IOException
+{
+ final static long serialVersionUID = 123; // Stupid eclipse...
+
+ protected JsonLocation _location;
+
+ protected JsonProcessingException(String msg, JsonLocation loc, Throwable rootCause) {
+ /* Argh. IOException(Throwable,String) is only available starting
+ * with JDK 1.6...
+ */
+ super(msg);
+ if (rootCause != null) {
+ initCause(rootCause);
+ }
+ _location = loc;
+ }
+
+ protected JsonProcessingException(String msg) {
+ super(msg);
+ }
+
+ protected JsonProcessingException(String msg, JsonLocation loc) {
+ this(msg, loc, null);
+ }
+
+ protected JsonProcessingException(String msg, Throwable rootCause) {
+ this(msg, null, rootCause);
+ }
+
+ protected JsonProcessingException(Throwable rootCause) {
+ this(null, null, rootCause);
+ }
+
+ /*
+ /**********************************************************
+ /* Extended API
+ /**********************************************************
+ */
+
+ public JsonLocation getLocation() { return _location; }
+
+ /**
+ * Method that allows accessing the original "message" argument,
+ * without additional decorations (like location information)
+ * that overridden {@link #getMessage} adds.
+ *
+ * @since 2.1
+ */
+ public String getOriginalMessage() { return super.getMessage(); }
+
+ /**
+ * Method that allows accessing underlying processor that triggered
+ * this exception; typically either {@link JsonParser} or {@link JsonGenerator}
+ * for exceptions that originate from streaming API.
+ * Note that it is possible that `null` may be returned if code throwing
+ * exception either has no access to processor; or has not been retrofitted
+ * to set it; this means that caller needs to take care to check for nulls.
+ * Subtypes override this method with co-variant return type, for more
+ * type-safe access.
+ *
+ * @return Originating processor, if available; null if not.
+ *
+ * @since 2.7
+ */
+ public Object getProcessor() { return null; }
+
+ /*
+ /**********************************************************
+ /* Methods for sub-classes to use, override
+ /**********************************************************
+ */
+
+ /**
+ * Accessor that sub-classes can override to append additional
+ * information right after the main message, but before
+ * source location information.
+ */
+ protected String getMessageSuffix() { return null; }
+
+ /*
+ /**********************************************************
+ /* Overrides of standard methods
+ /**********************************************************
+ */
+
+ /**
+ * Default method overridden so that we can add location information
+ */
+ @Override public String getMessage() {
+ String msg = super.getMessage();
+ if (msg == null) {
+ msg = "N/A";
+ }
+ JsonLocation loc = getLocation();
+ String suffix = getMessageSuffix();
+ // mild optimization, if nothing extra is needed:
+ if (loc != null || suffix != null) {
+ StringBuilder sb = new StringBuilder(100);
+ sb.append(msg);
+ if (suffix != null) {
+ sb.append(suffix);
+ }
+ if (loc != null) {
+ sb.append('\n');
+ sb.append(" at ");
+ sb.append(loc.toString());
+ }
+ msg = sb.toString();
+ }
+ return msg;
+ }
+
+ @Override public String toString() { return getClass().getName()+": "+getMessage(); }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonStreamContext.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonStreamContext.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonStreamContext.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,133 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Shared base class for streaming processing contexts used during
+ * reading and writing of Json content using Streaming API.
+ * This context is also exposed to applications:
+ * context object can be used by applications to get an idea of
+ * relative position of the parser/generator within json content
+ * being processed. This allows for some contextual processing: for
+ * example, output within Array context can differ from that of
+ * Object context.
+ */
+public abstract class JsonStreamContext
+{
+ // // // Type constants used internally
+
+ protected final static int TYPE_ROOT = 0;
+ protected final static int TYPE_ARRAY = 1;
+ protected final static int TYPE_OBJECT = 2;
+
+ protected int _type;
+
+ /**
+ * Index of the currently processed entry. Starts with -1 to signal
+ * that no entries have been started, and gets advanced each
+ * time a new entry is started, either by encountering an expected
+ * separator, or with new values if no separators are expected
+ * (the case for root context).
+ */
+ protected int _index;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ protected JsonStreamContext() { }
+
+ /*
+ /**********************************************************
+ /* Public API, accessors
+ /**********************************************************
+ */
+
+ /**
+ * Accessor for finding parent context of this context; will
+ * return null for root context.
+ */
+ public abstract JsonStreamContext getParent();
+
+ /**
+ * Method that returns true if this context is an Array context;
+ * that is, content is being read from or written to a Json Array.
+ */
+ public final boolean inArray() { return _type == TYPE_ARRAY; }
+
+ /**
+ * Method that returns true if this context is a Root context;
+ * that is, content is being read from or written to without
+ * enclosing array or object structure.
+ */
+ public final boolean inRoot() { return _type == TYPE_ROOT; }
+
+ /**
+ * Method that returns true if this context is an Object context;
+ * that is, content is being read from or written to a Json Object.
+ */
+ public final boolean inObject() { return _type == TYPE_OBJECT; }
+
+ /**
+ * Method for accessing simple type description of current context;
+ * either ROOT (for root-level values), OBJECT (for field names and
+ * values of JSON Objects) or ARRAY (for values of JSON Arrays)
+ */
+ public final String getTypeDesc() {
+ switch (_type) {
+ case TYPE_ROOT: return "ROOT";
+ case TYPE_ARRAY: return "ARRAY";
+ case TYPE_OBJECT: return "OBJECT";
+ }
+ return "?";
+ }
+
+ /**
+ * @return Number of entries that are complete and started.
+ */
+ public final int getEntryCount() { return _index + 1; }
+
+ /**
+ * @return Index of the currently processed entry, if any
+ */
+ public final int getCurrentIndex() { return (_index < 0) ? 0 : _index; }
+
+ /**
+ * Method for accessing name associated with the current location.
+ * Non-null for
+ * Note that "current value" is NOT populated (or used) by Streaming parser or generator;
+ * it is only used by higher-level data-binding functionality.
+ * The reason it is included here is that it can be stored and accessed hierarchically,
+ * and gets passed through data-binding.
+ *
+ * @return Currently active value, if one has been assigned.
+ *
+ * @since 2.5
+ */
+ public Object getCurrentValue() {
+ return null;
+ }
+
+ /**
+ * Method to call to pass value to be returned via {@link #getCurrentValue}; typically
+ * called indirectly through {@link JsonParser#setCurrentValue}
+ * or {@link JsonGenerator#setCurrentValue}).
+ *
+ * @since 2.5
+ */
+ public void setCurrentValue(Object v) { }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonToken.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonToken.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonToken.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,201 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Enumeration for basic token types used for returning results
+ * of parsing JSON content.
+ */
+public enum JsonToken
+{
+ /* Some notes on implementation:
+ *
+ * - Entries are to be ordered such that start/end array/object
+ * markers come first, then field name marker (if any), and
+ * finally scalar value tokens. This is assumed by some
+ * typing checks.
+ */
+
+ /**
+ * NOT_AVAILABLE can be returned if {@link JsonParser}
+ * implementation can not currently return the requested
+ * token (usually next one), or even if any will be
+ * available, but that may be able to determine this in
+ * future. This is the case with non-blocking parsers --
+ * they can not block to wait for more data to parse and
+ * must return something.
+ */
+ NOT_AVAILABLE(null, JsonTokenId.ID_NOT_AVAILABLE),
+
+ /**
+ * START_OBJECT is returned when encountering '{'
+ * which signals starting of an Object value.
+ */
+ START_OBJECT("{", JsonTokenId.ID_START_OBJECT),
+
+ /**
+ * END_OBJECT is returned when encountering '}'
+ * which signals ending of an Object value
+ */
+ END_OBJECT("}", JsonTokenId.ID_END_OBJECT),
+
+ /**
+ * START_ARRAY is returned when encountering '['
+ * which signals starting of an Array value
+ */
+ START_ARRAY("[", JsonTokenId.ID_START_ARRAY),
+
+ /**
+ * END_ARRAY is returned when encountering ']'
+ * which signals ending of an Array value
+ */
+ END_ARRAY("]", JsonTokenId.ID_END_ARRAY),
+
+ /**
+ * FIELD_NAME is returned when a String token is encountered
+ * as a field name (same lexical value, different function)
+ */
+ FIELD_NAME(null, JsonTokenId.ID_FIELD_NAME),
+
+ /**
+ * Placeholder token returned when the input source has a concept
+ * of embedded Object that are not accessible as usual structure
+ * (of starting with {@link #START_OBJECT}, having values, ending with
+ * {@link #END_OBJECT}), but as "raw" objects.
+ *
+ * Note: this token is never returned by regular JSON readers, but
+ * only by readers that expose other kinds of source (like
+ *
+ * The standard implementation of this class is
+ *
+ * Note: this method should NOT be used if the result type is a
+ * container ({@link java.util.Collection} or {@link java.util.Map}.
+ * The reason is that due to type erasure, key and value types
+ * can not be introspected when using this method.
+ */
+ public abstract
+ * Note: since Jackson 2.1, stateful implementations MUST implement
+ * {@link com.fasterxml.jackson.core.util.Instantiatable} interface,
+ * to allow for constructing per-generation instances and avoid
+ * state corruption (see [JACKSON-851] for details).
+ * Stateless implementations need not do this; but those are less common.
+ */
+public interface PrettyPrinter
+{
+ /*
+ /**********************************************************
+ /* First methods that act both as events, and expect
+ /* output for correct functioning (i.e something gets
+ /* output even when not pretty-printing)
+ /**********************************************************
+ */
+
+ // // // Root-level handling:
+
+ /**
+ * Method called after a root-level value has been completely
+ * output, and before another value is to be output.
+ *
+ * Default
+ * handling (without pretty-printing) will output a space, to
+ * allow values to be parsed correctly. Pretty-printer is
+ * to output some other suitable and nice-looking separator
+ * (tab(s), space(s), linefeed(s) or any combination thereof).
+ */
+ void writeRootValueSeparator(JsonGenerator jg)
+ throws IOException, JsonGenerationException;
+
+ // // Object handling
+
+ /**
+ * Method called when an Object value is to be output, before
+ * any fields are output.
+ *
+ * Default handling (without pretty-printing) will output
+ * the opening curly bracket.
+ * Pretty-printer is
+ * to output a curly bracket as well, but can surround that
+ * with other (white-space) decoration.
+ */
+ void writeStartObject(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+
+ /**
+ * Method called after an Object value has been completely output
+ * (minus closing curly bracket).
+ *
+ * Default handling (without pretty-printing) will output
+ * the closing curly bracket.
+ * Pretty-printer is
+ * to output a curly bracket as well, but can surround that
+ * with other (white-space) decoration.
+ *
+ * @param nrOfEntries Number of direct members of the array that
+ * have been output
+ */
+ void writeEndObject(JsonGenerator gen, int nrOfEntries)
+ throws IOException, JsonGenerationException;
+
+ /**
+ * Method called after an object entry (field:value) has been completely
+ * output, and before another value is to be output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * comma to separate the two. Pretty-printer is
+ * to output a comma as well, but can surround that with other
+ * (white-space) decoration.
+ */
+ void writeObjectEntrySeparator(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+
+ /**
+ * Method called after an object field has been output, but
+ * before the value is output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * colon to separate the two. Pretty-printer is
+ * to output a colon as well, but can surround that with other
+ * (white-space) decoration.
+ */
+ void writeObjectFieldValueSeparator(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+
+ // // // Array handling
+
+ /**
+ * Method called when an Array value is to be output, before
+ * any member/child values are output.
+ *
+ * Default handling (without pretty-printing) will output
+ * the opening bracket.
+ * Pretty-printer is
+ * to output a bracket as well, but can surround that
+ * with other (white-space) decoration.
+ */
+ void writeStartArray(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+
+ /**
+ * Method called after an Array value has been completely output
+ * (minus closing bracket).
+ *
+ * Default handling (without pretty-printing) will output
+ * the closing bracket.
+ * Pretty-printer is
+ * to output a bracket as well, but can surround that
+ * with other (white-space) decoration.
+ *
+ * @param nrOfValues Number of direct members of the array that
+ * have been output
+ */
+ void writeEndArray(JsonGenerator gen, int nrOfValues)
+ throws IOException, JsonGenerationException;
+
+ /**
+ * Method called after an array value has been completely
+ * output, and before another value is to be output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * comma to separate the two. Pretty-printer is
+ * to output a comma as well, but can surround that with other
+ * (white-space) decoration.
+ */
+ void writeArrayValueSeparator(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+
+ /*
+ /**********************************************************
+ /* Then events that by default do not produce any output
+ /* but that are often overridden to add white space
+ /* in pretty-printing mode
+ /**********************************************************
+ */
+
+ /**
+ * Method called after array start marker has been output,
+ * and right before the first value is to be output.
+ * It is not called for arrays with no values.
+ *
+ * Default handling does not output anything, but pretty-printer
+ * is free to add any white space decoration.
+ */
+ void beforeArrayValues(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+
+ /**
+ * Method called after object start marker has been output,
+ * and right before the field name of the first entry is
+ * to be output.
+ * It is not called for objects without entries.
+ *
+ * Default handling does not output anything, but pretty-printer
+ * is free to add any white space decoration.
+ */
+ void beforeObjectEntries(JsonGenerator gen)
+ throws IOException, JsonGenerationException;
+}
+
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/SerializableString.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/SerializableString.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/SerializableString.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,156 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+
+/**
+ * Interface that defines how Jackson package can interact with efficient
+ * pre-serialized or lazily-serialized and reused String representations.
+ * Typically implementations store possible serialized version(s) so that
+ * serialization of String can be done more efficiently, especially when
+ * used multiple times.
+ *
+ * Note that "quoted" in methods means quoting of 'special' characters using
+ * JSON backlash notation (and not use of actual double quotes).
+ *
+ * @see com.fasterxml.jackson.core.io.SerializedString
+ */
+public interface SerializableString
+{
+ /**
+ * Returns unquoted String that this object represents (and offers
+ * serialized forms for)
+ */
+ String getValue();
+
+ /**
+ * Returns length of the (unquoted) String as characters.
+ * Functionally equvalent to:
+ *
+ * Note that in Jackson 1.x
+ * NOTE: starting with Jackson 2.2, there is more functionality
+ * available via this class, and the intent is that this should
+ * form actual base for multiple alternative tree representations;
+ * for example, immutable trees could use different implementation
+ * than mutable trees. It should also be possible to move actual
+ * Tree Model implementation out of databind package eventually
+ * (Jackson 3?).
+ *
+ * @since 2.2
+ */
+public interface TreeNode
+{
+ /*
+ /**********************************************************
+ /* Minimal introspection methods
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used for efficient type detection
+ * when using stream abstraction for traversing nodes.
+ * Will return the first {@link JsonToken} that equivalent
+ * stream event would produce (for most nodes there is just
+ * one token but for structured/container types multiple)
+ */
+ JsonToken asToken();
+
+ /**
+ * If this node is a numeric type (as per {@link JsonToken#isNumeric}),
+ * returns native type that node uses to store the numeric value;
+ * otherwise returns null.
+ *
+ * @return Type of number contained, if any; or null if node does not
+ * contain numeric value.
+ */
+ JsonParser.NumberType numberType();
+
+ /**
+ * Method that returns number of child nodes this node contains:
+ * for Array nodes, number of child elements, for Object nodes,
+ * number of fields, and for all other nodes 0.
+ *
+ * @return For non-container nodes returns 0; for arrays number of
+ * contained elements, and for objects number of fields.
+ *
+ * @since 2.2
+ */
+ int size();
+
+ /**
+ * Method that returns true for all value nodes: ones that
+ * are not containers, and that do not represent "missing" nodes
+ * in the path. Such value nodes represent String, Number, Boolean
+ * and null values from JSON.
+ *
+ * Note: one and only one of methods {@link #isValueNode},
+ * {@link #isContainerNode} and {@link #isMissingNode} ever
+ * returns true for any given node.
+ *
+ * @since 2.2
+ */
+ boolean isValueNode();
+
+ /**
+ * Method that returns true for container nodes: Arrays and Objects.
+ *
+ * Note: one and only one of methods {@link #isValueNode},
+ * {@link #isContainerNode} and {@link #isMissingNode} ever
+ * returns true for any given node.
+ *
+ * @since 2.2
+ */
+ boolean isContainerNode();
+
+ /**
+ * Method that returns true for "virtual" nodes which represent
+ * missing entries constructed by path accessor methods when
+ * there is no actual node matching given criteria.
+ *
+ * Note: one and only one of methods {@link #isValueNode},
+ * {@link #isContainerNode} and {@link #isMissingNode} ever
+ * returns true for any given node.
+ *
+ * @since 2.2
+ */
+ boolean isMissingNode();
+
+ /**
+ * Method that returns true if this node is an Array node, false
+ * otherwise.
+ * Note that if true is returned, {@link #isContainerNode}
+ * must also return true.
+ *
+ * @since 2.2
+ */
+ boolean isArray();
+
+ /**
+ * Method that returns true if this node is an Object node, false
+ * otherwise.
+ * Note that if true is returned, {@link #isContainerNode}
+ * must also return true.
+ *
+ * @since 2.2
+ */
+ boolean isObject();
+
+ /*
+ /**********************************************************
+ /* Basic traversal through structured entries (Arrays, Objects)
+ /**********************************************************
+ */
+
+ /**
+ * Method for accessing value of the specified field of
+ * an object node. If this node is not an object (or it
+ * does not have a value for specified field name), or
+ * if there is no field with such name, null is returned.
+ *
+ * NOTE: handling of explicit null values may vary between
+ * implementations; some trees may retain explicit nulls, others
+ * not.
+ *
+ * @return Node that represent value of the specified field,
+ * if this node is an object and has value for the specified
+ * field. Null otherwise.
+ *
+ * @since 2.2
+ */
+ TreeNode get(String fieldName);
+
+ /**
+ * Method for accessing value of the specified element of
+ * an array node. For other nodes, null is returned.
+ *
+ * For array nodes, index specifies
+ * exact location within array and allows for efficient iteration
+ * over child elements (underlying storage is guaranteed to
+ * be efficiently indexable, i.e. has random-access to elements).
+ * If index is less than 0, or equal-or-greater than
+ *
+ * For array nodes, index specifies
+ * exact location within array and allows for efficient iteration
+ * over child elements (underlying storage is guaranteed to
+ * be efficiently indexable, i.e. has random-access to elements).
+ * If index is less than 0, or equal-or-greater than
+ *
+ * Note that if the same expression is used often, it is preferable to construct
+ * {@link JsonPointer} instance once and reuse it: this method will not perform
+ * any caching of compiled expressions.
+ *
+ * @param jsonPointerExpression Expression to compile as a {@link JsonPointer}
+ * instance
+ *
+ * @return Node that matches given JSON Pointer: if no match exists,
+ * will return a node for which {@link TreeNode#isMissingNode()} returns true.
+ *
+ * @since 2.3
+ */
+ TreeNode at(String jsonPointerExpression) throws IllegalArgumentException;
+
+ /*
+ /**********************************************************
+ /* Converting to/from Streaming API
+ /**********************************************************
+ */
+
+ /**
+ * Method for constructing a {@link JsonParser} instance for
+ * iterating over contents of the tree that this node is root of.
+ * Functionally equivalent to first serializing tree using
+ * {@link ObjectCodec} and then re-parsing but
+ * more efficient.
+ *
+ * NOTE: constructed parser instance will NOT initially point to a token,
+ * so before passing it to deserializers, it is typically necessary to
+ * advance it to the first available token by calling {@link JsonParser#nextToken()}.
+ *
+ * Also note that calling this method will NOT pass {@link ObjectCodec}
+ * reference, so data-binding callback methods like {@link JsonParser#readValueAs(Class)}
+ * will not work with calling {@link JsonParser#setCodec}).
+ * It is often better to call {@link #traverse(ObjectCodec)} to pass the codec explicitly.
+ */
+ JsonParser traverse();
+
+ /**
+ * Same as {@link #traverse()}, but additionally passes {@link com.fasterxml.jackson.core.ObjectCodec}
+ * to use if {@link JsonParser#readValueAs(Class)} is used (otherwise caller must call
+ * {@link JsonParser#setCodec} on response explicitly).
+ *
+ * NOTE: constructed parser instance will NOT initially point to a token,
+ * so before passing it to deserializers, it is typically necessary to
+ * advance it to the first available token by calling {@link JsonParser#nextToken()}.
+ *
+ * @since 2.1
+ */
+ JsonParser traverse(ObjectCodec codec);
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/Version.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/Version.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/Version.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,141 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Object that encapsulates versioning information of a component.
+ * Version information includes not just version number but also
+ * optionally group and artifact ids of the component being versioned.
+ *
+ * Note that optional group and artifact id properties are new with Jackson 2.0:
+ * if provided, they should align with Maven artifact information.
+ */
+public class Version
+ implements Comparable
+ * Note that 'minimal' here mostly refers to minimal number of fields
+ * (size) and functionality that is specific to certain types
+ * of parser implementations; but not necessarily to number of methods.
+ */
+public abstract class ParserMinimalBase extends JsonParser
+{
+ // Control chars:
+ protected final static int INT_TAB = '\t';
+ protected final static int INT_LF = '\n';
+ protected final static int INT_CR = '\r';
+ protected final static int INT_SPACE = 0x0020;
+
+ // Markup
+ protected final static int INT_LBRACKET = '[';
+ protected final static int INT_RBRACKET = ']';
+ protected final static int INT_LCURLY = '{';
+ protected final static int INT_RCURLY = '}';
+ protected final static int INT_QUOTE = '"';
+ protected final static int INT_BACKSLASH = '\\';
+ protected final static int INT_SLASH = '/';
+ protected final static int INT_COLON = ':';
+ protected final static int INT_COMMA = ',';
+ protected final static int INT_HASH = '#';
+
+ // fp numbers
+ protected final static int INT_PERIOD = '.';
+ protected final static int INT_e = 'e';
+ protected final static int INT_E = 'E';
+
+ /*
+ /**********************************************************
+ /* Minimal generally useful state
+ /**********************************************************
+ */
+
+ /**
+ * Last token retrieved via {@link #nextToken}, if any.
+ * Null before the first call to
+ * Default implementation returns
+ * Default implementation returns
+ * The default implementation simply returns
+ * The default implementation simply returns
+ * The default implementation simply returns
+ * Default action is to call
+ * NOTE: no binary payload passed; assumption is this won't be of much use.
+ */
+ public boolean includeBinary() {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * raw (pre-encoded, not quoted by generator) value
+ * should be included in output or not.
+ *
+ * NOTE: value itself not passed since it may come on multiple forms
+ * and is unlikely to be of much use in determining inclusion
+ * criteria.
+ */
+ public boolean includeRawValue() {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * embedded (Opaque) value
+ * should be included in output or not.
+ */
+ public boolean includeEmbeddedValue(Object ob) {
+ return _includeScalar();
+ }
+
+ /*
+ /**********************************************************
+ /* Overrides
+ /**********************************************************
+ */
+
+ @Override
+ public String toString() {
+ if (this == INCLUDE_ALL) {
+ return "TokenFilter.INCLUDE_ALL";
+ }
+ return super.toString();
+ }
+
+ /*
+ /**********************************************************
+ /* Other methods
+ /**********************************************************
+ */
+
+ /**
+ * Overridable default implementation delegated to all scalar value
+ * inclusion check methods.
+ * The default implementation simply includes all leaf values.
+ */
+ protected boolean _includeScalar() {
+ return true;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/TokenFilterContext.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/TokenFilterContext.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/TokenFilterContext.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,353 @@
+package com.fasterxml.jackson.core.filter;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Alternative variant of {@link JsonStreamContext}, used when filtering
+ * content being read or written (based on {@link TokenFilter}).
+ *
+ * @since 2.6
+ */
+public class TokenFilterContext extends JsonStreamContext
+{
+ /**
+ * Parent context for this context; null for root context.
+ */
+ protected final TokenFilterContext _parent;
+
+ /*
+ /**********************************************************
+ /* Simple instance reuse slots; speed up things
+ /* a bit (10-15%) for docs with lots of small
+ /* arrays/objects
+ /**********************************************************
+ */
+
+ protected TokenFilterContext _child;
+
+ /*
+ /**********************************************************
+ /* Location/state information
+ /**********************************************************
+ */
+
+ /**
+ * Name of the field of which value is to be parsed; only
+ * used for OBJECT contexts
+ */
+ protected String _currentName;
+
+ /**
+ * Filter to use for items in this state (for properties of Objects,
+ * elements of Arrays, and root-level values of root context)
+ */
+ protected TokenFilter _filter;
+
+ /**
+ * Flag that indicates that start token has been read/written,
+ * so that matching close token needs to be read/written as well
+ * when context is getting closed.
+ */
+ protected boolean _startHandled;
+
+ /**
+ * Flag that indicates that the current name of this context
+ * still needs to be read/written, if path from root down to
+ * included leaf is to be exposed.
+ */
+ protected boolean _needToHandleName;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ protected TokenFilterContext(int type, TokenFilterContext parent,
+ TokenFilter filter, boolean startHandled)
+ {
+ super();
+ _type = type;
+ _parent = parent;
+ _filter = filter;
+ _index = -1;
+ _startHandled = startHandled;
+ _needToHandleName = false;
+ }
+
+ protected TokenFilterContext reset(int type,
+ TokenFilter filter, boolean startWritten)
+ {
+ _type = type;
+ _filter = filter;
+ _index = -1;
+ _currentName = null;
+ _startHandled = startWritten;
+ _needToHandleName = false;
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods
+ /**********************************************************
+ */
+
+ public static TokenFilterContext createRootContext(TokenFilter filter) {
+ // true -> since we have no start/end marker, consider start handled
+ return new TokenFilterContext(TYPE_ROOT, null, filter, true);
+ }
+
+ public TokenFilterContext createChildArrayContext(TokenFilter filter, boolean writeStart) {
+ TokenFilterContext ctxt = _child;
+ if (ctxt == null) {
+ _child = ctxt = new TokenFilterContext(TYPE_ARRAY, this, filter, writeStart);
+ return ctxt;
+ }
+ return ctxt.reset(TYPE_ARRAY, filter, writeStart);
+ }
+
+ public TokenFilterContext createChildObjectContext(TokenFilter filter, boolean writeStart) {
+ TokenFilterContext ctxt = _child;
+ if (ctxt == null) {
+ _child = ctxt = new TokenFilterContext(TYPE_OBJECT, this, filter, writeStart);
+ return ctxt;
+ }
+ return ctxt.reset(TYPE_OBJECT, filter, writeStart);
+ }
+
+ /*
+ /**********************************************************
+ /* State changes
+ /**********************************************************
+ */
+
+ public TokenFilter setFieldName(String name) throws JsonProcessingException {
+ _currentName = name;
+ _needToHandleName = true;
+ return _filter;
+ }
+
+ /**
+ * Method called to check whether value is to be included at current output
+ * position, either as Object property, Array element, or root value.
+ */
+ public TokenFilter checkValue(TokenFilter filter) {
+ // First, checks for Object properties have been made earlier:
+ if (_type == TYPE_OBJECT) {
+ return filter;
+ }
+ // We increase it first because at the beginning of array, value is -1
+ int ix = ++_index;
+ if (_type == TYPE_ARRAY) {
+ return filter.includeElement(ix);
+ }
+ return filter.includeRootValue(ix);
+ }
+
+ /**
+ * Method called to ensure that parent path from root is written up to
+ * and including this node.
+ */
+ public void writePath(JsonGenerator gen) throws IOException
+ {
+ if ((_filter == null) || (_filter == TokenFilter.INCLUDE_ALL)) {
+ return;
+ }
+ if (_parent != null) {
+ _parent._writePath(gen);
+ }
+ if (_startHandled) {
+ // even if Object started, need to start leaf-level name
+ if (_needToHandleName) {
+ gen.writeFieldName(_currentName);
+ }
+ } else {
+ _startHandled = true;
+ if (_type == TYPE_OBJECT) {
+ gen.writeStartObject();
+ gen.writeFieldName(_currentName); // we know name must be written
+ } else if (_type == TYPE_ARRAY) {
+ gen.writeStartArray();
+ }
+ }
+ }
+
+ /**
+ * Variant of {@link #writePath(JsonGenerator)} called when all we
+ * need is immediately surrounding Object. Method typically called
+ * when including a single property but not including full path
+ * to root.
+ */
+ public void writeImmediatePath(JsonGenerator gen) throws IOException
+ {
+ if ((_filter == null) || (_filter == TokenFilter.INCLUDE_ALL)) {
+ return;
+ }
+ if (_startHandled) {
+ // even if Object started, need to start leaf-level name
+ if (_needToHandleName) {
+ gen.writeFieldName(_currentName);
+ }
+ } else {
+ _startHandled = true;
+ if (_type == TYPE_OBJECT) {
+ gen.writeStartObject();
+ if (_needToHandleName) {
+ gen.writeFieldName(_currentName);
+ }
+ } else if (_type == TYPE_ARRAY) {
+ gen.writeStartArray();
+ }
+ }
+ }
+
+ private void _writePath(JsonGenerator gen) throws IOException
+ {
+ if ((_filter == null) || (_filter == TokenFilter.INCLUDE_ALL)) {
+ return;
+ }
+ if (_parent != null) {
+ _parent._writePath(gen);
+ }
+ if (_startHandled) {
+ // even if Object started, need to start leaf-level name
+ if (_needToHandleName) {
+ _needToHandleName = false; // at parent must explicitly clear
+ gen.writeFieldName(_currentName);
+ }
+ } else {
+ _startHandled = true;
+ if (_type == TYPE_OBJECT) {
+ gen.writeStartObject();
+ if (_needToHandleName) {
+ _needToHandleName = false; // at parent must explicitly clear
+ gen.writeFieldName(_currentName);
+ }
+ } else if (_type == TYPE_ARRAY) {
+ gen.writeStartArray();
+ }
+ }
+ }
+
+ public TokenFilterContext closeArray(JsonGenerator gen) throws IOException
+ {
+ if (_startHandled) {
+ gen.writeEndArray();
+ }
+ if ((_filter != null) && (_filter != TokenFilter.INCLUDE_ALL)) {
+ _filter.filterFinishArray();
+ }
+ return _parent;
+ }
+
+ public TokenFilterContext closeObject(JsonGenerator gen) throws IOException
+ {
+ if (_startHandled) {
+ gen.writeEndObject();
+ }
+ if ((_filter != null) && (_filter != TokenFilter.INCLUDE_ALL)) {
+ _filter.filterFinishObject();
+ }
+ return _parent;
+ }
+
+ public void skipParentChecks() {
+ _filter = null;
+ for (TokenFilterContext ctxt = _parent; ctxt != null; ctxt = ctxt._parent) {
+ _parent._filter = null;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Accessors, mutators
+ /**********************************************************
+ */
+
+ @Override
+ public Object getCurrentValue() { return null; }
+
+ @Override
+ public void setCurrentValue(Object v) { }
+
+ @Override public final TokenFilterContext getParent() { return _parent; }
+ @Override public final String getCurrentName() { return _currentName; }
+
+ public TokenFilter getFilter() { return _filter; }
+ public boolean isStartHandled() { return _startHandled; }
+
+ public JsonToken nextTokenToRead() {
+ if (!_startHandled) {
+ _startHandled = true;
+ if (_type == TYPE_OBJECT) {
+ return JsonToken.START_OBJECT;
+ }
+ // Note: root should never be unhandled
+ return JsonToken.START_ARRAY;
+ }
+ // But otherwise at most might have FIELD_NAME
+ if (_needToHandleName && (_type == TYPE_OBJECT)) {
+ _needToHandleName = false;
+ return JsonToken.FIELD_NAME;
+ }
+ return null;
+ }
+
+ public TokenFilterContext findChildOf(TokenFilterContext parent) {
+ if (_parent == parent) {
+ return this;
+ }
+ TokenFilterContext curr = _parent;
+ while (curr != null) {
+ TokenFilterContext p = curr._parent;
+ if (p == parent) {
+ return curr;
+ }
+ curr = p;
+ }
+ // should never occur but...
+ return null;
+ }
+
+ // // // Internally used abstract methods
+
+ protected void appendDesc(StringBuilder sb) {
+ if (_parent != null) {
+ _parent.appendDesc(sb);
+ }
+ if (_type == TYPE_OBJECT) {
+ sb.append('{');
+ if (_currentName != null) {
+ sb.append('"');
+ // !!! TODO: Name chars should be escaped?
+ sb.append(_currentName);
+ sb.append('"');
+ } else {
+ sb.append('?');
+ }
+ sb.append('}');
+ } else if (_type == TYPE_ARRAY) {
+ sb.append('[');
+ sb.append(getCurrentIndex());
+ sb.append(']');
+ } else {
+ // nah, ROOT:
+ sb.append("/");
+ }
+ }
+
+ // // // Overridden standard methods
+
+ /**
+ * Overridden to provide developer writeable "JsonPath" representation
+ * of the context.
+ */
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ appendDesc(sb);
+ return sb.toString();
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/DataFormatDetector.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/DataFormatDetector.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/DataFormatDetector.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,202 @@
+package com.fasterxml.jackson.core.format;
+
+import java.io.*;
+import java.util.*;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Simple helper class that allows data format (content type) auto-detection,
+ * given an ordered set of {@link JsonFactory} instances to use for actual low-level
+ * detection.
+ */
+public class DataFormatDetector
+{
+ /**
+ * By default we will look ahead at most 64 bytes; in most cases,
+ * much less (4 bytes or so) is needed, but we will allow bit more
+ * leniency to support data formats that need more complex heuristics.
+ */
+ public final static int DEFAULT_MAX_INPUT_LOOKAHEAD = 64;
+
+ /**
+ * Ordered list of factories which both represent data formats to
+ * detect (in precedence order, starting with highest) and are used
+ * for actual detection.
+ */
+ protected final JsonFactory[] _detectors;
+
+ /**
+ * Strength of match we consider to be good enough to be used
+ * without checking any other formats.
+ * Default value is {@link MatchStrength#SOLID_MATCH},
+ */
+ protected final MatchStrength _optimalMatch;
+
+ /**
+ * Strength of minimal match we accept as the answer, unless
+ * better matches are found.
+ * Default value is {@link MatchStrength#WEAK_MATCH},
+ */
+ protected final MatchStrength _minimalMatch;
+
+ /**
+ * Maximum number of leading bytes of the input that we can read
+ * to determine data format.
+ *
+ * Default value is {@link #DEFAULT_MAX_INPUT_LOOKAHEAD}.
+ */
+ protected final int _maxInputLookahead;
+
+ /*
+ /**********************************************************
+ /* Construction
+ /**********************************************************
+ */
+
+ public DataFormatDetector(JsonFactory... detectors) {
+ this(detectors, MatchStrength.SOLID_MATCH, MatchStrength.WEAK_MATCH,
+ DEFAULT_MAX_INPUT_LOOKAHEAD);
+ }
+
+ public DataFormatDetector(Collection
+ * For example, when testing for XML data format,
+ * seeing a less-than character ("<") alone (with possible leading spaces)
+ * would be a strong indication that data could
+ * be in xml format (but see below for {@link #FULL_MATCH} description for more)
+ */
+ SOLID_MATCH,
+
+ /**
+ * Value that indicates that given data contains a signature that is deemed
+ * specific enough to uniquely indicate data format used.
+ *
+ * For example, when testing for XML data format,
+ * seing "<xml" as the first data bytes ("XML declaration", as per XML specification)
+ * could give full confidence that data is indeed in XML format.
+ * Not all data formats have unique leading identifiers to allow full matches; for example,
+ * JSON only has heuristic matches and can have at most {@link #SOLID_MATCH}) match.
+ */
+ FULL_MATCH
+ ;
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/package-info.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/package-info.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/package-info.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,6 @@
+/**
+ * Package that contains interfaces needed for dynamic, pluggable
+ * format (auto)detection; as well as basic utility classes for
+ * simple format detection functionality.
+ */
+package com.fasterxml.jackson.core.format;
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/CharTypes.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/CharTypes.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/CharTypes.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,259 @@
+package com.fasterxml.jackson.core.io;
+
+import java.util.Arrays;
+
+public final class CharTypes
+{
+ private final static char[] HC = "0123456789ABCDEF".toCharArray();
+ private final static byte[] HB;
+ static {
+ int len = HC.length;
+ HB = new byte[len];
+ for (int i = 0; i < len; ++i) {
+ HB[i] = (byte) HC[i];
+ }
+ }
+
+
+ /**
+ * Lookup table used for determining which input characters
+ * need special handling when contained in text segment.
+ */
+ private final static int[] sInputCodes;
+ static {
+ /* 96 would do for most cases (backslash is ASCII 94)
+ * but if we want to do lookups by raw bytes it's better
+ * to have full table
+ */
+ final int[] table = new int[256];
+ // Control chars and non-space white space are not allowed unquoted
+ for (int i = 0; i < 32; ++i) {
+ table[i] = -1;
+ }
+ // And then string end and quote markers are special too
+ table['"'] = 1;
+ table['\\'] = 1;
+ sInputCodes = table;
+ }
+
+ /**
+ * Additionally we can combine UTF-8 decoding info into similar
+ * data table.
+ */
+ private final static int[] sInputCodesUTF8;
+ static {
+ final int[] table = new int[sInputCodes.length];
+ System.arraycopy(sInputCodes, 0, table, 0, table.length);
+ for (int c = 128; c < 256; ++c) {
+ int code;
+
+ // We'll add number of bytes needed for decoding
+ if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
+ code = 2;
+ } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
+ code = 3;
+ } else if ((c & 0xF8) == 0xF0) {
+ // 4 bytes; double-char with surrogates and all...
+ code = 4;
+ } else {
+ // And -1 seems like a good "universal" error marker...
+ code = -1;
+ }
+ table[c] = code;
+ }
+ sInputCodesUTF8 = table;
+ }
+
+ /**
+ * To support non-default (and -standard) unquoted field names mode,
+ * need to have alternate checking.
+ * Basically this is list of 8-bit ASCII characters that are legal
+ * as part of Javascript identifier
+ */
+ private final static int[] sInputCodesJsNames;
+ static {
+ final int[] table = new int[256];
+ // Default is "not a name char", mark ones that are
+ Arrays.fill(table, -1);
+ // Assume rules with JS same as Java (change if/as needed)
+ for (int i = 33; i < 256; ++i) {
+ if (Character.isJavaIdentifierPart((char) i)) {
+ table[i] = 0;
+ }
+ }
+ /* As per [JACKSON-267], '@', '#' and '*' are also to be accepted as well.
+ * And '-' (for hyphenated names); and '+' for sake of symmetricity...
+ */
+ table['@'] = 0;
+ table['#'] = 0;
+ table['*'] = 0;
+ table['-'] = 0;
+ table['+'] = 0;
+ sInputCodesJsNames = table;
+ }
+
+ /**
+ * This table is similar to Latin-1, except that it marks all "high-bit"
+ * code as ok. They will be validated at a later point, when decoding
+ * name
+ */
+ private final static int[] sInputCodesUtf8JsNames;
+ static {
+ final int[] table = new int[256];
+ // start with 8-bit JS names
+ System.arraycopy(sInputCodesJsNames, 0, table, 0, table.length);
+ Arrays.fill(table, 128, 128, 0);
+ sInputCodesUtf8JsNames = table;
+ }
+
+ /**
+ * Decoding table used to quickly determine characters that are
+ * relevant within comment content.
+ */
+ private final static int[] sInputCodesComment;
+ static {
+ final int[] buf = new int[256];
+ // but first: let's start with UTF-8 multi-byte markers:
+ System.arraycopy(sInputCodesUTF8, 128, buf, 128, 128);
+
+ // default (0) means "ok" (skip); -1 invalid, others marked by char itself
+ Arrays.fill(buf, 0, 32, -1); // invalid white space
+ buf['\t'] = 0; // tab is still fine
+ buf['\n'] = '\n'; // lf/cr need to be observed, ends cpp comment
+ buf['\r'] = '\r';
+ buf['*'] = '*'; // end marker for c-style comments
+ sInputCodesComment = buf;
+ }
+
+ /**
+ * Decoding table used for skipping white space and comments.
+ *
+ * @since 2.3
+ */
+ private final static int[] sInputCodesWS;
+ static {
+ // but first: let's start with UTF-8 multi-byte markers:
+ final int[] buf = new int[256];
+ System.arraycopy(sInputCodesUTF8, 128, buf, 128, 128);
+
+ // default (0) means "not whitespace" (end); 1 "whitespace", -1 invalid,
+ // 2-4 UTF-8 multi-bytes, others marked by char itself
+ //
+ Arrays.fill(buf, 0, 32, -1); // invalid white space
+ buf[' '] = 1;
+ buf['\t'] = 1;
+ buf['\n'] = '\n'; // lf/cr need to be observed, ends cpp comment
+ buf['\r'] = '\r';
+ buf['/'] = '/'; // start marker for c/cpp comments
+ buf['#'] = '#'; // start marker for YAML comments
+ sInputCodesWS = buf;
+ }
+
+ /**
+ * Lookup table used for determining which output characters in
+ * 7-bit ASCII range need to be quoted.
+ */
+ private final static int[] sOutputEscapes128;
+ static {
+ int[] table = new int[128];
+ // Control chars need generic escape sequence
+ for (int i = 0; i < 32; ++i) {
+ // 04-Mar-2011, tatu: Used to use "-(i + 1)", replaced with constant
+ table[i] = CharacterEscapes.ESCAPE_STANDARD;
+ }
+ /* Others (and some within that range too) have explicit shorter
+ * sequences
+ */
+ table['"'] = '"';
+ table['\\'] = '\\';
+ // Escaping of slash is optional, so let's not add it
+ table[0x08] = 'b';
+ table[0x09] = 't';
+ table[0x0C] = 'f';
+ table[0x0A] = 'n';
+ table[0x0D] = 'r';
+ sOutputEscapes128 = table;
+ }
+
+ /**
+ * Lookup table for the first 128 Unicode characters (7-bit ASCII)
+ * range. For actual hex digits, contains corresponding value;
+ * for others -1.
+ */
+ private final static int[] sHexValues = new int[128];
+ static {
+ Arrays.fill(sHexValues, -1);
+ for (int i = 0; i < 10; ++i) {
+ sHexValues['0' + i] = i;
+ }
+ for (int i = 0; i < 6; ++i) {
+ sHexValues['a' + i] = 10 + i;
+ sHexValues['A' + i] = 10 + i;
+ }
+ }
+
+ public static int[] getInputCodeLatin1() { return sInputCodes; }
+ public static int[] getInputCodeUtf8() { return sInputCodesUTF8; }
+
+ public static int[] getInputCodeLatin1JsNames() { return sInputCodesJsNames; }
+ public static int[] getInputCodeUtf8JsNames() { return sInputCodesUtf8JsNames; }
+
+ public static int[] getInputCodeComment() { return sInputCodesComment; }
+ public static int[] getInputCodeWS() { return sInputCodesWS; }
+
+ /**
+ * Accessor for getting a read-only encoding table for first 128 Unicode
+ * code points (single-byte UTF-8 characters).
+ * Value of 0 means "no escaping"; other positive values that value is character
+ * to use after backslash; and negative values that generic (backslash - u)
+ * escaping is to be used.
+ */
+ public static int[] get7BitOutputEscapes() { return sOutputEscapes128; }
+
+ public static int charToHex(int ch)
+ {
+ return (ch > 127) ? -1 : sHexValues[ch];
+ }
+
+ public static void appendQuoted(StringBuilder sb, String content)
+ {
+ final int[] escCodes = sOutputEscapes128;
+ int escLen = escCodes.length;
+ for (int i = 0, len = content.length(); i < len; ++i) {
+ char c = content.charAt(i);
+ if (c >= escLen || escCodes[c] == 0) {
+ sb.append(c);
+ continue;
+ }
+ sb.append('\\');
+ int escCode = escCodes[c];
+ if (escCode < 0) { // generic quoting (hex value)
+ // The only negative value sOutputEscapes128 returns
+ // is CharacterEscapes.ESCAPE_STANDARD, which mean
+ // appendQuotes should encode using the Unicode encoding;
+ // not sure if this is the right way to encode for
+ // CharacterEscapes.ESCAPE_CUSTOM or other (future)
+ // CharacterEscapes.ESCAPE_XXX values.
+
+ // We know that it has to fit in just 2 hex chars
+ sb.append('u');
+ sb.append('0');
+ sb.append('0');
+ int value = c; // widening
+ sb.append(HC[value >> 4]);
+ sb.append(HC[value & 0xF]);
+ } else { // "named", i.e. prepend with slash
+ sb.append((char) escCode);
+ }
+ }
+ }
+
+ public static char[] copyHexChars() {
+ return (char[]) HC.clone();
+ }
+
+ public static byte[] copyHexBytes() {
+ return (byte[]) HB.clone();
+ }
+}
+
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/CharacterEscapes.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/CharacterEscapes.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/CharacterEscapes.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,71 @@
+package com.fasterxml.jackson.core.io;
+
+import java.util.Arrays;
+
+import com.fasterxml.jackson.core.SerializableString;
+
+/**
+ * Abstract base class that defines interface for customizing character
+ * escaping aspects for String values, for formats that use escaping.
+ * For JSON this applies to both property names and String values.
+ */
+@SuppressWarnings("serial")
+public abstract class CharacterEscapes
+ implements java.io.Serializable // since 2.1
+{
+ /**
+ * Value used for lookup tables to indicate that matching characters
+ * do not need to be escaped.
+ */
+ public final static int ESCAPE_NONE = 0;
+
+ /**
+ * Value used for lookup tables to indicate that matching characters
+ * are to be escaped using standard escaping; for JSON this means
+ * (for example) using "backslash - u" escape method.
+ */
+ public final static int ESCAPE_STANDARD = -1;
+
+ /**
+ * Value used for lookup tables to indicate that matching characters
+ * will need custom escapes; and that another call
+ * to {@link #getEscapeSequence} is needed to figure out exact escape
+ * sequence to output.
+ */
+ public final static int ESCAPE_CUSTOM = -2;
+
+ /**
+ * Method generators can call to get lookup table for determining
+ * escape handling for first 128 characters of Unicode (ASCII
+ * characters. Caller is not to modify contents of this array, since
+ * this is expected to be a shared copy.
+ *
+ * @return Array with size of at least 128, where first 128 entries
+ * have either one of
+ * NOTE: non-final since 2.4, to allow sub-classing.
+ */
+public class IOContext
+{
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Reference to the source object, which can be used for displaying
+ * location information
+ */
+ protected final Object _sourceRef;
+
+ /**
+ * Encoding used by the underlying stream, if known.
+ */
+ protected JsonEncoding _encoding;
+
+ /**
+ * Flag that indicates whether underlying input/output source/target
+ * object is fully managed by the owner of this context (parser or
+ * generator). If true, it is, and is to be closed by parser/generator;
+ * if false, calling application has to do closing (unless auto-closing
+ * feature is enabled for the parser/generator in question; in which
+ * case it acts like the owner).
+ */
+ protected final boolean _managedResource;
+
+ /*
+ /**********************************************************
+ /* Buffer handling, recycling
+ /**********************************************************
+ */
+
+ /**
+ * Recycler used for actual allocation/deallocation/reuse
+ */
+ protected final BufferRecycler _bufferRecycler;
+
+ /**
+ * Reference to the allocated I/O buffer for low-level input reading,
+ * if any allocated.
+ */
+ protected byte[] _readIOBuffer;
+
+ /**
+ * Reference to the allocated I/O buffer used for low-level
+ * encoding-related buffering.
+ */
+ protected byte[] _writeEncodingBuffer;
+
+ /**
+ * Reference to the buffer allocated for temporary use with
+ * base64 encoding or decoding.
+ */
+ protected byte[] _base64Buffer;
+
+ /**
+ * Reference to the buffer allocated for tokenization purposes,
+ * in which character input is read, and from which it can be
+ * further returned.
+ */
+ protected char[] _tokenCBuffer;
+
+ /**
+ * Reference to the buffer allocated for buffering it for
+ * output, before being encoded: generally this means concatenating
+ * output, then encoding when buffer fills up.
+ */
+ protected char[] _concatCBuffer;
+
+ /**
+ * Reference temporary buffer Parser instances need if calling
+ * app decides it wants to access name via 'getTextCharacters' method.
+ * Regular text buffer can not be used as it may contain textual
+ * representation of the value token.
+ */
+ protected char[] _nameCopyBuffer;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public IOContext(BufferRecycler br, Object sourceRef, boolean managedResource)
+ {
+ _bufferRecycler = br;
+ _sourceRef = sourceRef;
+ _managedResource = managedResource;
+ }
+
+ public void setEncoding(JsonEncoding enc) {
+ _encoding = enc;
+ }
+
+ /**
+ * @since 1.6
+ */
+ public IOContext withEncoding(JsonEncoding enc) {
+ _encoding = enc;
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, accessors
+ /**********************************************************
+ */
+
+ public Object getSourceReference() { return _sourceRef; }
+ public JsonEncoding getEncoding() { return _encoding; }
+ public boolean isResourceManaged() { return _managedResource; }
+
+ /*
+ /**********************************************************
+ /* Public API, buffer management
+ /**********************************************************
+ */
+
+ public TextBuffer constructTextBuffer() {
+ return new TextBuffer(_bufferRecycler);
+ }
+
+ /**
+ *
+ * Note: the method can only be called once during its life cycle.
+ * This is to protect against accidental sharing.
+ */
+ public byte[] allocReadIOBuffer() {
+ _verifyAlloc(_readIOBuffer);
+ return (_readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_READ_IO_BUFFER));
+ }
+
+ /**
+ * @since 2.4
+ */
+ public byte[] allocReadIOBuffer(int minSize) {
+ _verifyAlloc(_readIOBuffer);
+ return (_readIOBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_READ_IO_BUFFER, minSize));
+ }
+
+ public byte[] allocWriteEncodingBuffer() {
+ _verifyAlloc(_writeEncodingBuffer);
+ return (_writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER));
+ }
+
+ /**
+ * @since 2.4
+ */
+ public byte[] allocWriteEncodingBuffer(int minSize) {
+ _verifyAlloc(_writeEncodingBuffer);
+ return (_writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER, minSize));
+ }
+
+ /**
+ * @since 2.1
+ */
+ public byte[] allocBase64Buffer() {
+ _verifyAlloc(_base64Buffer);
+ return (_base64Buffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_BASE64_CODEC_BUFFER));
+ }
+
+ public char[] allocTokenBuffer() {
+ _verifyAlloc(_tokenCBuffer);
+ return (_tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER));
+ }
+
+ /**
+ * @since 2.4
+ */
+ public char[] allocTokenBuffer(int minSize) {
+ _verifyAlloc(_tokenCBuffer);
+ return (_tokenCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER, minSize));
+ }
+
+ public char[] allocConcatBuffer() {
+ _verifyAlloc(_concatCBuffer);
+ return (_concatCBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_CONCAT_BUFFER));
+ }
+
+ public char[] allocNameCopyBuffer(int minSize) {
+ _verifyAlloc(_nameCopyBuffer);
+ return (_nameCopyBuffer = _bufferRecycler.allocCharBuffer(BufferRecycler.CHAR_NAME_COPY_BUFFER, minSize));
+ }
+
+ /**
+ * Method to call when all the processing buffers can be safely
+ * recycled.
+ */
+ public void releaseReadIOBuffer(byte[] buf) {
+ if (buf != null) {
+ /* Let's do sanity checks to ensure once-and-only-once release,
+ * as well as avoiding trying to release buffers not owned
+ */
+ _verifyRelease(buf, _readIOBuffer);
+ _readIOBuffer = null;
+ _bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_READ_IO_BUFFER, buf);
+ }
+ }
+
+ public void releaseWriteEncodingBuffer(byte[] buf) {
+ if (buf != null) {
+ /* Let's do sanity checks to ensure once-and-only-once release,
+ * as well as avoiding trying to release buffers not owned
+ */
+ _verifyRelease(buf, _writeEncodingBuffer);
+ _writeEncodingBuffer = null;
+ _bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER, buf);
+ }
+ }
+
+ public void releaseBase64Buffer(byte[] buf) {
+ if (buf != null) { // sanity checks, release once-and-only-once, must be one owned
+ _verifyRelease(buf, _base64Buffer);
+ _base64Buffer = null;
+ _bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_BASE64_CODEC_BUFFER, buf);
+ }
+ }
+
+ public void releaseTokenBuffer(char[] buf) {
+ if (buf != null) {
+ _verifyRelease(buf, _tokenCBuffer);
+ _tokenCBuffer = null;
+ _bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER, buf);
+ }
+ }
+
+ public void releaseConcatBuffer(char[] buf) {
+ if (buf != null) {
+ // 14-Jan-2014, tatu: Let's actually allow upgrade of the original buffer.
+ _verifyRelease(buf, _concatCBuffer);
+ _concatCBuffer = null;
+ _bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_CONCAT_BUFFER, buf);
+ }
+ }
+
+ public void releaseNameCopyBuffer(char[] buf) {
+ if (buf != null) {
+ // 14-Jan-2014, tatu: Let's actually allow upgrade of the original buffer.
+ _verifyRelease(buf, _nameCopyBuffer);
+ _nameCopyBuffer = null;
+ _bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_NAME_COPY_BUFFER, buf);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal helpers
+ /**********************************************************
+ */
+
+ protected final void _verifyAlloc(Object buffer) {
+ if (buffer != null) { throw new IllegalStateException("Trying to call same allocXxx() method second time"); }
+ }
+
+ protected final void _verifyRelease(byte[] toRelease, byte[] src) {
+ if ((toRelease != src) && (toRelease.length <= src.length)) { throw wrongBuf(); }
+ }
+
+ protected final void _verifyRelease(char[] toRelease, char[] src) {
+ if ((toRelease != src) && (toRelease.length <= src.length)) { throw wrongBuf(); }
+ }
+
+ private IllegalArgumentException wrongBuf() { return new IllegalArgumentException("Trying to release buffer not owned by the context"); }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/InputDecorator.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/InputDecorator.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/InputDecorator.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,68 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+
+/**
+ * Handler class that can be used to decorate input sources.
+ * Typical use is to use a filter abstraction (filtered stream,
+ * reader) around original input source, and apply additional
+ * processing during read operations.
+ */
+public abstract class InputDecorator
+ implements java.io.Serializable // since 2.1
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
+ * creating parser given an {@link InputStream}, when this decorator
+ * has been registered.
+ *
+ * @param ctxt IO context in use (provides access to declared encoding).
+ * NOTE: at this point context may not have all information initialized;
+ * specifically auto-detected encoding is only available once parsing starts,
+ * which may occur only after this method is called.
+ * @param in Original input source
+ *
+ * @return InputStream to use; either 'in' as is, or decorator
+ * version that typically delogates to 'in'
+ */
+ public abstract InputStream decorate(IOContext ctxt, InputStream in)
+ throws IOException;
+
+ /**
+ * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
+ * creating parser on given "raw" byte source.
+ * Method can either construct a {@link InputStream} for reading; or return
+ * null to indicate that no wrapping should occur.
+ *
+ * @param ctxt IO context in use (provides access to declared encoding)
+ * NOTE: at this point context may not have all information initialized;
+ * specifically auto-detected encoding is only available once parsing starts,
+ * which may occur only after this method is called.
+ * @param src Input buffer that contains contents to parse
+ * @param offset Offset of the first available byte in the input buffer
+ * @param length Number of bytes available in the input buffer
+ *
+ * @return Either {@link InputStream} to use as input source; or null to indicate
+ * that contents are to be processed as-is by caller
+ */
+ public abstract InputStream decorate(IOContext ctxt, byte[] src, int offset, int length)
+ throws IOException;
+
+ /**
+ * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
+ * creating parser given an {@link Reader}, when this decorator
+ * has been registered.
+ *
+ * @param ctxt IO context in use (provides access to declared encoding)
+ * NOTE: at this point context may not have all information initialized;
+ * specifically auto-detected encoding is only available once parsing starts,
+ * which may occur only after this method is called.
+ * @param r Original reader
+ *
+ * @return Reader to use; either passed in argument, or something that
+ * calls it (for example, a {@link FilterReader})
+ */
+ public abstract Reader decorate(IOContext ctxt, Reader r) throws IOException;
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/JsonStringEncoder.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/JsonStringEncoder.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/JsonStringEncoder.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,392 @@
+package com.fasterxml.jackson.core.io;
+
+import java.lang.ref.SoftReference;
+
+import com.fasterxml.jackson.core.util.BufferRecycler;
+import com.fasterxml.jackson.core.util.ByteArrayBuilder;
+import com.fasterxml.jackson.core.util.TextBuffer;
+
+/**
+ * Helper class used for efficient encoding of JSON String values (including
+ * JSON field names) into Strings or UTF-8 byte arrays.
+ *
+ * Note that methods in here are somewhat optimized, but not ridiculously so.
+ * Reason is that conversion method results are expected to be cached so that
+ * these methods will not be hot spots during normal operation.
+ */
+public final class JsonStringEncoder
+{
+ private final static char[] HC = CharTypes.copyHexChars();
+
+ private final static byte[] HB = CharTypes.copyHexBytes();
+
+ private final static int SURR1_FIRST = 0xD800;
+ private final static int SURR1_LAST = 0xDBFF;
+ private final static int SURR2_FIRST = 0xDC00;
+ private final static int SURR2_LAST = 0xDFFF;
+
+// private final static int INT_BACKSLASH = '\\';
+// private final static int INT_U = 'u';
+// private final static int INT_0 = '0';
+
+ /**
+ * This
+ * Note: public to let unit tests call it
+ */
+ public static int parseInt(char[] ch, int off, int len)
+ {
+ int num = ch[off] - '0';
+
+ if (len > 4) {
+ num = (num * 10) + (ch[++off] - '0');
+ num = (num * 10) + (ch[++off] - '0');
+ num = (num * 10) + (ch[++off] - '0');
+ num = (num * 10) + (ch[++off] - '0');
+ len -= 4;
+ if (len > 4) {
+ num = (num * 10) + (ch[++off] - '0');
+ num = (num * 10) + (ch[++off] - '0');
+ num = (num * 10) + (ch[++off] - '0');
+ num = (num * 10) + (ch[++off] - '0');
+ return num;
+ }
+ }
+ if (len > 1) {
+ num = (num * 10) + (ch[++off] - '0');
+ if (len > 2) {
+ num = (num * 10) + (ch[++off] - '0');
+ if (len > 3) {
+ num = (num * 10) + (ch[++off] - '0');
+ }
+ }
+ }
+ return num;
+ }
+
+ /**
+ * Helper method to (more) efficiently parse integer numbers from
+ * String values.
+ */
+ public static int parseInt(String s)
+ {
+ /* Ok: let's keep strategy simple: ignoring optional minus sign,
+ * we'll accept 1 - 9 digits and parse things efficiently;
+ * otherwise just defer to JDK parse functionality.
+ */
+ char c = s.charAt(0);
+ int len = s.length();
+ boolean neg = (c == '-');
+ int offset = 1;
+ // must have 1 - 9 digits after optional sign:
+ // negative?
+ if (neg) {
+ if (len == 1 || len > 10) {
+ return Integer.parseInt(s);
+ }
+ c = s.charAt(offset++);
+ } else {
+ if (len > 9) {
+ return Integer.parseInt(s);
+ }
+ }
+ if (c > '9' || c < '0') {
+ return Integer.parseInt(s);
+ }
+ int num = c - '0';
+ if (offset < len) {
+ c = s.charAt(offset++);
+ if (c > '9' || c < '0') {
+ return Integer.parseInt(s);
+ }
+ num = (num * 10) + (c - '0');
+ if (offset < len) {
+ c = s.charAt(offset++);
+ if (c > '9' || c < '0') {
+ return Integer.parseInt(s);
+ }
+ num = (num * 10) + (c - '0');
+ // Let's just loop if we have more than 3 digits:
+ if (offset < len) {
+ do {
+ c = s.charAt(offset++);
+ if (c > '9' || c < '0') {
+ return Integer.parseInt(s);
+ }
+ num = (num * 10) + (c - '0');
+ } while (offset < len);
+ }
+ }
+ }
+ return neg ? -num : num;
+ }
+
+ public static long parseLong(char[] ch, int off, int len)
+ {
+ // Note: caller must ensure length is [10, 18]
+ int len1 = len-9;
+ long val = parseInt(ch, off, len1) * L_BILLION;
+ return val + (long) parseInt(ch, off+len1, 9);
+ }
+
+ public static long parseLong(String s)
+ {
+ /* Ok, now; as the very first thing, let's just optimize case of "fake longs";
+ * that is, if we know they must be ints, call int parsing
+ */
+ int length = s.length();
+ if (length <= 9) {
+ return (long) parseInt(s);
+ }
+ // !!! TODO: implement efficient 2-int parsing...
+ return Long.parseLong(s);
+ }
+
+ /**
+ * Helper method for determining if given String representation of
+ * an integral number would fit in 64-bit Java long or not.
+ * Note that input String must NOT contain leading minus sign (even
+ * if 'negative' is set to true).
+ *
+ * @param negative Whether original number had a minus sign (which is
+ * NOT passed to this method) or not
+ */
+ public static boolean inLongRange(char[] ch, int off, int len,
+ boolean negative)
+ {
+ String cmpStr = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
+ int cmpLen = cmpStr.length();
+ if (len < cmpLen) return true;
+ if (len > cmpLen) return false;
+
+ for (int i = 0; i < cmpLen; ++i) {
+ int diff = ch[off+i] - cmpStr.charAt(i);
+ if (diff != 0) {
+ return (diff < 0);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Similar to {@link #inLongRange(char[],int,int,boolean)}, but
+ * with String argument
+ *
+ * @param negative Whether original number had a minus sign (which is
+ * NOT passed to this method) or not
+ */
+ public static boolean inLongRange(String s, boolean negative)
+ {
+ String cmp = negative ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
+ int cmpLen = cmp.length();
+ int alen = s.length();
+ if (alen < cmpLen) return true;
+ if (alen > cmpLen) return false;
+
+ // could perhaps just use String.compareTo()?
+ for (int i = 0; i < cmpLen; ++i) {
+ int diff = s.charAt(i) - cmp.charAt(i);
+ if (diff != 0) {
+ return (diff < 0);
+ }
+ }
+ return true;
+ }
+
+ public static int parseAsInt(String s, int def)
+ {
+ if (s == null) {
+ return def;
+ }
+ s = s.trim();
+ int len = s.length();
+ if (len == 0) {
+ return def;
+ }
+ // One more thing: use integer parsing for 'simple'
+ int i = 0;
+ if (i < len) { // skip leading sign:
+ char c = s.charAt(0);
+ if (c == '+') { // for plus, actually physically remove
+ s = s.substring(1);
+ len = s.length();
+ } else if (c == '-') { // minus, just skip for checks, must retain
+ ++i;
+ }
+ }
+ for (; i < len; ++i) {
+ char c = s.charAt(i);
+ // if other symbols, parse as Double, coerce
+ if (c > '9' || c < '0') {
+ try {
+ return (int) parseDouble(s);
+ } catch (NumberFormatException e) {
+ return def;
+ }
+ }
+ }
+ try {
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) { }
+ return def;
+ }
+
+ public static long parseAsLong(String s, long def)
+ {
+ if (s == null) {
+ return def;
+ }
+ s = s.trim();
+ int len = s.length();
+ if (len == 0) {
+ return def;
+ }
+ // One more thing: use long parsing for 'simple'
+ int i = 0;
+ if (i < len) { // skip leading sign:
+ char c = s.charAt(0);
+ if (c == '+') { // for plus, actually physically remove
+ s = s.substring(1);
+ len = s.length();
+ } else if (c == '-') { // minus, just skip for checks, must retain
+ ++i;
+ }
+ }
+ for (; i < len; ++i) {
+ char c = s.charAt(i);
+ // if other symbols, parse as Double, coerce
+ if (c > '9' || c < '0') {
+ try {
+ return (long) parseDouble(s);
+ } catch (NumberFormatException e) {
+ return def;
+ }
+ }
+ }
+ try {
+ return Long.parseLong(s);
+ } catch (NumberFormatException e) { }
+ return def;
+ }
+
+ public static double parseAsDouble(String s, double def)
+ {
+ if (s == null) { return def; }
+ s = s.trim();
+ int len = s.length();
+ if (len == 0) {
+ return def;
+ }
+ try {
+ return parseDouble(s);
+ } catch (NumberFormatException e) { }
+ return def;
+ }
+
+ public static double parseDouble(String s) throws NumberFormatException {
+ // [JACKSON-486]: avoid some nasty float representations... but should it be MIN_NORMAL or MIN_VALUE?
+ /* as per [JACKSON-827], let's use MIN_VALUE as it is available on all JDKs; normalized
+ * only in JDK 1.6. In practice, should not really matter.
+ */
+ if (NASTY_SMALL_DOUBLE.equals(s)) {
+ return Double.MIN_VALUE;
+ }
+ return Double.parseDouble(s);
+ }
+
+ public static BigDecimal parseBigDecimal(String s) throws NumberFormatException {
+ try { return new BigDecimal(s); } catch (NumberFormatException e) {
+ throw _badBD(s);
+ }
+ }
+
+ public static BigDecimal parseBigDecimal(char[] b) throws NumberFormatException {
+ return parseBigDecimal(b, 0, b.length);
+ }
+
+ public static BigDecimal parseBigDecimal(char[] b, int off, int len) throws NumberFormatException {
+ try { return new BigDecimal(b, off, len); } catch (NumberFormatException e) {
+ throw _badBD(new String(b, off, len));
+ }
+ }
+
+ private static NumberFormatException _badBD(String s) {
+ return new NumberFormatException("Value \""+s+"\" can not be represented as BigDecimal");
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/NumberOutput.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/NumberOutput.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/NumberOutput.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,402 @@
+package com.fasterxml.jackson.core.io;
+
+public final class NumberOutput
+{
+ private final static char NC = (char) 0;
+
+ private static int MILLION = 1000000;
+ private static int BILLION = 1000000000;
+ private static long TEN_BILLION_L = 10000000000L;
+ private static long THOUSAND_L = 1000L;
+
+ private static long MIN_INT_AS_LONG = (long) Integer.MIN_VALUE;
+ private static long MAX_INT_AS_LONG = (long) Integer.MAX_VALUE;
+
+ final static String SMALLEST_LONG = String.valueOf(Long.MIN_VALUE);
+
+ private final static char[] LEAD_3 = new char[4000];
+ private final static char[] FULL_3 = new char[4000];
+ static {
+ /* Let's fill it with NULLs for ignorable leading digits,
+ * and digit chars for others
+ */
+ int ix = 0;
+ for (int i1 = 0; i1 < 10; ++i1) {
+ char f1 = (char) ('0' + i1);
+ char l1 = (i1 == 0) ? NC : f1;
+ for (int i2 = 0; i2 < 10; ++i2) {
+ char f2 = (char) ('0' + i2);
+ char l2 = (i1 == 0 && i2 == 0) ? NC : f2;
+ for (int i3 = 0; i3 < 10; ++i3) {
+ // Last is never to be empty
+ char f3 = (char) ('0' + i3);
+ LEAD_3[ix] = l1;
+ LEAD_3[ix+1] = l2;
+ LEAD_3[ix+2] = f3;
+ FULL_3[ix] = f1;
+ FULL_3[ix+1] = f2;
+ FULL_3[ix+2] = f3;
+ ix += 4;
+ }
+ }
+ }
+ }
+
+ private final static byte[] FULL_TRIPLETS_B = new byte[4000];
+ static {
+ for (int i = 0; i < 4000; ++i) {
+ FULL_TRIPLETS_B[i] = (byte) FULL_3[i];
+ }
+ }
+
+ private final static String[] sSmallIntStrs = new String[] {
+ "0","1","2","3","4","5","6","7","8","9","10"
+ };
+ private final static String[] sSmallIntStrs2 = new String[] {
+ "-1","-2","-3","-4","-5","-6","-7","-8","-9","-10"
+ };
+
+ /*
+ /**********************************************************
+ /* Efficient serialization methods using raw buffers
+ /**********************************************************
+ */
+
+ /**
+ * @return Offset within buffer after outputting int
+ */
+ public static int outputInt(int v, char[] b, int off)
+ {
+ if (v < 0) {
+ if (v == Integer.MIN_VALUE) {
+ /* Special case: no matching positive value within range;
+ * let's then "upgrade" to long and output as such.
+ */
+ return outputLong((long) v, b, off);
+ }
+ b[off++] = '-';
+ v = -v;
+ }
+
+ if (v < MILLION) { // at most 2 triplets...
+ if (v < 1000) {
+ if (v < 10) {
+ b[off++] = (char) ('0' + v);
+ } else {
+ off = leading3(v, b, off);
+ }
+ } else {
+ int thousands = v / 1000;
+ v -= (thousands * 1000); // == value % 1000
+ off = leading3(thousands, b, off);
+ off = full3(v, b, off);
+ }
+ return off;
+ }
+
+ // ok, all 3 triplets included
+ /* Let's first hand possible billions separately before
+ * handling 3 triplets. This is possible since we know we
+ * can have at most '2' as billion count.
+ */
+ boolean hasBillions = (v >= BILLION);
+ if (hasBillions) {
+ v -= BILLION;
+ if (v >= BILLION) {
+ v -= BILLION;
+ b[off++] = '2';
+ } else {
+ b[off++] = '1';
+ }
+ }
+ int newValue = v / 1000;
+ int ones = (v - (newValue * 1000)); // == value % 1000
+ v = newValue;
+ newValue /= 1000;
+ int thousands = (v - (newValue * 1000));
+
+ // value now has millions, which have 1, 2 or 3 digits
+ if (hasBillions) {
+ off = full3(newValue, b, off);
+ } else {
+ off = leading3(newValue, b, off);
+ }
+ off = full3(thousands, b, off);
+ off = full3(ones, b, off);
+ return off;
+ }
+
+ public static int outputInt(int v, byte[] b, int off)
+ {
+ if (v < 0) {
+ if (v == Integer.MIN_VALUE) {
+ return outputLong((long) v, b, off);
+ }
+ b[off++] = '-';
+ v = -v;
+ }
+
+ if (v < MILLION) { // at most 2 triplets...
+ if (v < 1000) {
+ if (v < 10) {
+ b[off++] = (byte) ('0' + v);
+ } else {
+ off = leading3(v, b, off);
+ }
+ } else {
+ int thousands = v / 1000;
+ v -= (thousands * 1000); // == value % 1000
+ off = leading3(thousands, b, off);
+ off = full3(v, b, off);
+ }
+ return off;
+ }
+ boolean hasB = (v >= BILLION);
+ if (hasB) {
+ v -= BILLION;
+ if (v >= BILLION) {
+ v -= BILLION;
+ b[off++] = '2';
+ } else {
+ b[off++] = '1';
+ }
+ }
+ int newValue = v / 1000;
+ int ones = (v - (newValue * 1000)); // == value % 1000
+ v = newValue;
+ newValue /= 1000;
+ int thousands = (v - (newValue * 1000));
+
+ if (hasB) {
+ off = full3(newValue, b, off);
+ } else {
+ off = leading3(newValue, b, off);
+ }
+ off = full3(thousands, b, off);
+ off = full3(ones, b, off);
+ return off;
+ }
+
+ /**
+ * @return Offset within buffer after outputting int
+ */
+ public static int outputLong(long v, char[] b, int off)
+ {
+ // First: does it actually fit in an int?
+ if (v < 0L) {
+ /* MIN_INT is actually printed as long, just because its
+ * negation is not an int but long
+ */
+ if (v > MIN_INT_AS_LONG) {
+ return outputInt((int) v, b, off);
+ }
+ if (v == Long.MIN_VALUE) {
+ // Special case: no matching positive value within range
+ int len = SMALLEST_LONG.length();
+ SMALLEST_LONG.getChars(0, len, b, off);
+ return (off + len);
+ }
+ b[off++] = '-';
+ v = -v;
+ } else {
+ if (v <= MAX_INT_AS_LONG) {
+ return outputInt((int) v, b, off);
+ }
+ }
+
+ /* Ok: real long print. Need to first figure out length
+ * in characters, and then print in from end to beginning
+ */
+ int origOffset = off;
+ off += calcLongStrLength(v);
+ int ptr = off;
+
+ // First, with long arithmetics:
+ while (v > MAX_INT_AS_LONG) { // full triplet
+ ptr -= 3;
+ long newValue = v / THOUSAND_L;
+ int triplet = (int) (v - newValue * THOUSAND_L);
+ full3(triplet, b, ptr);
+ v = newValue;
+ }
+ // Then with int arithmetics:
+ int ivalue = (int) v;
+ while (ivalue >= 1000) { // still full triplet
+ ptr -= 3;
+ int newValue = ivalue / 1000;
+ int triplet = ivalue - (newValue * 1000);
+ full3(triplet, b, ptr);
+ ivalue = newValue;
+ }
+ // And finally, if anything remains, partial triplet
+ leading3(ivalue, b, origOffset);
+
+ return off;
+ }
+
+ public static int outputLong(long v, byte[] b, int off)
+ {
+ if (v < 0L) {
+ if (v > MIN_INT_AS_LONG) {
+ return outputInt((int) v, b, off);
+ }
+ if (v == Long.MIN_VALUE) {
+ // Special case: no matching positive value within range
+ int len = SMALLEST_LONG.length();
+ for (int i = 0; i < len; ++i) {
+ b[off++] = (byte) SMALLEST_LONG.charAt(i);
+ }
+ return off;
+ }
+ b[off++] = '-';
+ v = -v;
+ } else {
+ if (v <= MAX_INT_AS_LONG) {
+ return outputInt((int) v, b, off);
+ }
+ }
+ int origOff = off;
+ off += calcLongStrLength(v);
+ int ptr = off;
+
+ // First, with long arithmetics:
+ while (v > MAX_INT_AS_LONG) { // full triplet
+ ptr -= 3;
+ long newV = v / THOUSAND_L;
+ int t = (int) (v - newV * THOUSAND_L);
+ full3(t, b, ptr);
+ v = newV;
+ }
+ // Then with int arithmetics:
+ int ivalue = (int) v;
+ while (ivalue >= 1000) { // still full triplet
+ ptr -= 3;
+ int newV = ivalue / 1000;
+ int t = ivalue - (newV * 1000);
+ full3(t, b, ptr);
+ ivalue = newV;
+ }
+ leading3(ivalue, b, origOff);
+ return off;
+ }
+
+ /*
+ /**********************************************************
+ /* Secondary convenience serialization methods
+ /**********************************************************
+ */
+
+ /* !!! 05-Aug-2008, tatus: Any ways to further optimize
+ * these? (or need: only called by diagnostics methods?)
+ */
+
+ public static String toString(int v)
+ {
+ // Lookup table for small values
+ if (v < sSmallIntStrs.length) {
+ if (v >= 0) {
+ return sSmallIntStrs[v];
+ }
+ int v2 = -v - 1;
+ if (v2 < sSmallIntStrs2.length) {
+ return sSmallIntStrs2[v2];
+ }
+ }
+ return Integer.toString(v);
+ }
+
+ public static String toString(long v) {
+ if (v <= Integer.MAX_VALUE && v >= Integer.MIN_VALUE) {
+ return toString((int) v);
+ }
+ return Long.toString(v);
+ }
+
+ public static String toString(double v) {
+ return Double.toString(v);
+ }
+
+ /**
+ * @since 2.6.0
+ */
+ public static String toString(float v) {
+ return Float.toString(v);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods
+ /**********************************************************
+ */
+
+ private static int leading3(int t, char[] b, int off)
+ {
+ int digitOffset = (t << 2);
+ char c = LEAD_3[digitOffset++];
+ if (c != NC) {
+ b[off++] = c;
+ }
+ c = LEAD_3[digitOffset++];
+ if (c != NC) {
+ b[off++] = c;
+ }
+ // Last is required to be non-empty
+ b[off++] = LEAD_3[digitOffset];
+ return off;
+ }
+
+ private static int leading3(int t, byte[] b, int off)
+ {
+ int digitOffset = (t << 2);
+ char c = LEAD_3[digitOffset++];
+ if (c != NC) {
+ b[off++] = (byte) c;
+ }
+ c = LEAD_3[digitOffset++];
+ if (c != NC) {
+ b[off++] = (byte) c;
+ }
+ // Last is required to be non-empty
+ b[off++] = (byte) LEAD_3[digitOffset];
+ return off;
+ }
+
+ private static int full3(int t, char[] b, int off)
+ {
+ int digitOffset = (t << 2);
+ b[off++] = FULL_3[digitOffset++];
+ b[off++] = FULL_3[digitOffset++];
+ b[off++] = FULL_3[digitOffset];
+ return off;
+ }
+
+ private static int full3(int t, byte[] b, int off)
+ {
+ int digitOffset = (t << 2);
+ b[off++] = FULL_TRIPLETS_B[digitOffset++];
+ b[off++] = FULL_TRIPLETS_B[digitOffset++];
+ b[off++] = FULL_TRIPLETS_B[digitOffset];
+ return off;
+ }
+
+ /**
+ *
+ * Pre-conditions:
+ * This class is most useful when serializing JSON content as a String:
+ * if so, instance of this class can be given as the writer to
+ *
+ * Class is final for performance reasons and since this is not designed to
+ * be extensible or customizable (customizations would occur in calling code)
+ */
+public class SerializedString
+ implements SerializableString, java.io.Serializable
+{
+ protected final String _value;
+
+ /* 13-Dec-2010, tatu: Whether use volatile or not is actually an important
+ * decision for multi-core use cases. Cost of volatility can be non-trivial
+ * for heavy use cases, and serialized-string instances are accessed often.
+ * Given that all code paths with common Jackson usage patterns go through
+ * a few memory barriers (mostly with cache/reuse pool access) it seems safe
+ * enough to omit volatiles here, given how simple lazy initialization is.
+ * This can be compared to how {@link String#hashCode} works; lazily and
+ * without synchronization or use of volatile keyword.
+ *
+ * Change to remove volatile was a request by implementors of a high-throughput
+ * search framework; and they believed this is an important optimization for
+ * heaviest, multi-core deployed use cases.
+ */
+ /*
+ * 22-Sep-2013, tatu: FWIW, there have been no reports of problems in this
+ * area, or anything pointing to it. So I think we are safe up to JDK7
+ * and hopefully beyond.
+ */
+
+ protected /*volatile*/ byte[] _quotedUTF8Ref;
+
+ protected /*volatile*/ byte[] _unquotedUTF8Ref;
+
+ protected /*volatile*/ char[] _quotedChars;
+
+ public SerializedString(String v) {
+ if (v == null) {
+ throw new IllegalStateException("Null String illegal for SerializedString");
+ }
+ _value = v;
+ }
+
+ /*
+ /**********************************************************
+ /* Serializable overrides
+ /**********************************************************
+ */
+
+ /**
+ * Ugly hack, to work through the requirement that _value is indeed final,
+ * and that JDK serialization won't call ctor(s).
+ *
+ * @since 2.1
+ */
+ protected transient String _jdkSerializeValue;
+
+ private void readObject(ObjectInputStream in) throws IOException {
+ _jdkSerializeValue = in.readUTF();
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ out.writeUTF(_value);
+ }
+
+ protected Object readResolve() {
+ return new SerializedString(_jdkSerializeValue);
+ }
+
+ /*
+ /**********************************************************
+ /* API
+ /**********************************************************
+ */
+
+ @Override
+ public final String getValue() { return _value; }
+
+ /**
+ * Returns length of the String as characters
+ */
+ @Override
+ public final int charLength() { return _value.length(); }
+
+ @Override
+ public final char[] asQuotedChars() {
+ char[] result = _quotedChars;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().quoteAsString(_value);
+ _quotedChars = result;
+ }
+ return result;
+ }
+
+ /**
+ * Accessor for accessing value that has been quoted using JSON
+ * quoting rules, and encoded using UTF-8 encoding.
+ */
+ @Override
+ public final byte[] asUnquotedUTF8() {
+ byte[] result = _unquotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
+ _unquotedUTF8Ref = result;
+ }
+ return result;
+ }
+
+ /**
+ * Accessor for accessing value as is (without JSON quoting)
+ * encoded using UTF-8 encoding.
+ */
+ @Override
+ public final byte[] asQuotedUTF8() {
+ byte[] result = _quotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
+ _quotedUTF8Ref = result;
+ }
+ return result;
+ }
+
+ /*
+ /**********************************************************
+ /* Additional 2.0 methods for appending/writing contents
+ /**********************************************************
+ */
+
+ @Override
+ public int appendQuotedUTF8(byte[] buffer, int offset) {
+ byte[] result = _quotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
+ _quotedUTF8Ref = result;
+ }
+ final int length = result.length;
+ if ((offset + length) > buffer.length) {
+ return -1;
+ }
+ System.arraycopy(result, 0, buffer, offset, length);
+ return length;
+ }
+
+ @Override
+ public int appendQuoted(char[] buffer, int offset) {
+ char[] result = _quotedChars;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().quoteAsString(_value);
+ _quotedChars = result;
+ }
+ final int length = result.length;
+ if ((offset + length) > buffer.length) {
+ return -1;
+ }
+ System.arraycopy(result, 0, buffer, offset, length);
+ return length;
+ }
+
+ @Override
+ public int appendUnquotedUTF8(byte[] buffer, int offset) {
+ byte[] result = _unquotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
+ _unquotedUTF8Ref = result;
+ }
+ final int length = result.length;
+ if ((offset + length) > buffer.length) {
+ return -1;
+ }
+ System.arraycopy(result, 0, buffer, offset, length);
+ return length;
+ }
+
+ @Override
+ public int appendUnquoted(char[] buffer, int offset) {
+ String str = _value;
+ final int length = str.length();
+ if ((offset + length) > buffer.length) {
+ return -1;
+ }
+ str.getChars(0, length, buffer, offset);
+ return length;
+ }
+
+ @Override
+ public int writeQuotedUTF8(OutputStream out) throws IOException {
+ byte[] result = _quotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
+ _quotedUTF8Ref = result;
+ }
+ final int length = result.length;
+ out.write(result, 0, length);
+ return length;
+ }
+
+ @Override
+ public int writeUnquotedUTF8(OutputStream out) throws IOException {
+ byte[] result = _unquotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
+ _unquotedUTF8Ref = result;
+ }
+ final int length = result.length;
+ out.write(result, 0, length);
+ return length;
+ }
+
+ @Override
+ public int putQuotedUTF8(ByteBuffer buffer) {
+ byte[] result = _quotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
+ _quotedUTF8Ref = result;
+ }
+ final int length = result.length;
+ if (length > buffer.remaining()) {
+ return -1;
+ }
+ buffer.put(result, 0, length);
+ return length;
+ }
+
+ @Override
+ public int putUnquotedUTF8(ByteBuffer buffer) {
+ byte[] result = _unquotedUTF8Ref;
+ if (result == null) {
+ result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
+ _unquotedUTF8Ref = result;
+ }
+ final int length = result.length;
+ if (length > buffer.remaining()) {
+ return -1;
+ }
+ buffer.put(result, 0, length);
+ return length;
+ }
+
+
+ /*
+ /**********************************************************
+ /* Standard method overrides
+ /**********************************************************
+ */
+
+ @Override
+ public final String toString() { return _value; }
+
+ @Override
+ public final int hashCode() { return _value.hashCode(); }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || o.getClass() != getClass()) return false;
+ SerializedString other = (SerializedString) o;
+ return _value.equals(other._value);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/UTF32Reader.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/UTF32Reader.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/UTF32Reader.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,268 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+
+
+/**
+ * Since JDK does not come with UTF-32/UCS-4, let's implement a simple
+ * decoder to use.
+ */
+public class UTF32Reader extends Reader
+{
+ /**
+ * JSON actually limits available Unicode range in the high end
+ * to the same as xml (to basically limit UTF-8 max byte sequence
+ * length to 4)
+ */
+ final protected static int LAST_VALID_UNICODE_CHAR = 0x10FFFF;
+
+ final protected static char NC = (char) 0;
+
+ final protected IOContext _context;
+
+ protected InputStream _in;
+
+ protected byte[] _buffer;
+
+ protected int _ptr;
+ protected int _length;
+
+ protected final boolean _bigEndian;
+
+ /**
+ * Although input is fine with full Unicode set, Java still uses
+ * 16-bit chars, so we may have to split high-order chars into
+ * surrogate pairs.
+ */
+ protected char _surrogate = NC;
+
+ /**
+ * Total read character count; used for error reporting purposes
+ */
+ protected int _charCount;
+
+ /**
+ * Total read byte count; used for error reporting purposes
+ */
+ protected int _byteCount;
+
+ protected final boolean _managedBuffers;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public UTF32Reader(IOContext ctxt, InputStream in, byte[] buf, int ptr, int len, boolean isBigEndian) {
+ _context = ctxt;
+ _in = in;
+ _buffer = buf;
+ _ptr = ptr;
+ _length = len;
+ _bigEndian = isBigEndian;
+ _managedBuffers = (in != null);
+ }
+
+ /*
+ /**********************************************************
+ /* Public API
+ /**********************************************************
+ */
+
+ @Override
+ public void close() throws IOException {
+ InputStream in = _in;
+
+ if (in != null) {
+ _in = null;
+ freeBuffers();
+ in.close();
+ }
+ }
+
+ protected char[] _tmpBuf;
+
+ /**
+ * Although this method is implemented by the base class, AND it should
+ * never be called by main code, let's still implement it bit more
+ * efficiently just in case
+ */
+ @Override
+ public int read() throws IOException {
+ if (_tmpBuf == null) {
+ _tmpBuf = new char[1];
+ }
+ if (read(_tmpBuf, 0, 1) < 1) {
+ return -1;
+ }
+ return _tmpBuf[0];
+ }
+
+ @Override
+ public int read(char[] cbuf, int start, int len) throws IOException {
+ // Already EOF?
+ if (_buffer == null) { return -1; }
+ if (len < 1) { return len; }
+ // Let's then ensure there's enough room...
+ if (start < 0 || (start+len) > cbuf.length) {
+ reportBounds(cbuf, start, len);
+ }
+
+ len += start;
+ int outPtr = start;
+
+ // Ok, first; do we have a surrogate from last round?
+ if (_surrogate != NC) {
+ cbuf[outPtr++] = _surrogate;
+ _surrogate = NC;
+ // No need to load more, already got one char
+ } else {
+ /* Note: we'll try to avoid blocking as much as possible. As a
+ * result, we only need to get 4 bytes for a full char.
+ */
+ int left = (_length - _ptr);
+ if (left < 4) {
+ if (!loadMore(left)) { // (legal) EOF?
+ return -1;
+ }
+ }
+ }
+
+ main_loop:
+ while (outPtr < len) {
+ int ptr = _ptr;
+ int ch;
+
+ if (_bigEndian) {
+ ch = (_buffer[ptr] << 24) | ((_buffer[ptr+1] & 0xFF) << 16)
+ | ((_buffer[ptr+2] & 0xFF) << 8) | (_buffer[ptr+3] & 0xFF);
+ } else {
+ ch = (_buffer[ptr] & 0xFF) | ((_buffer[ptr+1] & 0xFF) << 8)
+ | ((_buffer[ptr+2] & 0xFF) << 16) | (_buffer[ptr+3] << 24);
+ }
+ _ptr += 4;
+
+ // Does it need to be split to surrogates?
+ // (also, we can and need to verify illegal chars)
+ if (ch > 0xFFFF) { // need to split into surrogates?
+ if (ch > LAST_VALID_UNICODE_CHAR) {
+ reportInvalid(ch, outPtr-start,
+ "(above "+Integer.toHexString(LAST_VALID_UNICODE_CHAR)+") ");
+ }
+ ch -= 0x10000; // to normalize it starting with 0x0
+ cbuf[outPtr++] = (char) (0xD800 + (ch >> 10));
+ // hmmh. can this ever be 0? (not legal, at least?)
+ ch = (0xDC00 | (ch & 0x03FF));
+ // Room for second part?
+ if (outPtr >= len) { // nope
+ _surrogate = (char) ch;
+ break main_loop;
+ }
+ }
+ cbuf[outPtr++] = (char) ch;
+ if (_ptr >= _length) {
+ break main_loop;
+ }
+ }
+
+ len = outPtr - start;
+ _charCount += len;
+ return len;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods
+ /**********************************************************
+ */
+
+ private void reportUnexpectedEOF(int gotBytes, int needed) throws IOException {
+ int bytePos = _byteCount + gotBytes, charPos = _charCount;
+
+ throw new CharConversionException("Unexpected EOF in the middle of a 4-byte UTF-32 char: got "+gotBytes+", needed "+needed+", at char #"+charPos+", byte #"+bytePos+")");
+ }
+
+ private void reportInvalid(int value, int offset, String msg) throws IOException {
+ int bytePos = _byteCount + _ptr - 1, charPos = _charCount + offset;
+
+ throw new CharConversionException("Invalid UTF-32 character 0x"+Integer.toHexString(value)+msg+" at char #"+charPos+", byte #"+bytePos+")");
+ }
+
+ /**
+ * @param available Number of "unused" bytes in the input buffer
+ *
+ * @return True, if enough bytes were read to allow decoding of at least
+ * one full character; false if EOF was encountered instead.
+ */
+ private boolean loadMore(int available) throws IOException {
+ _byteCount += (_length - available);
+
+ // Bytes that need to be moved to the beginning of buffer?
+ if (available > 0) {
+ if (_ptr > 0) {
+ System.arraycopy(_buffer, _ptr, _buffer, 0, available);
+ _ptr = 0;
+ }
+ _length = available;
+ } else {
+ /* Ok; here we can actually reasonably expect an EOF,
+ * so let's do a separate read right away:
+ */
+ _ptr = 0;
+ int count = (_in == null) ? -1 : _in.read(_buffer);
+ if (count < 1) {
+ _length = 0;
+ if (count < 0) { // -1
+ if (_managedBuffers) {
+ freeBuffers(); // to help GC?
+ }
+ return false;
+ }
+ // 0 count is no good; let's err out
+ reportStrangeStream();
+ }
+ _length = count;
+ }
+
+ /* Need at least 4 bytes; if we don't get that many, it's an
+ * error.
+ */
+ while (_length < 4) {
+ int count = (_in == null) ? -1 : _in.read(_buffer, _length, _buffer.length - _length);
+ if (count < 1) {
+ if (count < 0) { // -1, EOF... no good!
+ if (_managedBuffers) {
+ freeBuffers(); // to help GC?
+ }
+ reportUnexpectedEOF(_length, 4);
+ }
+ // 0 count is no good; let's err out
+ reportStrangeStream();
+ }
+ _length += count;
+ }
+ return true;
+ }
+
+ /**
+ * This method should be called along with (or instead of) normal
+ * close. After calling this method, no further reads should be tried.
+ * Method will try to recycle read buffers (if any).
+ */
+ private void freeBuffers() {
+ byte[] buf = _buffer;
+ if (buf != null) {
+ _buffer = null;
+ _context.releaseReadIOBuffer(buf);
+ }
+ }
+
+ private void reportBounds(char[] cbuf, int start, int len) throws IOException {
+ throw new ArrayIndexOutOfBoundsException("read(buf,"+start+","+len+"), cbuf["+cbuf.length+"]");
+ }
+
+ private void reportStrangeStream() throws IOException {
+ throw new IOException("Strange I/O stream, returned 0 bytes on read");
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/UTF8Writer.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/UTF8Writer.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/UTF8Writer.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,387 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+
+public final class UTF8Writer extends Writer
+{
+ final static int SURR1_FIRST = 0xD800;
+ final static int SURR1_LAST = 0xDBFF;
+ final static int SURR2_FIRST = 0xDC00;
+ final static int SURR2_LAST = 0xDFFF;
+
+ final private IOContext _context;
+
+ private OutputStream _out;
+
+ private byte[] _outBuffer;
+
+ final private int _outBufferEnd;
+
+ private int _outPtr;
+
+ /**
+ * When outputting chars from BMP, surrogate pairs need to be coalesced.
+ * To do this, both pairs must be known first; and since it is possible
+ * pairs may be split, we need temporary storage for the first half
+ */
+ private int _surrogate;
+
+ public UTF8Writer(IOContext ctxt, OutputStream out)
+ {
+ _context = ctxt;
+ _out = out;
+
+ _outBuffer = ctxt.allocWriteEncodingBuffer();
+ /* Max. expansion for a single char (in unmodified UTF-8) is
+ * 4 bytes (or 3 depending on how you view it -- 4 when recombining
+ * surrogate pairs)
+ */
+ _outBufferEnd = _outBuffer.length - 4;
+ _outPtr = 0;
+ }
+
+ @Override
+ public Writer append(char c)
+ throws IOException
+ {
+ write(c);
+ return this;
+ }
+
+ @Override
+ public void close()
+ throws IOException
+ {
+ if (_out != null) {
+ if (_outPtr > 0) {
+ _out.write(_outBuffer, 0, _outPtr);
+ _outPtr = 0;
+ }
+ OutputStream out = _out;
+ _out = null;
+
+ byte[] buf = _outBuffer;
+ if (buf != null) {
+ _outBuffer = null;
+ _context.releaseWriteEncodingBuffer(buf);
+ }
+
+ out.close();
+
+ /* Let's 'flush' orphan surrogate, no matter what; but only
+ * after cleanly closing everything else.
+ */
+ int code = _surrogate;
+ _surrogate = 0;
+ if (code > 0) {
+ illegalSurrogate(code);
+ }
+ }
+ }
+
+ @Override
+ public void flush()
+ throws IOException
+ {
+ if (_out != null) {
+ if (_outPtr > 0) {
+ _out.write(_outBuffer, 0, _outPtr);
+ _outPtr = 0;
+ }
+ _out.flush();
+ }
+ }
+
+ @Override
+ public void write(char[] cbuf)
+ throws IOException
+ {
+ write(cbuf, 0, cbuf.length);
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len)
+ throws IOException
+ {
+ if (len < 2) {
+ if (len == 1) {
+ write(cbuf[off]);
+ }
+ return;
+ }
+
+ // First: do we have a leftover surrogate to deal with?
+ if (_surrogate > 0) {
+ char second = cbuf[off++];
+ --len;
+ write(convertSurrogate(second));
+ // will have at least one more char
+ }
+
+ int outPtr = _outPtr;
+ byte[] outBuf = _outBuffer;
+ int outBufLast = _outBufferEnd; // has 4 'spare' bytes
+
+ // All right; can just loop it nice and easy now:
+ len += off; // len will now be the end of input buffer
+
+ output_loop:
+ for (; off < len; ) {
+ /* First, let's ensure we can output at least 4 bytes
+ * (longest UTF-8 encoded codepoint):
+ */
+ if (outPtr >= outBufLast) {
+ _out.write(outBuf, 0, outPtr);
+ outPtr = 0;
+ }
+
+ int c = cbuf[off++];
+ // And then see if we have an Ascii char:
+ if (c < 0x80) { // If so, can do a tight inner loop:
+ outBuf[outPtr++] = (byte)c;
+ // Let's calc how many ascii chars we can copy at most:
+ int maxInCount = (len - off);
+ int maxOutCount = (outBufLast - outPtr);
+
+ if (maxInCount > maxOutCount) {
+ maxInCount = maxOutCount;
+ }
+ maxInCount += off;
+ ascii_loop:
+ while (true) {
+ if (off >= maxInCount) { // done with max. ascii seq
+ continue output_loop;
+ }
+ c = cbuf[off++];
+ if (c >= 0x80) {
+ break ascii_loop;
+ }
+ outBuf[outPtr++] = (byte) c;
+ }
+ }
+
+ // Nope, multi-byte:
+ if (c < 0x800) { // 2-byte
+ outBuf[outPtr++] = (byte) (0xc0 | (c >> 6));
+ outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f));
+ } else { // 3 or 4 bytes
+ // Surrogates?
+ if (c < SURR1_FIRST || c > SURR2_LAST) {
+ outBuf[outPtr++] = (byte) (0xe0 | (c >> 12));
+ outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f));
+ continue;
+ }
+ // Yup, a surrogate:
+ if (c > SURR1_LAST) { // must be from first range
+ _outPtr = outPtr;
+ illegalSurrogate(c);
+ }
+ _surrogate = c;
+ // and if so, followed by another from next range
+ if (off >= len) { // unless we hit the end?
+ break;
+ }
+ c = convertSurrogate(cbuf[off++]);
+ if (c > 0x10FFFF) { // illegal in JSON as well as in XML
+ _outPtr = outPtr;
+ illegalSurrogate(c);
+ }
+ outBuf[outPtr++] = (byte) (0xf0 | (c >> 18));
+ outBuf[outPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
+ outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f));
+ }
+ }
+ _outPtr = outPtr;
+ }
+
+ @Override
+ public void write(int c) throws IOException
+ {
+ // First; do we have a left over surrogate?
+ if (_surrogate > 0) {
+ c = convertSurrogate(c);
+ // If not, do we start with a surrogate?
+ } else if (c >= SURR1_FIRST && c <= SURR2_LAST) {
+ // Illegal to get second part without first:
+ if (c > SURR1_LAST) {
+ illegalSurrogate(c);
+ }
+ // First part just needs to be held for now
+ _surrogate = c;
+ return;
+ }
+
+ if (_outPtr >= _outBufferEnd) { // let's require enough room, first
+ _out.write(_outBuffer, 0, _outPtr);
+ _outPtr = 0;
+ }
+
+ if (c < 0x80) { // ascii
+ _outBuffer[_outPtr++] = (byte) c;
+ } else {
+ int ptr = _outPtr;
+ if (c < 0x800) { // 2-byte
+ _outBuffer[ptr++] = (byte) (0xc0 | (c >> 6));
+ _outBuffer[ptr++] = (byte) (0x80 | (c & 0x3f));
+ } else if (c <= 0xFFFF) { // 3 bytes
+ _outBuffer[ptr++] = (byte) (0xe0 | (c >> 12));
+ _outBuffer[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ _outBuffer[ptr++] = (byte) (0x80 | (c & 0x3f));
+ } else { // 4 bytes
+ if (c > 0x10FFFF) { // illegal
+ illegalSurrogate(c);
+ }
+ _outBuffer[ptr++] = (byte) (0xf0 | (c >> 18));
+ _outBuffer[ptr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
+ _outBuffer[ptr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ _outBuffer[ptr++] = (byte) (0x80 | (c & 0x3f));
+ }
+ _outPtr = ptr;
+ }
+ }
+
+ @Override
+ public void write(String str) throws IOException
+ {
+ write(str, 0, str.length());
+ }
+
+ @Override
+ public void write(String str, int off, int len) throws IOException
+ {
+ if (len < 2) {
+ if (len == 1) {
+ write(str.charAt(off));
+ }
+ return;
+ }
+
+ // First: do we have a leftover surrogate to deal with?
+ if (_surrogate > 0) {
+ char second = str.charAt(off++);
+ --len;
+ write(convertSurrogate(second));
+ // will have at least one more char (case of 1 char was checked earlier on)
+ }
+
+ int outPtr = _outPtr;
+ byte[] outBuf = _outBuffer;
+ int outBufLast = _outBufferEnd; // has 4 'spare' bytes
+
+ // All right; can just loop it nice and easy now:
+ len += off; // len will now be the end of input buffer
+
+ output_loop:
+ for (; off < len; ) {
+ /* First, let's ensure we can output at least 4 bytes
+ * (longest UTF-8 encoded codepoint):
+ */
+ if (outPtr >= outBufLast) {
+ _out.write(outBuf, 0, outPtr);
+ outPtr = 0;
+ }
+
+ int c = str.charAt(off++);
+ // And then see if we have an Ascii char:
+ if (c < 0x80) { // If so, can do a tight inner loop:
+ outBuf[outPtr++] = (byte)c;
+ // Let's calc how many ascii chars we can copy at most:
+ int maxInCount = (len - off);
+ int maxOutCount = (outBufLast - outPtr);
+
+ if (maxInCount > maxOutCount) {
+ maxInCount = maxOutCount;
+ }
+ maxInCount += off;
+ ascii_loop:
+ while (true) {
+ if (off >= maxInCount) { // done with max. ascii seq
+ continue output_loop;
+ }
+ c = str.charAt(off++);
+ if (c >= 0x80) {
+ break ascii_loop;
+ }
+ outBuf[outPtr++] = (byte) c;
+ }
+ }
+
+ // Nope, multi-byte:
+ if (c < 0x800) { // 2-byte
+ outBuf[outPtr++] = (byte) (0xc0 | (c >> 6));
+ outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f));
+ } else { // 3 or 4 bytes
+ // Surrogates?
+ if (c < SURR1_FIRST || c > SURR2_LAST) {
+ outBuf[outPtr++] = (byte) (0xe0 | (c >> 12));
+ outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f));
+ continue;
+ }
+ // Yup, a surrogate:
+ if (c > SURR1_LAST) { // must be from first range
+ _outPtr = outPtr;
+ illegalSurrogate(c);
+ }
+ _surrogate = c;
+ // and if so, followed by another from next range
+ if (off >= len) { // unless we hit the end?
+ break;
+ }
+ c = convertSurrogate(str.charAt(off++));
+ if (c > 0x10FFFF) { // illegal, as per RFC 4627
+ _outPtr = outPtr;
+ illegalSurrogate(c);
+ }
+ outBuf[outPtr++] = (byte) (0xf0 | (c >> 18));
+ outBuf[outPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f));
+ outBuf[outPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ outBuf[outPtr++] = (byte) (0x80 | (c & 0x3f));
+ }
+ }
+ _outPtr = outPtr;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods
+ /**********************************************************
+ */
+
+ /**
+ * Method called to calculate UTF codepoint, from a surrogate pair.
+ */
+ protected int convertSurrogate(int secondPart)
+ throws IOException
+ {
+ int firstPart = _surrogate;
+ _surrogate = 0;
+
+ // Ok, then, is the second part valid?
+ if (secondPart < SURR2_FIRST || secondPart > SURR2_LAST) {
+ throw new IOException("Broken surrogate pair: first char 0x"+Integer.toHexString(firstPart)+", second 0x"+Integer.toHexString(secondPart)+"; illegal combination");
+ }
+ return 0x10000 + ((firstPart - SURR1_FIRST) << 10) + (secondPart - SURR2_FIRST);
+ }
+
+ protected static void illegalSurrogate(int code) throws IOException {
+ throw new IOException(illegalSurrogateDesc(code));
+ }
+
+ protected static String illegalSurrogateDesc(int code)
+ {
+ if (code > 0x10FFFF) { // over max?
+ return "Illegal character point (0x"+Integer.toHexString(code)+") to output; max is 0x10FFFF as per RFC 4627";
+ }
+ if (code >= SURR1_FIRST) {
+ if (code <= SURR1_LAST) { // Unmatched first part (closing without second part?)
+ return "Unmatched first part of surrogate pair (0x"+Integer.toHexString(code)+")";
+ }
+ return "Unmatched second part of surrogate pair (0x"+Integer.toHexString(code)+")";
+ }
+ // should we ever get this?
+ return "Illegal character point (0x"+Integer.toHexString(code)+") to output";
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/ByteSourceJsonBootstrapper.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,499 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.format.InputAccessor;
+import com.fasterxml.jackson.core.format.MatchStrength;
+import com.fasterxml.jackson.core.io.*;
+import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
+import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
+
+/**
+ * This class is used to determine the encoding of byte stream
+ * that is to contain JSON content. Rules are fairly simple, and
+ * defined in JSON specification (RFC-4627 or newer), except
+ * for BOM handling, which is a property of underlying
+ * streams.
+ */
+public final class ByteSourceJsonBootstrapper
+{
+ final static byte UTF8_BOM_1 = (byte) 0xEF;
+ final static byte UTF8_BOM_2 = (byte) 0xBB;
+ final static byte UTF8_BOM_3 = (byte) 0xBF;
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ protected final IOContext _context;
+
+ protected final InputStream _in;
+
+ /*
+ /**********************************************************
+ /* Input buffering
+ /**********************************************************
+ */
+
+ protected final byte[] _inputBuffer;
+
+ private int _inputPtr;
+
+ private int _inputEnd;
+
+ /**
+ * Flag that indicates whether buffer above is to be recycled
+ * after being used or not.
+ */
+ private final boolean _bufferRecyclable;
+
+ /*
+ /**********************************************************
+ /* Input location
+ /**********************************************************
+ */
+
+ /**
+ * Current number of input units (bytes or chars) that were processed in
+ * previous blocks,
+ * before contents of current input buffer.
+ *
+ * Note: includes possible BOMs, if those were part of the input.
+ */
+ protected int _inputProcessed;
+
+ /*
+ /**********************************************************
+ /* Data gathered
+ /**********************************************************
+ */
+
+ protected boolean _bigEndian = true;
+
+ protected int _bytesPerChar; // 0 means "dunno yet"
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public ByteSourceJsonBootstrapper(IOContext ctxt, InputStream in) {
+ _context = ctxt;
+ _in = in;
+ _inputBuffer = ctxt.allocReadIOBuffer();
+ _inputEnd = _inputPtr = 0;
+ _inputProcessed = 0;
+ _bufferRecyclable = true;
+ }
+
+ public ByteSourceJsonBootstrapper(IOContext ctxt, byte[] inputBuffer, int inputStart, int inputLen) {
+ _context = ctxt;
+ _in = null;
+ _inputBuffer = inputBuffer;
+ _inputPtr = inputStart;
+ _inputEnd = (inputStart + inputLen);
+ // Need to offset this for correct location info
+ _inputProcessed = -inputStart;
+ _bufferRecyclable = false;
+ }
+
+ /*
+ /**********************************************************
+ /* Encoding detection during bootstrapping
+ /**********************************************************
+ */
+
+ /**
+ * Method that should be called after constructing an instace.
+ * It will figure out encoding that content uses, to allow
+ * for instantiating a proper scanner object.
+ */
+ public JsonEncoding detectEncoding() throws IOException
+ {
+ boolean foundEncoding = false;
+
+ // First things first: BOM handling
+ /* Note: we can require 4 bytes to be read, since no
+ * combination of BOM + valid JSON content can have
+ * shorter length (shortest valid JSON content is single
+ * digit char, but BOMs are chosen such that combination
+ * is always at least 4 chars long)
+ */
+ if (ensureLoaded(4)) {
+ int quad = (_inputBuffer[_inputPtr] << 24)
+ | ((_inputBuffer[_inputPtr+1] & 0xFF) << 16)
+ | ((_inputBuffer[_inputPtr+2] & 0xFF) << 8)
+ | (_inputBuffer[_inputPtr+3] & 0xFF);
+
+ if (handleBOM(quad)) {
+ foundEncoding = true;
+ } else {
+ /* If no BOM, need to auto-detect based on first char;
+ * this works since it must be 7-bit ascii (wrt. unicode
+ * compatible encodings, only ones JSON can be transferred
+ * over)
+ */
+ // UTF-32?
+ if (checkUTF32(quad)) {
+ foundEncoding = true;
+ } else if (checkUTF16(quad >>> 16)) {
+ foundEncoding = true;
+ }
+ }
+ } else if (ensureLoaded(2)) {
+ int i16 = ((_inputBuffer[_inputPtr] & 0xFF) << 8)
+ | (_inputBuffer[_inputPtr+1] & 0xFF);
+ if (checkUTF16(i16)) {
+ foundEncoding = true;
+ }
+ }
+
+ JsonEncoding enc;
+
+ /* Not found yet? As per specs, this means it must be UTF-8. */
+ if (!foundEncoding) {
+ enc = JsonEncoding.UTF8;
+ } else {
+ switch (_bytesPerChar) {
+ case 1: enc = JsonEncoding.UTF8;
+ break;
+ case 2: enc = _bigEndian ? JsonEncoding.UTF16_BE : JsonEncoding.UTF16_LE;
+ break;
+ case 4: enc = _bigEndian ? JsonEncoding.UTF32_BE : JsonEncoding.UTF32_LE;
+ break;
+ default: throw new RuntimeException("Internal error"); // should never get here
+ }
+ }
+ _context.setEncoding(enc);
+ return enc;
+ }
+
+ /*
+ /**********************************************************
+ /* Constructing a Reader
+ /**********************************************************
+ */
+
+ @SuppressWarnings("resource")
+ public Reader constructReader() throws IOException
+ {
+ JsonEncoding enc = _context.getEncoding();
+ switch (enc.bits()) {
+ case 8: // only in non-common case where we don't want to do direct mapping
+ case 16:
+ {
+ // First: do we have a Stream? If not, need to create one:
+ InputStream in = _in;
+
+ if (in == null) {
+ in = new ByteArrayInputStream(_inputBuffer, _inputPtr, _inputEnd);
+ } else {
+ /* Also, if we have any read but unused input (usually true),
+ * need to merge that input in:
+ */
+ if (_inputPtr < _inputEnd) {
+ in = new MergedStream(_context, in, _inputBuffer, _inputPtr, _inputEnd);
+ }
+ }
+ return new InputStreamReader(in, enc.getJavaName());
+ }
+ case 32:
+ return new UTF32Reader(_context, _in, _inputBuffer, _inputPtr, _inputEnd,
+ _context.getEncoding().isBigEndian());
+ }
+ throw new RuntimeException("Internal error"); // should never get here
+ }
+
+ public JsonParser constructParser(int parserFeatures, ObjectCodec codec,
+ ByteQuadsCanonicalizer rootByteSymbols, CharsToNameCanonicalizer rootCharSymbols,
+ int factoryFeatures) throws IOException
+ {
+ JsonEncoding enc = detectEncoding();
+
+ if (enc == JsonEncoding.UTF8) {
+ /* and without canonicalization, byte-based approach is not performance; just use std UTF-8 reader
+ * (which is ok for larger input; not so hot for smaller; but this is not a common case)
+ */
+ if (JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(factoryFeatures)) {
+ ByteQuadsCanonicalizer can = rootByteSymbols.makeChild(factoryFeatures);
+ return new UTF8StreamJsonParser(_context, parserFeatures, _in, codec, can,
+ _inputBuffer, _inputPtr, _inputEnd, _bufferRecyclable);
+ }
+ }
+ return new ReaderBasedJsonParser(_context, parserFeatures, constructReader(), codec,
+ rootCharSymbols.makeChild(factoryFeatures));
+ }
+
+ /*
+ /**********************************************************
+ /* Encoding detection for data format auto-detection
+ /**********************************************************
+ */
+
+ /**
+ * Current implementation is not as thorough as other functionality
+ * ({@link com.fasterxml.jackson.core.json.ByteSourceJsonBootstrapper});
+ * supports UTF-8, for example. But it should work, for now, and can
+ * be improved as necessary.
+ */
+ public static MatchStrength hasJSONFormat(InputAccessor acc) throws IOException
+ {
+ // Ideally we should see "[" or "{"; but if not, we'll accept double-quote (String)
+ // in future could also consider accepting non-standard matches?
+
+ if (!acc.hasMoreBytes()) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ byte b = acc.nextByte();
+ // Very first thing, a UTF-8 BOM?
+ if (b == UTF8_BOM_1) { // yes, looks like UTF-8 BOM
+ if (!acc.hasMoreBytes()) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ if (acc.nextByte() != UTF8_BOM_2) {
+ return MatchStrength.NO_MATCH;
+ }
+ if (!acc.hasMoreBytes()) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ if (acc.nextByte() != UTF8_BOM_3) {
+ return MatchStrength.NO_MATCH;
+ }
+ if (!acc.hasMoreBytes()) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ b = acc.nextByte();
+ }
+ // Then possible leading space
+ int ch = skipSpace(acc, b);
+ if (ch < 0) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ // First, let's see if it looks like a structured type:
+ if (ch == '{') { // JSON object?
+ // Ideally we need to find either double-quote or closing bracket
+ ch = skipSpace(acc);
+ if (ch < 0) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ if (ch == '"' || ch == '}') {
+ return MatchStrength.SOLID_MATCH;
+ }
+ // ... should we allow non-standard? Let's not yet... can add if need be
+ return MatchStrength.NO_MATCH;
+ }
+ MatchStrength strength;
+
+ if (ch == '[') {
+ ch = skipSpace(acc);
+ if (ch < 0) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ // closing brackets is easy; but for now, let's also accept opening...
+ if (ch == ']' || ch == '[') {
+ return MatchStrength.SOLID_MATCH;
+ }
+ return MatchStrength.SOLID_MATCH;
+ } else {
+ // plain old value is not very convincing...
+ strength = MatchStrength.WEAK_MATCH;
+ }
+
+ if (ch == '"') { // string value
+ return strength;
+ }
+ if (ch <= '9' && ch >= '0') { // number
+ return strength;
+ }
+ if (ch == '-') { // negative number
+ ch = skipSpace(acc);
+ if (ch < 0) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ return (ch <= '9' && ch >= '0') ? strength : MatchStrength.NO_MATCH;
+ }
+ // or one of literals
+ if (ch == 'n') { // null
+ return tryMatch(acc, "ull", strength);
+ }
+ if (ch == 't') { // true
+ return tryMatch(acc, "rue", strength);
+ }
+ if (ch == 'f') { // false
+ return tryMatch(acc, "alse", strength);
+ }
+ return MatchStrength.NO_MATCH;
+ }
+
+ private static MatchStrength tryMatch(InputAccessor acc, String matchStr, MatchStrength fullMatchStrength)
+ throws IOException
+ {
+ for (int i = 0, len = matchStr.length(); i < len; ++i) {
+ if (!acc.hasMoreBytes()) {
+ return MatchStrength.INCONCLUSIVE;
+ }
+ if (acc.nextByte() != matchStr.charAt(i)) {
+ return MatchStrength.NO_MATCH;
+ }
+ }
+ return fullMatchStrength;
+ }
+
+ private static int skipSpace(InputAccessor acc) throws IOException
+ {
+ if (!acc.hasMoreBytes()) {
+ return -1;
+ }
+ return skipSpace(acc, acc.nextByte());
+ }
+
+ private static int skipSpace(InputAccessor acc, byte b) throws IOException
+ {
+ while (true) {
+ int ch = (int) b & 0xFF;
+ if (!(ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t')) {
+ return ch;
+ }
+ if (!acc.hasMoreBytes()) {
+ return -1;
+ }
+ b = acc.nextByte();
+ ch = (int) b & 0xFF;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, parsing
+ /**********************************************************
+ */
+
+ /**
+ * @return True if a BOM was succesfully found, and encoding
+ * thereby recognized.
+ */
+ private boolean handleBOM(int quad) throws IOException
+ {
+ /* Handling of (usually) optional BOM (required for
+ * multi-byte formats); first 32-bit charsets:
+ */
+ switch (quad) {
+ case 0x0000FEFF:
+ _bigEndian = true;
+ _inputPtr += 4;
+ _bytesPerChar = 4;
+ return true;
+ case 0xFFFE0000: // UCS-4, LE?
+ _inputPtr += 4;
+ _bytesPerChar = 4;
+ _bigEndian = false;
+ return true;
+ case 0x0000FFFE: // UCS-4, in-order...
+ reportWeirdUCS4("2143"); // throws exception
+ case 0xFEFF0000: // UCS-4, in-order...
+ reportWeirdUCS4("3412"); // throws exception
+ }
+ // Ok, if not, how about 16-bit encoding BOMs?
+ int msw = quad >>> 16;
+ if (msw == 0xFEFF) { // UTF-16, BE
+ _inputPtr += 2;
+ _bytesPerChar = 2;
+ _bigEndian = true;
+ return true;
+ }
+ if (msw == 0xFFFE) { // UTF-16, LE
+ _inputPtr += 2;
+ _bytesPerChar = 2;
+ _bigEndian = false;
+ return true;
+ }
+ // And if not, then UTF-8 BOM?
+ if ((quad >>> 8) == 0xEFBBBF) { // UTF-8
+ _inputPtr += 3;
+ _bytesPerChar = 1;
+ _bigEndian = true; // doesn't really matter
+ return true;
+ }
+ return false;
+ }
+
+ private boolean checkUTF32(int quad) throws IOException
+ {
+ /* Handling of (usually) optional BOM (required for
+ * multi-byte formats); first 32-bit charsets:
+ */
+ if ((quad >> 8) == 0) { // 0x000000?? -> UTF32-BE
+ _bigEndian = true;
+ } else if ((quad & 0x00FFFFFF) == 0) { // 0x??000000 -> UTF32-LE
+ _bigEndian = false;
+ } else if ((quad & ~0x00FF0000) == 0) { // 0x00??0000 -> UTF32-in-order
+ reportWeirdUCS4("3412");
+ } else if ((quad & ~0x0000FF00) == 0) { // 0x0000??00 -> UTF32-in-order
+ reportWeirdUCS4("2143");
+ } else {
+ // Can not be valid UTF-32 encoded JSON...
+ return false;
+ }
+ // Not BOM (just regular content), nothing to skip past:
+ //_inputPtr += 4;
+ _bytesPerChar = 4;
+ return true;
+ }
+
+ private boolean checkUTF16(int i16)
+ {
+ if ((i16 & 0xFF00) == 0) { // UTF-16BE
+ _bigEndian = true;
+ } else if ((i16 & 0x00FF) == 0) { // UTF-16LE
+ _bigEndian = false;
+ } else { // nope, not UTF-16
+ return false;
+ }
+ // Not BOM (just regular content), nothing to skip past:
+ //_inputPtr += 2;
+ _bytesPerChar = 2;
+ return true;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, problem reporting
+ /**********************************************************
+ */
+
+ private void reportWeirdUCS4(String type) throws IOException {
+ throw new CharConversionException("Unsupported UCS-4 endianness ("+type+") detected");
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, raw input access
+ /**********************************************************
+ */
+
+ protected boolean ensureLoaded(int minimum) throws IOException {
+ /* Let's assume here buffer has enough room -- this will always
+ * be true for the limited used this method gets
+ */
+ int gotten = (_inputEnd - _inputPtr);
+ while (gotten < minimum) {
+ int count;
+
+ if (_in == null) { // block source
+ count = -1;
+ } else {
+ count = _in.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd);
+ }
+ if (count < 1) {
+ return false;
+ }
+ _inputEnd += count;
+ gotten += count;
+ }
+ return true;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/DupDetector.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/DupDetector.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/DupDetector.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,97 @@
+package com.fasterxml.jackson.core.json;
+
+import java.util.*;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Helper class used if
+ * {@link com.fasterxml.jackson.core.JsonParser.Feature#STRICT_DUPLICATE_DETECTION}
+ * is enabled.
+ * Optimized to try to limit memory usage and processing overhead for smallest
+ * entries, but without adding trashing (immutable objects would achieve optimal
+ * memory usage but lead to significant number of discarded temp objects for
+ * scopes with large number of entries). Another consideration is trying to limit
+ * actual number of compiled classes as it contributes significantly to overall
+ * jar size (due to linkage etc).
+ *
+ * @since 2.3
+ */
+public class DupDetector
+{
+ /**
+ * We need to store a back-reference here to parser/generator.
+ */
+ protected final Object _source;
+
+ protected String _firstName;
+
+ protected String _secondName;
+
+ /**
+ * Lazily constructed set of names already seen within this context.
+ */
+ protected HashSet
+ * 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;
+
+ /**
+ * Flag that is set if quoting is not to be added around
+ * JSON Object property names.
+ *
+ * @since 2.7
+ */
+ protected boolean _cfgUnqNames;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public JsonGeneratorImpl(IOContext ctxt, int features, ObjectCodec codec)
+ {
+ super(features, codec);
+ _ioContext = ctxt;
+ if (Feature.ESCAPE_NON_ASCII.enabledIn(features)) {
+ // inlined `setHighestNonEscapedChar()`
+ _maximumNonEscapedChar = 127;
+ }
+ _cfgUnqNames = !Feature.QUOTE_FIELD_NAMES.enabledIn(features);
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden configuration methods
+ /**********************************************************
+ */
+
+ @Override
+ public JsonGenerator enable(Feature f) {
+ super.enable(f);
+ if (f == Feature.QUOTE_FIELD_NAMES) {
+ _cfgUnqNames = false;
+ }
+ return this;
+ }
+
+ @Override
+ public JsonGenerator disable(Feature f) {
+ super.disable(f);
+ if (f == Feature.QUOTE_FIELD_NAMES) {
+ _cfgUnqNames = true;
+ }
+ return this;
+ }
+
+ @Override
+ protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures) {
+ super._checkStdFeatureChanges(newFeatureFlags, changedFeatures);
+ _cfgUnqNames = !Feature.QUOTE_FIELD_NAMES.enabledIn(newFeatureFlags);
+ }
+
+ @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
+ {
+ writeFieldName(fieldName);
+ writeString(value);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/JsonReadContext.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/JsonReadContext.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/JsonReadContext.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,245 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.CharTypes;
+
+/**
+ * Extension of {@link JsonStreamContext}, which implements
+ * core methods needed, and also exposes
+ * more complete API to parser implementation classes.
+ */
+public final class JsonReadContext extends JsonStreamContext
+{
+ // // // Configuration
+
+ /**
+ * Parent context for this context; null for root context.
+ */
+ protected final JsonReadContext _parent;
+
+ // // // Optional duplicate detection
+
+ protected DupDetector _dups;
+
+ /*
+ /**********************************************************
+ /* Simple instance reuse slots; speeds up things
+ /* a bit (10-15%) for docs with lots of small
+ /* arrays/objects (for which allocation was
+ /* visible in profile stack frames)
+ /**********************************************************
+ */
+
+ protected JsonReadContext _child;
+
+ /*
+ /**********************************************************
+ /* Location/state information (minus source reference)
+ /**********************************************************
+ */
+
+ protected String _currentName;
+
+ /**
+ * @since 2.5
+ */
+ protected Object _currentValue;
+
+ protected int _lineNr;
+ protected int _columnNr;
+
+ /*
+ /**********************************************************
+ /* Instance construction, config, reuse
+ /**********************************************************
+ */
+
+ public JsonReadContext(JsonReadContext parent, DupDetector dups, int type, int lineNr, int colNr) {
+ super();
+ _parent = parent;
+ _dups = dups;
+ _type = type;
+ _lineNr = lineNr;
+ _columnNr = colNr;
+ _index = -1;
+ }
+
+ protected void reset(int type, int lineNr, int colNr) {
+ _type = type;
+ _index = -1;
+ _lineNr = lineNr;
+ _columnNr = colNr;
+ _currentName = null;
+ _currentValue = null;
+ if (_dups != null) {
+ _dups.reset();
+ }
+ }
+
+ /*
+ public void trackDups(JsonParser jp) {
+ _dups = DupDetector.rootDetector(jp);
+ }
+ */
+
+ public JsonReadContext withDupDetector(DupDetector dups) {
+ _dups = dups;
+ return this;
+ }
+
+ @Override
+ public Object getCurrentValue() {
+ return _currentValue;
+ }
+
+ @Override
+ public void setCurrentValue(Object v) {
+ _currentValue = v;
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods
+ /**********************************************************
+ */
+
+ public static JsonReadContext createRootContext(int lineNr, int colNr, DupDetector dups) {
+ return new JsonReadContext(null, dups, TYPE_ROOT, lineNr, colNr);
+ }
+
+ public static JsonReadContext createRootContext(DupDetector dups) {
+ return new JsonReadContext(null, dups, TYPE_ROOT, 1, 0);
+ }
+
+ public JsonReadContext createChildArrayContext(int lineNr, int colNr) {
+ JsonReadContext ctxt = _child;
+ if (ctxt == null) {
+ _child = ctxt = new JsonReadContext(this,
+ (_dups == null) ? null : _dups.child(), TYPE_ARRAY, lineNr, colNr);
+ } else {
+ ctxt.reset(TYPE_ARRAY, lineNr, colNr);
+ }
+ return ctxt;
+ }
+
+ public JsonReadContext createChildObjectContext(int lineNr, int colNr) {
+ JsonReadContext ctxt = _child;
+ if (ctxt == null) {
+ _child = ctxt = new JsonReadContext(this,
+ (_dups == null) ? null : _dups.child(), TYPE_OBJECT, lineNr, colNr);
+ return ctxt;
+ }
+ ctxt.reset(TYPE_OBJECT, lineNr, colNr);
+ return ctxt;
+ }
+
+ /*
+ /**********************************************************
+ /* Abstract method implementation
+ /**********************************************************
+ */
+
+ @Override public String getCurrentName() { return _currentName; }
+ @Override public JsonReadContext getParent() { return _parent; }
+
+ /**
+ * Method that can be used to both clear the accumulated references
+ * (specifically value set with {@link #setCurrentValue(Object)})
+ * that should not be retained, and returns parent (as would
+ * {@link #getParent()} do). Typically called when closing the active
+ * context when encountering {@link JsonToken#END_ARRAY} or
+ * {@link JsonToken#END_OBJECT}.
+ *
+ * @since 2.7
+ */
+ public JsonReadContext clearAndGetParent() {
+ _currentValue = null;
+ // could also clear the current name, but seems cheap enough to leave?
+ return _parent;
+ }
+
+ /*
+ /**********************************************************
+ /* Extended API
+ /**********************************************************
+ */
+
+ /**
+ * @return Location pointing to the point where the context
+ * start marker was found
+ */
+ public JsonLocation getStartLocation(Object srcRef) {
+ // We don't keep track of offsets at this level (only reader does)
+ long totalChars = -1L;
+ return new JsonLocation(srcRef, totalChars, _lineNr, _columnNr);
+ }
+
+ public DupDetector getDupDetector() {
+ return _dups;
+ }
+
+ /*
+ /**********************************************************
+ /* State changes
+ /**********************************************************
+ */
+
+ public boolean expectComma() {
+ /* Assumption here is that we will be getting a value (at least
+ * before calling this method again), and
+ * so will auto-increment index to avoid having to do another call
+ */
+ int ix = ++_index; // starts from -1
+ return (_type != TYPE_ROOT && ix > 0);
+ }
+
+ public void setCurrentName(String name) throws JsonProcessingException {
+ _currentName = name;
+ if (_dups != null) { _checkDup(_dups, name); }
+ }
+
+ private void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
+ if (dd.isDup(name)) {
+ Object src = dd.getSource();
+ throw new JsonParseException(((src instanceof JsonGenerator) ? ((JsonParser) src) : null),
+ "Duplicate field '"+name+"'");
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden standard methods
+ /**********************************************************
+ */
+
+ /**
+ * Overridden to provide developer readable "JsonPath" representation
+ * of the context.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ switch (_type) {
+ case TYPE_ROOT:
+ sb.append("/");
+ break;
+ case TYPE_ARRAY:
+ sb.append('[');
+ sb.append(getCurrentIndex());
+ sb.append(']');
+ break;
+ case TYPE_OBJECT:
+ sb.append('{');
+ if (_currentName != null) {
+ sb.append('"');
+ CharTypes.appendQuoted(sb, _currentName);
+ sb.append('"');
+ } else {
+ sb.append('?');
+ }
+ sb.append('}');
+ break;
+ }
+ return sb.toString();
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/JsonWriteContext.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/JsonWriteContext.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/JsonWriteContext.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,241 @@
+package com.fasterxml.jackson.core.json;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Extension of {@link JsonStreamContext}, which implements
+ * core methods needed, and also exposes
+ * more complete API to generator implementation classes.
+ */
+public class JsonWriteContext extends JsonStreamContext
+{
+ // // // Return values for writeValue()
+
+ public final static int STATUS_OK_AS_IS = 0;
+ public final static int STATUS_OK_AFTER_COMMA = 1;
+ public final static int STATUS_OK_AFTER_COLON = 2;
+ public final static int STATUS_OK_AFTER_SPACE = 3; // in root context
+ public final static int STATUS_EXPECT_VALUE = 4;
+ public final static int STATUS_EXPECT_NAME = 5;
+
+ /**
+ * Parent context for this context; null for root context.
+ */
+ protected final JsonWriteContext _parent;
+
+ // // // Optional duplicate detection
+
+ protected DupDetector _dups;
+
+ /*
+ /**********************************************************
+ /* Simple instance reuse slots; speed up things
+ /* a bit (10-15%) for docs with lots of small
+ /* arrays/objects
+ /**********************************************************
+ */
+
+ protected JsonWriteContext _child;
+
+ /*
+ /**********************************************************
+ /* Location/state information (minus source reference)
+ /**********************************************************
+ */
+
+ /**
+ * Name of the field of which value is to be parsed; only
+ * used for OBJECT contexts
+ */
+ protected String _currentName;
+
+ /**
+ * @since 2.5
+ */
+ protected Object _currentValue;
+
+ /**
+ * Marker used to indicate that we just received a name, and
+ * now expect a value
+ */
+ protected boolean _gotName;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ protected JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups) {
+ super();
+ _type = type;
+ _parent = parent;
+ _dups = dups;
+ _index = -1;
+ }
+
+ protected JsonWriteContext reset(int type) {
+ _type = type;
+ _index = -1;
+ _currentName = null;
+ _gotName = false;
+ _currentValue = null;
+ if (_dups != null) { _dups.reset(); }
+ return this;
+ }
+
+ public JsonWriteContext withDupDetector(DupDetector dups) {
+ _dups = dups;
+ return this;
+ }
+
+ @Override
+ public Object getCurrentValue() {
+ return _currentValue;
+ }
+
+ @Override
+ public void setCurrentValue(Object v) {
+ _currentValue = v;
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods
+ /**********************************************************
+ */
+
+ /**
+ * @deprecated Since 2.3; use method that takes argument
+ */
+ @Deprecated
+ public static JsonWriteContext createRootContext() { return createRootContext(null); }
+
+ public static JsonWriteContext createRootContext(DupDetector dd) {
+ return new JsonWriteContext(TYPE_ROOT, null, dd);
+ }
+
+ public JsonWriteContext createChildArrayContext() {
+ JsonWriteContext ctxt = _child;
+ if (ctxt == null) {
+ _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this, (_dups == null) ? null : _dups.child());
+ return ctxt;
+ }
+ return ctxt.reset(TYPE_ARRAY);
+ }
+
+ public JsonWriteContext createChildObjectContext() {
+ JsonWriteContext ctxt = _child;
+ if (ctxt == null) {
+ _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this, (_dups == null) ? null : _dups.child());
+ return ctxt;
+ }
+ return ctxt.reset(TYPE_OBJECT);
+ }
+
+ @Override public final JsonWriteContext getParent() { return _parent; }
+ @Override public final String getCurrentName() { return _currentName; }
+
+ /**
+ * Method that can be used to both clear the accumulated references
+ * (specifically value set with {@link #setCurrentValue(Object)})
+ * that should not be retained, and returns parent (as would
+ * {@link #getParent()} do). Typically called when closing the active
+ * context when encountering {@link JsonToken#END_ARRAY} or
+ * {@link JsonToken#END_OBJECT}.
+ *
+ * @since 2.7
+ */
+ public JsonWriteContext clearAndGetParent() {
+ _currentValue = null;
+ // could also clear the current name, but seems cheap enough to leave?
+ return _parent;
+ }
+
+ public DupDetector getDupDetector() {
+ return _dups;
+ }
+
+ /**
+ * Method that writer is to call before it writes a field name.
+ *
+ * @return Index of the field entry (0-based)
+ */
+ public int writeFieldName(String name) throws JsonProcessingException {
+ if (_gotName) {
+ return STATUS_EXPECT_VALUE;
+ }
+ _gotName = true;
+ _currentName = name;
+ if (_dups != null) { _checkDup(_dups, name); }
+ return (_index < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA;
+ }
+
+ private final void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
+ if (dd.isDup(name)) {
+ Object src = dd.getSource();
+ throw new JsonGenerationException("Duplicate field '"+name+"'",
+ ((src instanceof JsonGenerator) ? ((JsonGenerator) src) : null));
+ }
+ }
+
+ public int writeValue() {
+ // Most likely, object:
+ if (_type == TYPE_OBJECT) {
+ if (!_gotName) {
+ return STATUS_EXPECT_NAME;
+ }
+ _gotName = false;
+ ++_index;
+ return STATUS_OK_AFTER_COLON;
+ }
+
+ // Ok, array?
+ if (_type == TYPE_ARRAY) {
+ int ix = _index;
+ ++_index;
+ return (ix < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA;
+ }
+
+ // Nope, root context
+ // No commas within root context, but need space
+ ++_index;
+ return (_index == 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_SPACE;
+ }
+
+ // // // Internally used abstract methods
+
+ protected void appendDesc(StringBuilder sb) {
+ if (_type == TYPE_OBJECT) {
+ sb.append('{');
+ if (_currentName != null) {
+ sb.append('"');
+ // !!! TODO: Name chars should be escaped?
+ sb.append(_currentName);
+ sb.append('"');
+ } else {
+ sb.append('?');
+ }
+ sb.append('}');
+ } else if (_type == TYPE_ARRAY) {
+ sb.append('[');
+ sb.append(getCurrentIndex());
+ sb.append(']');
+ } else {
+ // nah, ROOT:
+ sb.append("/");
+ }
+ }
+
+ // // // Overridden standard methods
+
+ /**
+ * Overridden to provide developer writeable "JsonPath" representation
+ * of the context.
+ */
+ @Override public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ appendDesc(sb);
+ return sb.toString();
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/PackageVersion.java.in
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/PackageVersion.java.in (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/PackageVersion.java.in (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,20 @@
+package @package@;
+
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.core.Versioned;
+import com.fasterxml.jackson.core.util.VersionUtil;
+
+/**
+ * Automatically generated from PackageVersion.java.in during
+ * packageVersion-generate execution of maven-replacer-plugin in
+ * pom.xml.
+ */
+public final class PackageVersion implements Versioned {
+ public final static Version VERSION = VersionUtil.parseVersion(
+ "@projectversion@", "@projectgroupid@", "@projectartifactid@");
+
+ @Override
+ public Version version() {
+ return VERSION;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,2756 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.base.ParserBase;
+import com.fasterxml.jackson.core.io.CharTypes;
+import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.sym.CharsToNameCanonicalizer;
+import com.fasterxml.jackson.core.util.*;
+
+import static com.fasterxml.jackson.core.JsonTokenId.*;
+
+/**
+ * This is a concrete implementation of {@link JsonParser}, which is
+ * based on a {@link java.io.Reader} to handle low-level character
+ * conversion tasks.
+ */
+public class ReaderBasedJsonParser // final in 2.3, earlier
+ extends ParserBase
+{
+ // Latin1 encoding is not supported, but we do use 8-bit subset for
+ // pre-processing task, to simplify first pass, keep it fast.
+ protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
+
+ /*
+ /**********************************************************
+ /* Input configuration
+ /**********************************************************
+ */
+
+ /**
+ * Reader that can be used for reading more content, if one
+ * buffer from input source, but in some cases pre-loaded buffer
+ * is handed to the parser.
+ */
+ protected Reader _reader;
+
+ /**
+ * Current buffer from which data is read; generally data is read into
+ * buffer from input source.
+ */
+ protected char[] _inputBuffer;
+
+ /**
+ * Flag that indicates whether the input buffer is recycable (and
+ * needs to be returned to recycler once we are done) or not.
+ *
+ * If it is not, it also means that parser can NOT modify underlying
+ * buffer.
+ */
+ protected boolean _bufferRecyclable;
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ protected ObjectCodec _objectCodec;
+
+ final protected CharsToNameCanonicalizer _symbols;
+
+ final protected int _hashSeed;
+
+ /*
+ /**********************************************************
+ /* Parsing state
+ /**********************************************************
+ */
+
+ /**
+ * Flag that indicates that the current token has not yet
+ * been fully processed, and needs to be finished for
+ * some access (or skipped to obtain the next token)
+ */
+ protected boolean _tokenIncomplete;
+
+ /**
+ * Value of {@link #_inputPtr} at the time when the first character of
+ * name token was read. Used for calculating token location when requested;
+ * combined with {@link #_currInputProcessed}, may be updated appropriately
+ * as needed.
+ *
+ * @since 2.7
+ */
+ protected long _nameStartOffset;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartRow;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartCol;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ /**
+ * Method called when caller wants to provide input buffer directly,
+ * and it may or may not be recyclable use standard recycle context.
+ *
+ * @since 2.4
+ */
+ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
+ ObjectCodec codec, CharsToNameCanonicalizer st,
+ char[] inputBuffer, int start, int end,
+ boolean bufferRecyclable)
+ {
+ super(ctxt, features);
+ _reader = r;
+ _inputBuffer = inputBuffer;
+ _inputPtr = start;
+ _inputEnd = end;
+ _objectCodec = codec;
+ _symbols = st;
+ _hashSeed = st.hashSeed();
+ _bufferRecyclable = bufferRecyclable;
+ }
+
+ /**
+ * Method called when input comes as a {@link java.io.Reader}, and buffer allocation
+ * can be done using default mechanism.
+ */
+ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r,
+ ObjectCodec codec, CharsToNameCanonicalizer st)
+ {
+ super(ctxt, features);
+ _reader = r;
+ _inputBuffer = ctxt.allocTokenBuffer();
+ _inputPtr = 0;
+ _inputEnd = 0;
+ _objectCodec = codec;
+ _symbols = st;
+ _hashSeed = st.hashSeed();
+ _bufferRecyclable = true;
+ }
+
+ /*
+ /**********************************************************
+ /* Base method defs, overrides
+ /**********************************************************
+ */
+
+ @Override public ObjectCodec getCodec() { return _objectCodec; }
+ @Override public void setCodec(ObjectCodec c) { _objectCodec = c; }
+
+ @Override
+ public int releaseBuffered(Writer w) throws IOException {
+ int count = _inputEnd - _inputPtr;
+ if (count < 1) { return 0; }
+ // let's just advance ptr to end
+ int origPtr = _inputPtr;
+ w.write(_inputBuffer, origPtr, count);
+ return count;
+ }
+
+ @Override public Object getInputSource() { return _reader; }
+
+ @Override
+ protected boolean loadMore() throws IOException
+ {
+ final int bufSize = _inputEnd;
+
+ _currInputProcessed += bufSize;
+ _currInputRowStart -= bufSize;
+
+ // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+ // this increase to avoid "moving" name-offset, resulting most likely
+ // in negative value, which is fine as combine value remains unchanged.
+ _nameStartOffset -= bufSize;
+
+ if (_reader != null) {
+ int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
+ if (count > 0) {
+ _inputPtr = 0;
+ _inputEnd = count;
+ return true;
+ }
+ // End of input
+ _closeInput();
+ // Should never return 0, so let's fail
+ if (count == 0) {
+ throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd);
+ }
+ }
+ return false;
+ }
+
+ protected char getNextChar(String eofMsg) throws IOException {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) { _reportInvalidEOF(eofMsg); }
+ }
+ return _inputBuffer[_inputPtr++];
+ }
+
+ @Override
+ protected void _closeInput() throws IOException {
+ /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
+ * on the underlying Reader, unless we "own" it, or auto-closing
+ * feature is enabled.
+ * One downside is that when using our optimized
+ * Reader (granted, we only do that for UTF-32...) this
+ * means that buffer recycling won't work correctly.
+ */
+ if (_reader != null) {
+ if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
+ _reader.close();
+ }
+ _reader = null;
+ }
+ }
+
+ /**
+ * Method called to release internal buffers owned by the base
+ * reader. This may be called along with {@link #_closeInput} (for
+ * example, when explicitly closing this reader instance), or
+ * separately (if need be).
+ */
+ @Override
+ protected void _releaseBuffers() throws IOException {
+ super._releaseBuffers();
+ // merge new symbols, if any
+ _symbols.release();
+ // and release buffers, if they are recyclable ones
+ if (_bufferRecyclable) {
+ char[] buf = _inputBuffer;
+ if (buf != null) {
+ _inputBuffer = null;
+ _ioContext.releaseTokenBuffer(buf);
+ }
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, data access
+ /**********************************************************
+ */
+
+ /**
+ * Method for accessing textual representation of the current event;
+ * if no current event (before first call to {@link #nextToken}, or
+ * after encountering end-of-input), returns null.
+ * Method can be called for any event.
+ */
+ @Override
+ public final String getText() throws IOException
+ {
+ JsonToken t = _currToken;
+ if (t == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ return _textBuffer.contentsAsString();
+ }
+ return _getText2(t);
+ }
+
+ // // // Let's override default impls for improved performance
+
+ // @since 2.1
+ @Override
+ public final String getValueAsString() throws IOException
+ {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ return _textBuffer.contentsAsString();
+ }
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return getCurrentName();
+ }
+ return super.getValueAsString(null);
+ }
+
+ // @since 2.1
+ @Override
+ public final String getValueAsString(String defValue) throws IOException {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ return _textBuffer.contentsAsString();
+ }
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return getCurrentName();
+ }
+ return super.getValueAsString(defValue);
+ }
+
+ protected final String _getText2(JsonToken t) {
+ if (t == null) {
+ return null;
+ }
+ switch (t.id()) {
+ case ID_FIELD_NAME:
+ return _parsingContext.getCurrentName();
+
+ case ID_STRING:
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.contentsAsString();
+ default:
+ return t.asString();
+ }
+ }
+
+ @Override
+ public final char[] getTextCharacters() throws IOException
+ {
+ if (_currToken != null) { // null only before/after document
+ switch (_currToken.id()) {
+ case ID_FIELD_NAME:
+ if (!_nameCopied) {
+ String name = _parsingContext.getCurrentName();
+ int nameLen = name.length();
+ if (_nameCopyBuffer == null) {
+ _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
+ } else if (_nameCopyBuffer.length < nameLen) {
+ _nameCopyBuffer = new char[nameLen];
+ }
+ name.getChars(0, nameLen, _nameCopyBuffer, 0);
+ _nameCopied = true;
+ }
+ return _nameCopyBuffer;
+ case ID_STRING:
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.getTextBuffer();
+ default:
+ return _currToken.asCharArray();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public final int getTextLength() throws IOException
+ {
+ if (_currToken != null) { // null only before/after document
+ switch (_currToken.id()) {
+ case ID_FIELD_NAME:
+ return _parsingContext.getCurrentName().length();
+ case ID_STRING:
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.size();
+ default:
+ return _currToken.asCharArray().length;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public final int getTextOffset() throws IOException
+ {
+ // Most have offset of 0, only some may have other values:
+ if (_currToken != null) {
+ switch (_currToken.id()) {
+ case ID_FIELD_NAME:
+ return 0;
+ case ID_STRING:
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.getTextOffset();
+ default:
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
+ {
+ if (_currToken != JsonToken.VALUE_STRING &&
+ (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
+ _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
+ }
+ /* To ensure that we won't see inconsistent data, better clear up
+ * state...
+ */
+ if (_tokenIncomplete) {
+ try {
+ _binaryValue = _decodeBase64(b64variant);
+ } catch (IllegalArgumentException iae) {
+ throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
+ }
+ /* let's clear incomplete only now; allows for accessing other
+ * textual content in error cases
+ */
+ _tokenIncomplete = false;
+ } else { // may actually require conversion...
+ if (_binaryValue == null) {
+ @SuppressWarnings("resource")
+ ByteArrayBuilder builder = _getByteArrayBuilder();
+ _decodeBase64(getText(), builder, b64variant);
+ _binaryValue = builder.toByteArray();
+ }
+ }
+ return _binaryValue;
+ }
+
+ @Override
+ public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
+ {
+ // if we have already read the token, just use whatever we may have
+ if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
+ byte[] b = getBinaryValue(b64variant);
+ out.write(b);
+ return b.length;
+ }
+ // otherwise do "real" incremental parsing...
+ byte[] buf = _ioContext.allocBase64Buffer();
+ try {
+ return _readBinary(b64variant, out, buf);
+ } finally {
+ _ioContext.releaseBase64Buffer(buf);
+ }
+ }
+
+ protected int _readBinary(Base64Variant b64variant, OutputStream out, byte[] buffer) throws IOException
+ {
+ int outputPtr = 0;
+ final int outputEnd = buffer.length - 3;
+ int outputCount = 0;
+
+ while (true) {
+ // first, we'll skip preceding white space, if any
+ char ch;
+ do {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ } while (ch <= INT_SPACE);
+ int bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) { // reached the end, fair and square?
+ if (ch == '"') {
+ break;
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 0);
+ if (bits < 0) { // white space to skip
+ continue;
+ }
+ }
+
+ // enough room? If not, flush
+ if (outputPtr > outputEnd) {
+ outputCount += outputPtr;
+ out.write(buffer, 0, outputPtr);
+ outputPtr = 0;
+ }
+
+ int decodedData = bits;
+
+ // then second base64 char; can't get padding yet, nor ws
+
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ bits = _decodeBase64Escape(b64variant, ch, 1);
+ }
+ decodedData = (decodedData << 6) | bits;
+
+ // third base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ bits = b64variant.decodeBase64Char(ch);
+
+ // First branch: can get padding (-> 1 byte)
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 4;
+ buffer[outputPtr++] = (byte) decodedData;
+ break;
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 2);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ // Ok, must get padding
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ if (!b64variant.usesPaddingChar(ch)) {
+ throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
+ }
+ // Got 12 bits, only need 8, need to shift
+ decodedData >>= 4;
+ buffer[outputPtr++] = (byte) decodedData;
+ continue;
+ }
+ }
+ // Nope, 2 or 3 bytes
+ decodedData = (decodedData << 6) | bits;
+ // fourth and last base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 2;
+ buffer[outputPtr++] = (byte) (decodedData >> 8);
+ buffer[outputPtr++] = (byte) decodedData;
+ break;
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 3);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ /* With padding we only get 2 bytes; but we have
+ * to shift it a bit so it is identical to triplet
+ * case with partial output.
+ * 3 chars gives 3x6 == 18 bits, of which 2 are
+ * dummies, need to discard:
+ */
+ decodedData >>= 2;
+ buffer[outputPtr++] = (byte) (decodedData >> 8);
+ buffer[outputPtr++] = (byte) decodedData;
+ continue;
+ }
+ }
+ // otherwise, our triplet is now complete
+ decodedData = (decodedData << 6) | bits;
+ buffer[outputPtr++] = (byte) (decodedData >> 16);
+ buffer[outputPtr++] = (byte) (decodedData >> 8);
+ buffer[outputPtr++] = (byte) decodedData;
+ }
+ _tokenIncomplete = false;
+ if (outputPtr > 0) {
+ outputCount += outputPtr;
+ out.write(buffer, 0, outputPtr);
+ }
+ return outputCount;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, traversal
+ /**********************************************************
+ */
+
+ /**
+ * @return Next token from the stream, if any found, or null
+ * to indicate end-of-input
+ */
+ @Override
+ public final JsonToken nextToken() throws IOException
+ {
+ /* First: field names are special -- we will always tokenize
+ * (part of) value along with field name to simplify
+ * state handling. If so, can and need to use secondary token:
+ */
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return _nextAfterName();
+ }
+ // But if we didn't already have a name, and (partially?) decode number,
+ // need to ensure no numeric information is leaked
+ _numTypesValid = NR_UNKNOWN;
+ if (_tokenIncomplete) {
+ _skipString(); // only strings can be partial
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) { // end-of-input
+ /* 19-Feb-2009, tatu: Should actually close/release things
+ * like input source, symbol table and recyclable buffers now.
+ */
+ close();
+ return (_currToken = null);
+ }
+ // clear any data retained so far
+ _binaryValue = null;
+
+ // Closing scope?
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ return (_currToken = JsonToken.END_ARRAY);
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ return (_currToken = JsonToken.END_OBJECT);
+ }
+
+ // Nope: do we then expect a comma?
+ if (_parsingContext.expectComma()) {
+ i = _skipComma(i);
+ }
+
+ /* And should we now have a name? Always true for Object contexts, since
+ * the intermediate 'expect-value' state is never retained.
+ */
+ boolean inObject = _parsingContext.inObject();
+ if (inObject) {
+ // First, field name itself:
+ _updateNameLocation();
+ String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
+ _parsingContext.setCurrentName(name);
+ _currToken = JsonToken.FIELD_NAME;
+ i = _skipColon();
+ }
+ _updateLocation();
+
+ // Ok: we must have a value... what is it?
+
+ JsonToken t;
+
+ switch (i) {
+ case '"':
+ _tokenIncomplete = true;
+ t = JsonToken.VALUE_STRING;
+ break;
+ case '[':
+ if (!inObject) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ }
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ if (!inObject) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ t = JsonToken.START_OBJECT;
+ break;
+ case ']':
+ case '}':
+ // Error: neither is valid at this point; valid closers have
+ // been handled earlier
+ _reportUnexpectedChar(i, "expected a value");
+ case 't':
+ _matchTrue();
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case 'f':
+ _matchFalse();
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchNull();
+ t = JsonToken.VALUE_NULL;
+ break;
+
+ case '-':
+ /* Should we have separate handling for plus? Although
+ * it is not allowed per se, it may be erroneously used,
+ * and could be indicate by a more specific error message.
+ */
+ t = _parseNegNumber();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ default:
+ t = _handleOddValue(i);
+ break;
+ }
+
+ if (inObject) {
+ _nextToken = t;
+ return _currToken;
+ }
+ _currToken = t;
+ return t;
+ }
+
+ private final JsonToken _nextAfterName()
+ {
+ _nameCopied = false; // need to invalidate if it was copied
+ JsonToken t = _nextToken;
+ _nextToken = null;
+
+// !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
+
+ // Also: may need to start new context?
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return (_currToken = t);
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, nextXxx() overrides
+ /**********************************************************
+ */
+
+ // Implemented since 2.7
+ @Override
+ public boolean nextFieldName(SerializableString sstr) throws IOException
+ {
+ // // // Note: most of code below is copied from nextToken()
+
+ _numTypesValid = NR_UNKNOWN;
+ if (_currToken == JsonToken.FIELD_NAME) {
+ _nextAfterName();
+ return false;
+ }
+ if (_tokenIncomplete) {
+ _skipString();
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) {
+ close();
+ _currToken = null;
+ return false;
+ }
+ _binaryValue = null;
+
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_ARRAY;
+ return false;
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_OBJECT;
+ return false;
+ }
+ if (_parsingContext.expectComma()) {
+ i = _skipComma(i);
+ }
+
+ if (!_parsingContext.inObject()) {
+ _updateLocation();
+ _nextTokenNotInObject(i);
+ return false;
+ }
+
+ _updateNameLocation();
+ if (i == INT_QUOTE) {
+ // when doing literal match, must consider escaping:
+ char[] nameChars = sstr.asQuotedChars();
+ final int len = nameChars.length;
+
+ // Require 4 more bytes for faster skipping of colon that follows name
+ if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
+ // first check length match by
+ final int end = _inputPtr+len;
+ if (_inputBuffer[end] == '"') {
+ int offset = 0;
+ int ptr = _inputPtr;
+ while (true) {
+ if (ptr == end) { // yes, match!
+ _parsingContext.setCurrentName(sstr.getValue());
+ _isNextTokenNameYes(_skipColonFast(ptr+1));
+ return true;
+ }
+ if (nameChars[offset] != _inputBuffer[ptr]) {
+ break;
+ }
+ ++offset;
+ ++ptr;
+ }
+ }
+ }
+ }
+ return _isNextTokenNameMaybe(i, sstr.getValue());
+ }
+
+ @Override
+ public String nextFieldName() throws IOException
+ {
+ // // // Note: this is almost a verbatim copy of nextToken() (minus comments)
+
+ _numTypesValid = NR_UNKNOWN;
+ if (_currToken == JsonToken.FIELD_NAME) {
+ _nextAfterName();
+ return null;
+ }
+ if (_tokenIncomplete) {
+ _skipString();
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) {
+ close();
+ _currToken = null;
+ return null;
+ }
+ _binaryValue = null;
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_ARRAY;
+ return null;
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_OBJECT;
+ return null;
+ }
+ if (_parsingContext.expectComma()) {
+ i = _skipComma(i);
+ }
+ if (!_parsingContext.inObject()) {
+ _updateLocation();
+ _nextTokenNotInObject(i);
+ return null;
+ }
+
+ _updateNameLocation();
+ String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
+ _parsingContext.setCurrentName(name);
+ _currToken = JsonToken.FIELD_NAME;
+ i = _skipColon();
+
+ _updateLocation();
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return name;
+ }
+
+ // Ok: we must have a value... what is it?
+
+ JsonToken t;
+
+ switch (i) {
+ case '-':
+ t = _parseNegNumber();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ case 'f':
+ _matchFalse();
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchNull();
+ t = JsonToken.VALUE_NULL;
+ break;
+ case 't':
+ _matchTrue();
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case '[':
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ t = JsonToken.START_OBJECT;
+ break;
+ default:
+ t = _handleOddValue(i);
+ break;
+ }
+ _nextToken = t;
+ return name;
+ }
+
+ private final void _isNextTokenNameYes(int i) throws IOException
+ {
+ _currToken = JsonToken.FIELD_NAME;
+ _updateLocation();
+
+ switch (i) {
+ case '"':
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return;
+ case '[':
+ _nextToken = JsonToken.START_ARRAY;
+ return;
+ case '{':
+ _nextToken = JsonToken.START_OBJECT;
+ return;
+ case 't':
+ _matchToken("true", 1);
+ _nextToken = JsonToken.VALUE_TRUE;
+ return;
+ case 'f':
+ _matchToken("false", 1);
+ _nextToken = JsonToken.VALUE_FALSE;
+ return;
+ case 'n':
+ _matchToken("null", 1);
+ _nextToken = JsonToken.VALUE_NULL;
+ return;
+ case '-':
+ _nextToken = _parseNegNumber();
+ return;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ _nextToken = _parsePosNumber(i);
+ return;
+ }
+ _nextToken = _handleOddValue(i);
+ }
+
+ protected boolean _isNextTokenNameMaybe(int i, String nameToMatch) throws IOException
+ {
+ // // // and this is back to standard nextToken()
+ String name = (i == INT_QUOTE) ? _parseName() : _handleOddName(i);
+ _parsingContext.setCurrentName(name);
+ _currToken = JsonToken.FIELD_NAME;
+ i = _skipColon();
+ _updateLocation();
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return nameToMatch.equals(name);
+ }
+ // Ok: we must have a value... what is it?
+ JsonToken t;
+ switch (i) {
+ case '-':
+ t = _parseNegNumber();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ case 'f':
+ _matchFalse();
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchNull();
+ t = JsonToken.VALUE_NULL;
+ break;
+ case 't':
+ _matchTrue();
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case '[':
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ t = JsonToken.START_OBJECT;
+ break;
+ default:
+ t = _handleOddValue(i);
+ break;
+ }
+ _nextToken = t;
+ return nameToMatch.equals(name);
+ }
+
+ private final JsonToken _nextTokenNotInObject(int i) throws IOException
+ {
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ return (_currToken = JsonToken.VALUE_STRING);
+ }
+ switch (i) {
+ case '[':
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ return (_currToken = JsonToken.START_ARRAY);
+ case '{':
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ return (_currToken = JsonToken.START_OBJECT);
+ case 't':
+ _matchToken("true", 1);
+ return (_currToken = JsonToken.VALUE_TRUE);
+ case 'f':
+ _matchToken("false", 1);
+ return (_currToken = JsonToken.VALUE_FALSE);
+ case 'n':
+ _matchToken("null", 1);
+ return (_currToken = JsonToken.VALUE_NULL);
+ case '-':
+ return (_currToken = _parseNegNumber());
+ /* Should we have separate handling for plus? Although
+ * it is not allowed per se, it may be erroneously used,
+ * and could be indicated by a more specific error message.
+ */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return (_currToken = _parsePosNumber(i));
+ }
+ return (_currToken = _handleOddValue(i));
+ }
+
+ // note: identical to one in UTF8StreamJsonParser
+ @Override
+ public final String nextTextValue() throws IOException
+ {
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString();
+ }
+ return _textBuffer.contentsAsString();
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return null;
+ }
+ // !!! TODO: optimize this case as well
+ return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+ }
+
+ // note: identical to one in Utf8StreamParser
+ @Override
+ public final int nextIntValue(int defaultValue) throws IOException
+ {
+ if (_currToken == JsonToken.FIELD_NAME) {
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return getIntValue();
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return defaultValue;
+ }
+ // !!! TODO: optimize this case as well
+ return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+ }
+
+ // note: identical to one in Utf8StreamParser
+ @Override
+ public final long nextLongValue(long defaultValue) throws IOException
+ {
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return getLongValue();
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return defaultValue;
+ }
+ // !!! TODO: optimize this case as well
+ return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+ }
+
+ // note: identical to one in UTF8StreamJsonParser
+ @Override
+ public final Boolean nextBooleanValue() throws IOException
+ {
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_TRUE) {
+ return Boolean.TRUE;
+ }
+ if (t == JsonToken.VALUE_FALSE) {
+ return Boolean.FALSE;
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return null;
+ }
+ JsonToken t = nextToken();
+ if (t != null) {
+ int id = t.id();
+ if (id == ID_TRUE) return Boolean.TRUE;
+ if (id == ID_FALSE) return Boolean.FALSE;
+ }
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, number parsing
+ /**********************************************************
+ */
+
+ /**
+ * Initial parsing method for number values. It needs to be able
+ * to parse enough input to be able to determine whether the
+ * value is to be considered a simple integer value, or a more
+ * generic decimal value: latter of which needs to be expressed
+ * as a floating point number. The basic rule is that if the number
+ * has no fractional or exponential part, it is an integer; otherwise
+ * a floating point number.
+ *
+ * Because much of input has to be processed in any case, no partial
+ * parsing is done: all input text will be stored for further
+ * processing. However, actual numeric value conversion will be
+ * deferred, since it is usually the most complicated and costliest
+ * part of processing.
+ */
+ protected final JsonToken _parsePosNumber(int ch) throws IOException
+ {
+ /* Although we will always be complete with respect to textual
+ * representation (that is, all characters will be parsed),
+ * actual conversion to a number is deferred. Thus, need to
+ * note that no representations are valid yet
+ */
+ int ptr = _inputPtr;
+ int startPtr = ptr-1; // to include digit already read
+ final int inputLen = _inputEnd;
+
+ // One special case, leading zero(es):
+ if (ch == INT_0) {
+ return _parseNumber2(false, startPtr);
+ }
+
+ /* First, let's see if the whole number is contained within
+ * the input buffer unsplit. This should be the common case;
+ * and to simplify processing, we will just reparse contents
+ * in the alternative case (number split on buffer boundary)
+ */
+
+ int intLen = 1; // already got one
+
+ // First let's get the obligatory integer part:
+ int_loop:
+ while (true) {
+ if (ptr >= inputLen) {
+ _inputPtr = startPtr;
+ return _parseNumber2(false, startPtr);
+ }
+ ch = (int) _inputBuffer[ptr++];
+ if (ch < INT_0 || ch > INT_9) {
+ break int_loop;
+ }
+ ++intLen;
+ }
+ if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
+ _inputPtr = ptr;
+ return _parseFloat(ch, startPtr, ptr, false, intLen);
+ }
+ // Got it all: let's add to text buffer for parsing, access
+ --ptr; // need to push back following separator
+ _inputPtr = ptr;
+ // As per #105, need separating space between root values; check here
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(ch);
+ }
+ int len = ptr-startPtr;
+ _textBuffer.resetWithShared(_inputBuffer, startPtr, len);
+ return resetInt(false, intLen);
+ }
+
+ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, int intLen)
+ throws IOException
+ {
+ final int inputLen = _inputEnd;
+ int fractLen = 0;
+
+ // And then see if we get other parts
+ if (ch == '.') { // yes, fraction
+ fract_loop:
+ while (true) {
+ if (ptr >= inputLen) {
+ return _parseNumber2(neg, startPtr);
+ }
+ ch = (int) _inputBuffer[ptr++];
+ if (ch < INT_0 || ch > INT_9) {
+ break fract_loop;
+ }
+ ++fractLen;
+ }
+ // must be followed by sequence of ints, one minimum
+ if (fractLen == 0) {
+ reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
+ }
+ }
+ int expLen = 0;
+ if (ch == 'e' || ch == 'E') { // and/or exponent
+ if (ptr >= inputLen) {
+ _inputPtr = startPtr;
+ return _parseNumber2(neg, startPtr);
+ }
+ // Sign indicator?
+ ch = (int) _inputBuffer[ptr++];
+ if (ch == INT_MINUS || ch == INT_PLUS) { // yup, skip for now
+ if (ptr >= inputLen) {
+ _inputPtr = startPtr;
+ return _parseNumber2(neg, startPtr);
+ }
+ ch = (int) _inputBuffer[ptr++];
+ }
+ while (ch <= INT_9 && ch >= INT_0) {
+ ++expLen;
+ if (ptr >= inputLen) {
+ _inputPtr = startPtr;
+ return _parseNumber2(neg, startPtr);
+ }
+ ch = (int) _inputBuffer[ptr++];
+ }
+ // must be followed by sequence of ints, one minimum
+ if (expLen == 0) {
+ reportUnexpectedNumberChar(ch, "Exponent indicator not followed by a digit");
+ }
+ }
+ --ptr; // need to push back following separator
+ _inputPtr = ptr;
+ // As per #105, need separating space between root values; check here
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(ch);
+ }
+ int len = ptr-startPtr;
+ _textBuffer.resetWithShared(_inputBuffer, startPtr, len);
+ // And there we have it!
+ return resetFloat(neg, intLen, fractLen, expLen);
+ }
+
+ protected final JsonToken _parseNegNumber() throws IOException
+ {
+ int ptr = _inputPtr;
+ int startPtr = ptr-1; // to include sign/digit already read
+ final int inputLen = _inputEnd;
+
+ if (ptr >= inputLen) {
+ return _parseNumber2(true, startPtr);
+ }
+ int ch = _inputBuffer[ptr++];
+ // First check: must have a digit to follow minus sign
+ if (ch > INT_9 || ch < INT_0) {
+ _inputPtr = ptr;
+ return _handleInvalidNumberStart(ch, true);
+ }
+ // One special case, leading zero(es):
+ if (ch == INT_0) {
+ return _parseNumber2(true, startPtr);
+ }
+ int intLen = 1; // already got one
+
+ // First let's get the obligatory integer part:
+ int_loop:
+ while (true) {
+ if (ptr >= inputLen) {
+ return _parseNumber2(true, startPtr);
+ }
+ ch = (int) _inputBuffer[ptr++];
+ if (ch < INT_0 || ch > INT_9) {
+ break int_loop;
+ }
+ ++intLen;
+ }
+
+ if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
+ _inputPtr = ptr;
+ return _parseFloat(ch, startPtr, ptr, true, intLen);
+ }
+ --ptr;
+ _inputPtr = ptr;
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(ch);
+ }
+ int len = ptr-startPtr;
+ _textBuffer.resetWithShared(_inputBuffer, startPtr, len);
+ return resetInt(true, intLen);
+ }
+
+ /**
+ * Method called to parse a number, when the primary parse
+ * method has failed to parse it, due to it being split on
+ * buffer boundary. As a result code is very similar, except
+ * that it has to explicitly copy contents to the text buffer
+ * instead of just sharing the main input buffer.
+ */
+ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOException
+ {
+ _inputPtr = neg ? (startPtr+1) : startPtr;
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+ int outPtr = 0;
+
+ // Need to prepend sign?
+ if (neg) {
+ outBuf[outPtr++] = '-';
+ }
+
+ // This is the place to do leading-zero check(s) too:
+ int intLen = 0;
+ char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : getNextChar("No digit following minus sign");
+ if (c == '0') {
+ c = _verifyNoLeadingZeroes();
+ }
+ boolean eof = false;
+
+ // Ok, first the obligatory integer part:
+ int_loop:
+ while (c >= '0' && c <= '9') {
+ ++intLen;
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = c;
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ // EOF is legal for main level int values
+ c = CHAR_NULL;
+ eof = true;
+ break int_loop;
+ }
+ c = _inputBuffer[_inputPtr++];
+ }
+ // Also, integer part is not optional
+ if (intLen == 0) {
+ return _handleInvalidNumberStart(c, neg);
+ }
+
+ int fractLen = 0;
+ // And then see if we get other parts
+ if (c == '.') { // yes, fraction
+ outBuf[outPtr++] = c;
+
+ fract_loop:
+ while (true) {
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ eof = true;
+ break fract_loop;
+ }
+ c = _inputBuffer[_inputPtr++];
+ if (c < INT_0 || c > INT_9) {
+ break fract_loop;
+ }
+ ++fractLen;
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = c;
+ }
+ // must be followed by sequence of ints, one minimum
+ if (fractLen == 0) {
+ reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
+ }
+ }
+
+ int expLen = 0;
+ if (c == 'e' || c == 'E') { // exponent?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = c;
+ // Not optional, can require that we get one more char
+ c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
+ : getNextChar("expected a digit for number exponent");
+ // Sign indicator?
+ if (c == '-' || c == '+') {
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = c;
+ // Likewise, non optional:
+ c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
+ : getNextChar("expected a digit for number exponent");
+ }
+
+ exp_loop:
+ while (c <= INT_9 && c >= INT_0) {
+ ++expLen;
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = c;
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ eof = true;
+ break exp_loop;
+ }
+ c = _inputBuffer[_inputPtr++];
+ }
+ // must be followed by sequence of ints, one minimum
+ if (expLen == 0) {
+ reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
+ }
+ }
+
+ // Ok; unless we hit end-of-input, need to push last char read back
+ if (!eof) {
+ --_inputPtr;
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(c);
+ }
+ }
+ _textBuffer.setCurrentLength(outPtr);
+ // And there we have it!
+ return reset(neg, intLen, fractLen, expLen);
+ }
+
+ /**
+ * Method called when we have seen one zero, and want to ensure
+ * it is not followed by another
+ */
+ private final char _verifyNoLeadingZeroes() throws IOException
+ {
+ // Fast case first:
+ if (_inputPtr < _inputEnd) {
+ char ch = _inputBuffer[_inputPtr];
+ // if not followed by a number (probably '.'); return zero as is, to be included
+ if (ch < '0' || ch > '9') {
+ return '0';
+ }
+ }
+ // and offline the less common case
+ return _verifyNLZ2();
+ }
+
+ private char _verifyNLZ2() throws IOException
+ {
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ return '0';
+ }
+ char ch = _inputBuffer[_inputPtr];
+ if (ch < '0' || ch > '9') {
+ return '0';
+ }
+ if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) {
+ reportInvalidNumber("Leading zeroes not allowed");
+ }
+ // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
+ ++_inputPtr; // Leading zero to be skipped
+ if (ch == INT_0) {
+ while (_inputPtr < _inputEnd || loadMore()) {
+ ch = _inputBuffer[_inputPtr];
+ if (ch < '0' || ch > '9') { // followed by non-number; retain one zero
+ return '0';
+ }
+ ++_inputPtr; // skip previous zero
+ if (ch != '0') { // followed by other number; return
+ break;
+ }
+ }
+ }
+ return ch;
+ }
+
+ /**
+ * Method called if expected numeric value (due to leading sign) does not
+ * look like a number
+ */
+ protected JsonToken _handleInvalidNumberStart(int ch, boolean negative) throws IOException
+ {
+ if (ch == 'I') {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) { _reportInvalidEOFInValue(); }
+ }
+ ch = _inputBuffer[_inputPtr++];
+ if (ch == 'N') {
+ String match = negative ? "-INF" :"+INF";
+ _matchToken(match, 3);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ }
+ _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ } else if (ch == 'n') {
+ String match = negative ? "-Infinity" :"+Infinity";
+ _matchToken(match, 3);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN(match, negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ }
+ _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ }
+ }
+ reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
+ return null;
+ }
+
+ /**
+ * Method called to ensure that a root-value is followed by a space
+ * token.
+ *
+ * NOTE: caller MUST ensure there is at least one character available;
+ * and that input pointer is AT given char (not past)
+ */
+ private final void _verifyRootSpace(int ch) throws IOException
+ {
+ // caller had pushed it back, before calling; reset
+ ++_inputPtr;
+ switch (ch) {
+ case ' ':
+ case '\t':
+ return;
+ case '\r':
+ _skipCR();
+ return;
+ case '\n':
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ return;
+ }
+ _reportMissingRootWS(ch);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, secondary parsing
+ /**********************************************************
+ */
+
+ protected final String _parseName() throws IOException
+ {
+ // First: let's try to see if we have a simple name: one that does
+ // not cross input buffer boundary, and does not contain escape sequences.
+ int ptr = _inputPtr;
+ int hash = _hashSeed;
+ final int[] codes = _icLatin1;
+
+ while (ptr < _inputEnd) {
+ int ch = _inputBuffer[ptr];
+ if (ch < codes.length && codes[ch] != 0) {
+ if (ch == '"') {
+ int start = _inputPtr;
+ _inputPtr = ptr+1; // to skip the quote
+ return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
+ }
+ break;
+ }
+ hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
+ ++ptr;
+ }
+ int start = _inputPtr;
+ _inputPtr = ptr;
+ return _parseName2(start, hash, INT_QUOTE);
+ }
+
+ private String _parseName2(int startPtr, int hash, int endChar) throws IOException
+ {
+ _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
+
+ /* Output pointers; calls will also ensure that the buffer is
+ * not shared and has room for at least one more char.
+ */
+ char[] outBuf = _textBuffer.getCurrentSegment();
+ int outPtr = _textBuffer.getCurrentSegmentSize();
+
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(": was expecting closing '"+((char) endChar)+"' for name");
+ }
+ }
+ char c = _inputBuffer[_inputPtr++];
+ int i = (int) c;
+ if (i <= INT_BACKSLASH) {
+ if (i == INT_BACKSLASH) {
+ /* Although chars outside of BMP are to be escaped as
+ * an UTF-16 surrogate pair, does that affect decoding?
+ * For now let's assume it does not.
+ */
+ c = _decodeEscaped();
+ } else if (i <= endChar) {
+ if (i == endChar) {
+ break;
+ }
+ if (i < INT_SPACE) {
+ _throwUnquotedSpace(i, "name");
+ }
+ }
+ }
+ hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + c;
+ // Ok, let's add char to output:
+ outBuf[outPtr++] = c;
+
+ // Need more room?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ }
+ _textBuffer.setCurrentLength(outPtr);
+ {
+ TextBuffer tb = _textBuffer;
+ char[] buf = tb.getTextBuffer();
+ int start = tb.getTextOffset();
+ int len = tb.size();
+ return _symbols.findSymbol(buf, start, len, hash);
+ }
+ }
+
+ /**
+ * Method called when we see non-white space character other
+ * than double quote, when expecting a field name.
+ * In standard mode will just throw an expection; but
+ * in non-standard modes may be able to parse name.
+ */
+ protected String _handleOddName(int i) throws IOException
+ {
+ // [JACKSON-173]: allow single quotes
+ if (i == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+ return _parseAposName();
+ }
+ // [JACKSON-69]: allow unquoted names if feature enabled:
+ if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) {
+ _reportUnexpectedChar(i, "was expecting double-quote to start field name");
+ }
+ final int[] codes = CharTypes.getInputCodeLatin1JsNames();
+ final int maxCode = codes.length;
+
+ // Also: first char must be a valid name char, but NOT be number
+ boolean firstOk;
+
+ if (i < maxCode) { // identifier, or a number ([Issue#102])
+ firstOk = (codes[i] == 0);
+ } else {
+ firstOk = Character.isJavaIdentifierPart((char) i);
+ }
+ if (!firstOk) {
+ _reportUnexpectedChar(i, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
+ }
+ int ptr = _inputPtr;
+ int hash = _hashSeed;
+ final int inputLen = _inputEnd;
+
+ if (ptr < inputLen) {
+ do {
+ int ch = _inputBuffer[ptr];
+ if (ch < maxCode) {
+ if (codes[ch] != 0) {
+ int start = _inputPtr-1; // -1 to bring back first char
+ _inputPtr = ptr;
+ return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
+ }
+ } else if (!Character.isJavaIdentifierPart((char) ch)) {
+ int start = _inputPtr-1; // -1 to bring back first char
+ _inputPtr = ptr;
+ return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
+ }
+ hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
+ ++ptr;
+ } while (ptr < inputLen);
+ }
+ int start = _inputPtr-1;
+ _inputPtr = ptr;
+ return _handleOddName2(start, hash, codes);
+ }
+
+ protected String _parseAposName() throws IOException
+ {
+ // Note: mostly copy of_parseFieldName
+ int ptr = _inputPtr;
+ int hash = _hashSeed;
+ final int inputLen = _inputEnd;
+
+ if (ptr < inputLen) {
+ final int[] codes = _icLatin1;
+ final int maxCode = codes.length;
+
+ do {
+ int ch = _inputBuffer[ptr];
+ if (ch == '\'') {
+ int start = _inputPtr;
+ _inputPtr = ptr+1; // to skip the quote
+ return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
+ }
+ if (ch < maxCode && codes[ch] != 0) {
+ break;
+ }
+ hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
+ ++ptr;
+ } while (ptr < inputLen);
+ }
+
+ int start = _inputPtr;
+ _inputPtr = ptr;
+
+ return _parseName2(start, hash, '\'');
+ }
+
+ /**
+ * Method for handling cases where first non-space character
+ * of an expected value token is not legal for standard JSON content.
+ */
+ protected JsonToken _handleOddValue(int i) throws IOException
+ {
+ // Most likely an error, unless we are to allow single-quote-strings
+ switch (i) {
+ case '\'':
+ /* [JACKSON-173]: allow single quotes. Unlike with regular
+ * Strings, we'll eagerly parse contents; this so that there's
+ * no need to store information on quote char used.
+ *
+ * Also, no separation to fast/slow parsing; we'll just do
+ * one regular (~= slowish) parsing, to keep code simple
+ */
+ if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+ return _handleApos();
+ }
+ break;
+ case 'N':
+ _matchToken("NaN", 1);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN("NaN", Double.NaN);
+ }
+ _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ break;
+ case 'I':
+ _matchToken("Infinity", 1);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
+ }
+ _reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ break;
+ case '+': // note: '-' is taken as number
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOFInValue();
+ }
+ }
+ return _handleInvalidNumberStart(_inputBuffer[_inputPtr++], false);
+ }
+ // [Issue#77] Try to decode most likely token
+ if (Character.isJavaIdentifierStart(i)) {
+ _reportInvalidToken(""+((char) i), "('true', 'false' or 'null')");
+ }
+ // but if it doesn't look like a token:
+ _reportUnexpectedChar(i, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
+ return null;
+ }
+
+ protected JsonToken _handleApos() throws IOException
+ {
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+ int outPtr = _textBuffer.getCurrentSegmentSize();
+
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(": was expecting closing quote for a string value");
+ }
+ }
+ char c = _inputBuffer[_inputPtr++];
+ int i = (int) c;
+ if (i <= '\\') {
+ if (i == '\\') {
+ /* Although chars outside of BMP are to be escaped as
+ * an UTF-16 surrogate pair, does that affect decoding?
+ * For now let's assume it does not.
+ */
+ c = _decodeEscaped();
+ } else if (i <= '\'') {
+ if (i == '\'') {
+ break;
+ }
+ if (i < INT_SPACE) {
+ _throwUnquotedSpace(i, "string value");
+ }
+ }
+ }
+ // Need more room?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ // Ok, let's add char to output:
+ outBuf[outPtr++] = c;
+ }
+ _textBuffer.setCurrentLength(outPtr);
+ return JsonToken.VALUE_STRING;
+ }
+
+ private String _handleOddName2(int startPtr, int hash, int[] codes) throws IOException
+ {
+ _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
+ char[] outBuf = _textBuffer.getCurrentSegment();
+ int outPtr = _textBuffer.getCurrentSegmentSize();
+ final int maxCode = codes.length;
+
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) { // acceptable for now (will error out later)
+ break;
+ }
+ }
+ char c = _inputBuffer[_inputPtr];
+ int i = (int) c;
+ if (i <= maxCode) {
+ if (codes[i] != 0) {
+ break;
+ }
+ } else if (!Character.isJavaIdentifierPart(c)) {
+ break;
+ }
+ ++_inputPtr;
+ hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + i;
+ // Ok, let's add char to output:
+ outBuf[outPtr++] = c;
+
+ // Need more room?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ }
+ _textBuffer.setCurrentLength(outPtr);
+ {
+ TextBuffer tb = _textBuffer;
+ char[] buf = tb.getTextBuffer();
+ int start = tb.getTextOffset();
+ int len = tb.size();
+
+ return _symbols.findSymbol(buf, start, len, hash);
+ }
+ }
+
+ @Override
+ protected final void _finishString() throws IOException
+ {
+ /* First: let's try to see if we have simple String value: one
+ * that does not cross input buffer boundary, and does not
+ * contain escape sequences.
+ */
+ int ptr = _inputPtr;
+ final int inputLen = _inputEnd;
+
+ if (ptr < inputLen) {
+ final int[] codes = _icLatin1;
+ final int maxCode = codes.length;
+
+ do {
+ int ch = _inputBuffer[ptr];
+ if (ch < maxCode && codes[ch] != 0) {
+ if (ch == '"') {
+ _textBuffer.resetWithShared(_inputBuffer, _inputPtr, (ptr-_inputPtr));
+ _inputPtr = ptr+1;
+ // Yes, we got it all
+ return;
+ }
+ break;
+ }
+ ++ptr;
+ } while (ptr < inputLen);
+ }
+
+ /* Either ran out of input, or bumped into an escape
+ * sequence...
+ */
+ _textBuffer.resetWithCopy(_inputBuffer, _inputPtr, (ptr-_inputPtr));
+ _inputPtr = ptr;
+ _finishString2();
+ }
+
+ protected void _finishString2() throws IOException
+ {
+ char[] outBuf = _textBuffer.getCurrentSegment();
+ int outPtr = _textBuffer.getCurrentSegmentSize();
+ final int[] codes = _icLatin1;
+ final int maxCode = codes.length;
+
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(": was expecting closing quote for a string value");
+ }
+ }
+ char c = _inputBuffer[_inputPtr++];
+ int i = (int) c;
+ if (i < maxCode && codes[i] != 0) {
+ if (i == INT_QUOTE) {
+ break;
+ } else if (i == INT_BACKSLASH) {
+ /* Although chars outside of BMP are to be escaped as
+ * an UTF-16 surrogate pair, does that affect decoding?
+ * For now let's assume it does not.
+ */
+ c = _decodeEscaped();
+ } else if (i < INT_SPACE) {
+ _throwUnquotedSpace(i, "string value");
+ } // anything else?
+ }
+ // Need more room?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ // Ok, let's add char to output:
+ outBuf[outPtr++] = c;
+ }
+ _textBuffer.setCurrentLength(outPtr);
+ }
+
+ /**
+ * Method called to skim through rest of unparsed String value,
+ * if it is not needed. This can be done bit faster if contents
+ * need not be stored for future access.
+ */
+ protected final void _skipString() throws IOException
+ {
+ _tokenIncomplete = false;
+
+ int inPtr = _inputPtr;
+ int inLen = _inputEnd;
+ char[] inBuf = _inputBuffer;
+
+ while (true) {
+ if (inPtr >= inLen) {
+ _inputPtr = inPtr;
+ if (!loadMore()) {
+ _reportInvalidEOF(": was expecting closing quote for a string value");
+ }
+ inPtr = _inputPtr;
+ inLen = _inputEnd;
+ }
+ char c = inBuf[inPtr++];
+ int i = (int) c;
+ if (i <= INT_BACKSLASH) {
+ if (i == INT_BACKSLASH) {
+ /* Although chars outside of BMP are to be escaped as
+ * an UTF-16 surrogate pair, does that affect decoding?
+ * For now let's assume it does not.
+ */
+ _inputPtr = inPtr;
+ c = _decodeEscaped();
+ inPtr = _inputPtr;
+ inLen = _inputEnd;
+ } else if (i <= INT_QUOTE) {
+ if (i == INT_QUOTE) {
+ _inputPtr = inPtr;
+ break;
+ }
+ if (i < INT_SPACE) {
+ _inputPtr = inPtr;
+ _throwUnquotedSpace(i, "string value");
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, other parsing
+ /**********************************************************
+ */
+
+ /**
+ * We actually need to check the character value here
+ * (to see if we have \n following \r).
+ */
+ protected final void _skipCR() throws IOException {
+ if (_inputPtr < _inputEnd || loadMore()) {
+ if (_inputBuffer[_inputPtr] == '\n') {
+ ++_inputPtr;
+ }
+ }
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ }
+
+ private final int _skipColon() throws IOException
+ {
+ if ((_inputPtr + 4) >= _inputEnd) {
+ return _skipColon2(false);
+ }
+ char c = _inputBuffer[_inputPtr];
+ if (c == ':') { // common case, no leading space
+ int i = _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) { // nor trailing
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ }
+ return _skipColon2(true); // true -> skipped colon
+ }
+ if (c == ' ' || c == '\t') {
+ c = _inputBuffer[++_inputPtr];
+ }
+ if (c == ':') {
+ int i = _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ }
+ return _skipColon2(true);
+ }
+ return _skipColon2(false);
+ }
+
+ private final int _skipColon2(boolean gotColon) throws IOException
+ {
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ int i = (int) _inputBuffer[_inputPtr++];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH) {
+ _skipComment();
+ continue;
+ }
+ if (i == INT_HASH) {
+ if (_skipYAMLComment()) {
+ continue;
+ }
+ }
+ if (gotColon) {
+ return i;
+ }
+ if (i != INT_COLON) {
+ if (i < INT_SPACE) {
+ _throwInvalidSpace(i);
+ }
+ _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
+ }
+ gotColon = true;
+ continue;
+ }
+ if (i < INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ }
+
+ // Variant called when we know there's at least 4 more bytes available
+ private final int _skipColonFast(int ptr) throws IOException
+ {
+ int i = (int) _inputBuffer[ptr++];
+ if (i == INT_COLON) { // common case, no leading space
+ i = _inputBuffer[ptr++];
+ if (i > INT_SPACE) { // nor trailing
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ } else if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ }
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(true); // true -> skipped colon
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = _inputBuffer[ptr++];
+ }
+ boolean gotColon = (i == INT_COLON);
+ if (gotColon) {
+ i = _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ } else if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ }
+ }
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(gotColon);
+ }
+
+ // Primary loop: no reloading, comment handling
+ private final int _skipComma(int i) throws IOException
+ {
+ if (i != INT_COMMA) {
+ _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+ }
+ while (_inputPtr < _inputEnd) {
+ i = (int) _inputBuffer[_inputPtr++];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ --_inputPtr;
+ return _skipAfterComma2();
+ }
+ return i;
+ }
+ if (i < INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ return _skipAfterComma2();
+ }
+
+ private final int _skipAfterComma2() throws IOException
+ {
+ while (_inputPtr < _inputEnd || loadMore()) {
+ int i = (int) _inputBuffer[_inputPtr++];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH) {
+ _skipComment();
+ continue;
+ }
+ if (i == INT_HASH) {
+ if (_skipYAMLComment()) {
+ continue;
+ }
+ }
+ return i;
+ }
+ if (i < INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
+ }
+
+ private final int _skipWSOrEnd() throws IOException
+ {
+ // Let's handle first character separately since it is likely that
+ // it is either non-whitespace; or we have longer run of white space
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ return _eofAsNextChar();
+ }
+ }
+ int i = _inputBuffer[_inputPtr++];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ --_inputPtr;
+ return _skipWSOrEnd2();
+ }
+ return i;
+ }
+ if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+
+ while (_inputPtr < _inputEnd) {
+ i = (int) _inputBuffer[_inputPtr++];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ --_inputPtr;
+ return _skipWSOrEnd2();
+ }
+ return i;
+ }
+ if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ return _skipWSOrEnd2();
+ }
+
+ private int _skipWSOrEnd2() throws IOException
+ {
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) { // We ran out of input...
+ return _eofAsNextChar();
+ }
+ }
+ int i = (int) _inputBuffer[_inputPtr++];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH) {
+ _skipComment();
+ continue;
+ }
+ if (i == INT_HASH) {
+ if (_skipYAMLComment()) {
+ continue;
+ }
+ }
+ return i;
+ } else if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ }
+
+ private void _skipComment() throws IOException
+ {
+ if (!isEnabled(Feature.ALLOW_COMMENTS)) {
+ _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
+ }
+ // First: check which comment (if either) it is:
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ _reportInvalidEOF(" in a comment");
+ }
+ char c = _inputBuffer[_inputPtr++];
+ if (c == '/') {
+ _skipLine();
+ } else if (c == '*') {
+ _skipCComment();
+ } else {
+ _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment");
+ }
+ }
+
+ private void _skipCComment() throws IOException
+ {
+ // Ok: need the matching '*/'
+ while ((_inputPtr < _inputEnd) || loadMore()) {
+ int i = (int) _inputBuffer[_inputPtr++];
+ if (i <= '*') {
+ if (i == '*') { // end?
+ if ((_inputPtr >= _inputEnd) && !loadMore()) {
+ break;
+ }
+ if (_inputBuffer[_inputPtr] == INT_SLASH) {
+ ++_inputPtr;
+ return;
+ }
+ continue;
+ }
+ if (i < INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ }
+ _reportInvalidEOF(" in a comment");
+ }
+
+ private boolean _skipYAMLComment() throws IOException
+ {
+ if (!isEnabled(Feature.ALLOW_YAML_COMMENTS)) {
+ return false;
+ }
+ _skipLine();
+ return true;
+ }
+
+ private void _skipLine() throws IOException
+ {
+ // Ok: need to find EOF or linefeed
+ while ((_inputPtr < _inputEnd) || loadMore()) {
+ int i = (int) _inputBuffer[_inputPtr++];
+ if (i < INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ break;
+ } else if (i == INT_CR) {
+ _skipCR();
+ break;
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected char _decodeEscaped() throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in character escape sequence");
+ }
+ }
+ char c = _inputBuffer[_inputPtr++];
+
+ switch ((int) c) {
+ // First, ones that are mapped
+ case 'b':
+ return '\b';
+ case 't':
+ return '\t';
+ case 'n':
+ return '\n';
+ case 'f':
+ return '\f';
+ case 'r':
+ return '\r';
+
+ // And these are to be returned as they are
+ case '"':
+ case '/':
+ case '\\':
+ return c;
+
+ case 'u': // and finally hex-escaped
+ break;
+
+ default:
+ return _handleUnrecognizedCharacterEscape(c);
+ }
+
+ // Ok, a hex escape. Need 4 characters
+ int value = 0;
+ for (int i = 0; i < 4; ++i) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in character escape sequence");
+ }
+ }
+ int ch = (int) _inputBuffer[_inputPtr++];
+ int digit = CharTypes.charToHex(ch);
+ if (digit < 0) {
+ _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence");
+ }
+ value = (value << 4) | digit;
+ }
+ return (char) value;
+ }
+
+ private final void _matchTrue() throws IOException {
+ int ptr = _inputPtr;
+ if ((ptr + 3) < _inputEnd) {
+ final char[] b = _inputBuffer;
+ if (b[ptr] == 'r' && b[++ptr] == 'u' && b[++ptr] == 'e') {
+ char c = b[++ptr];
+ if (c < '0' || c == ']' || c == '}') { // expected/allowed chars
+ _inputPtr = ptr;
+ return;
+ }
+ }
+ }
+ // buffer boundary, or problem, offline
+ _matchToken("true", 1);
+ }
+
+ private final void _matchFalse() throws IOException {
+ int ptr = _inputPtr;
+ if ((ptr + 4) < _inputEnd) {
+ final char[] b = _inputBuffer;
+ if (b[ptr] == 'a' && b[++ptr] == 'l' && b[++ptr] == 's' && b[++ptr] == 'e') {
+ char c = b[++ptr];
+ if (c < '0' || c == ']' || c == '}') { // expected/allowed chars
+ _inputPtr = ptr;
+ return;
+ }
+ }
+ }
+ // buffer boundary, or problem, offline
+ _matchToken("false", 1);
+ }
+
+ private final void _matchNull() throws IOException {
+ int ptr = _inputPtr;
+ if ((ptr + 3) < _inputEnd) {
+ final char[] b = _inputBuffer;
+ if (b[ptr] == 'u' && b[++ptr] == 'l' && b[++ptr] == 'l') {
+ char c = b[++ptr];
+ if (c < '0' || c == ']' || c == '}') { // expected/allowed chars
+ _inputPtr = ptr;
+ return;
+ }
+ }
+ }
+ // buffer boundary, or problem, offline
+ _matchToken("null", 1);
+ }
+
+ /**
+ * Helper method for checking whether input matches expected token
+ */
+ protected final void _matchToken(String matchStr, int i) throws IOException
+ {
+ final int len = matchStr.length();
+
+ do {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidToken(matchStr.substring(0, i));
+ }
+ }
+ if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
+ _reportInvalidToken(matchStr.substring(0, i));
+ }
+ ++_inputPtr;
+ } while (++i < len);
+
+ // but let's also ensure we either get EOF, or non-alphanum char...
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ return;
+ }
+ }
+ char c = _inputBuffer[_inputPtr];
+ if (c < '0' || c == ']' || c == '}') { // expected/allowed chars
+ return;
+ }
+ // if Java letter, it's a problem tho
+ if (Character.isJavaIdentifierPart(c)) {
+ _reportInvalidToken(matchStr.substring(0, i));
+ }
+ return;
+ }
+
+ /*
+ /**********************************************************
+ /* Binary access
+ /**********************************************************
+ */
+
+ /**
+ * Efficient handling for incremental parsing of base64-encoded
+ * textual content.
+ */
+ @SuppressWarnings("resource")
+ protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException
+ {
+ ByteArrayBuilder builder = _getByteArrayBuilder();
+
+ //main_loop:
+ while (true) {
+ // first, we'll skip preceding white space, if any
+ char ch;
+ do {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ } while (ch <= INT_SPACE);
+ int bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ if (ch == '"') { // reached the end, fair and square?
+ return builder.toByteArray();
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 0);
+ if (bits < 0) { // white space to skip
+ continue;
+ }
+ }
+ int decodedData = bits;
+
+ // then second base64 char; can't get padding yet, nor ws
+
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ bits = _decodeBase64Escape(b64variant, ch, 1);
+ }
+ decodedData = (decodedData << 6) | bits;
+
+ // third base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ bits = b64variant.decodeBase64Char(ch);
+
+ // First branch: can get padding (-> 1 byte)
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 4;
+ builder.append(decodedData);
+ return builder.toByteArray();
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 2);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ // Ok, must get more padding chars, then
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ if (!b64variant.usesPaddingChar(ch)) {
+ throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
+ }
+ // Got 12 bits, only need 8, need to shift
+ decodedData >>= 4;
+ builder.append(decodedData);
+ continue;
+ }
+ // otherwise we got escaped other char, to be processed below
+ }
+ // Nope, 2 or 3 bytes
+ decodedData = (decodedData << 6) | bits;
+ // fourth and last base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++];
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 2;
+ builder.appendTwoBytes(decodedData);
+ return builder.toByteArray();
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 3);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ // With padding we only get 2 bytes; but we have
+ // to shift it a bit so it is identical to triplet
+ // case with partial output.
+ // 3 chars gives 3x6 == 18 bits, of which 2 are
+ // dummies, need to discard:
+ decodedData >>= 2;
+ builder.appendTwoBytes(decodedData);
+ continue;
+ }
+ // otherwise we got escaped other char, to be processed below
+ }
+ // otherwise, our triplet is now complete
+ decodedData = (decodedData << 6) | bits;
+ builder.appendThreeBytes(decodedData);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, location updating (refactored in 2.7)
+ /**********************************************************
+ */
+
+ @Override
+ public JsonLocation getTokenLocation()
+ {
+ final Object src = _ioContext.getSourceReference();
+ if (_currToken == JsonToken.FIELD_NAME) {
+ long total = _currInputProcessed + (_nameStartOffset-1);
+ return new JsonLocation(src,
+ -1L, total, _nameStartRow, _nameStartCol);
+ }
+ return new JsonLocation(src,
+ -1L, _tokenInputTotal-1, _tokenInputRow, _tokenInputCol);
+ }
+
+ @Override
+ public JsonLocation getCurrentLocation() {
+ int col = _inputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_ioContext.getSourceReference(),
+ -1L, _currInputProcessed + _inputPtr,
+ _currInputRow, col);
+ }
+
+ // @since 2.7
+ private final void _updateLocation()
+ {
+ int ptr = _inputPtr;
+ _tokenInputTotal = _currInputProcessed + ptr;
+ _tokenInputRow = _currInputRow;
+ _tokenInputCol = ptr - _currInputRowStart;
+ }
+
+ // @since 2.7
+ private final void _updateNameLocation()
+ {
+ int ptr = _inputPtr;
+ _nameStartOffset = ptr;
+ _nameStartRow = _currInputRow;
+ _nameStartCol = ptr - _currInputRowStart;
+ }
+
+ /*
+ /**********************************************************
+ /* Error reporting
+ /**********************************************************
+ */
+
+ protected void _reportInvalidToken(String matchedPart) throws IOException {
+ _reportInvalidToken(matchedPart, "'null', 'true', 'false' or NaN");
+ }
+
+ protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
+ {
+ StringBuilder sb = new StringBuilder(matchedPart);
+ /* Let's just try to find what appears to be the token, using
+ * regular Java identifier character rules. It's just a heuristic,
+ * nothing fancy here.
+ */
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ break;
+ }
+ }
+ char c = _inputBuffer[_inputPtr];
+ if (!Character.isJavaIdentifierPart(c)) {
+ break;
+ }
+ ++_inputPtr;
+ sb.append(c);
+ }
+ _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,1985 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.*;
+
+public class UTF8JsonGenerator
+ extends JsonGeneratorImpl
+{
+ private final static byte BYTE_u = (byte) 'u';
+
+ private final static byte BYTE_0 = (byte) '0';
+
+ private final static byte BYTE_LBRACKET = (byte) '[';
+ private final static byte BYTE_RBRACKET = (byte) ']';
+ private final static byte BYTE_LCURLY = (byte) '{';
+ private final static byte BYTE_RCURLY = (byte) '}';
+
+ private final static byte BYTE_BACKSLASH = (byte) '\\';
+ private final static byte BYTE_COMMA = (byte) ',';
+ private final static byte BYTE_COLON = (byte) ':';
+ private final static byte BYTE_QUOTE = (byte) '"';
+
+ // intermediate copies only made up to certain length...
+ private final static int MAX_BYTES_TO_BUFFER = 512;
+
+ private final static byte[] HEX_CHARS = CharTypes.copyHexBytes();
+
+ private final static byte[] NULL_BYTES = { 'n', 'u', 'l', 'l' };
+ private final static byte[] TRUE_BYTES = { 't', 'r', 'u', 'e' };
+ private final static byte[] FALSE_BYTES = { 'f', 'a', 'l', 's', 'e' };
+
+ /*
+ /**********************************************************
+ /* Output buffering
+ /**********************************************************
+ */
+
+ /**
+ * Underlying output stream used for writing JSON content.
+ */
+ final protected OutputStream _outputStream;
+
+ /**
+ * Intermediate buffer in which contents are buffered before
+ * being written using {@link #_outputStream}.
+ */
+ protected byte[] _outputBuffer;
+
+ /**
+ * Pointer to the position right beyond the last character to output
+ * (end marker; may be past the buffer)
+ */
+ protected int _outputTail;
+
+ /**
+ * End marker of the output buffer; one past the last valid position
+ * within the buffer.
+ */
+ protected final int _outputEnd;
+
+ /**
+ * Maximum number of
+ * Note: non-final since version 2.3.
+ */
+public class UTF8StreamJsonParser
+ extends ParserBase
+{
+ final static byte BYTE_LF = (byte) '\n';
+
+ // This is the main input-code lookup table, fetched eagerly
+ private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8();
+
+ // Latin1 encoding is not supported, but we do use 8-bit subset for
+ // pre-processing task, to simplify first pass, keep it fast.
+ protected final static int[] _icLatin1 = CharTypes.getInputCodeLatin1();
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Codec used for data binding when (if) requested; typically full
+ *
+ * If it is not, it also means that parser can NOT modify underlying
+ * buffer.
+ */
+ protected boolean _bufferRecyclable;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in,
+ ObjectCodec codec, ByteQuadsCanonicalizer sym,
+ byte[] inputBuffer, int start, int end,
+ boolean bufferRecyclable)
+ {
+ super(ctxt, features);
+ _inputStream = in;
+ _objectCodec = codec;
+ _symbols = sym;
+ _inputBuffer = inputBuffer;
+ _inputPtr = start;
+ _inputEnd = end;
+ _currInputRowStart = start;
+ // If we have offset, need to omit that from byte offset, so:
+ _currInputProcessed = -start;
+ _bufferRecyclable = bufferRecyclable;
+ }
+
+ @Override
+ public ObjectCodec getCodec() {
+ return _objectCodec;
+ }
+
+ @Override
+ public void setCodec(ObjectCodec c) {
+ _objectCodec = c;
+ }
+
+ /*
+ /**********************************************************
+ /* Overrides for life-cycle
+ /**********************************************************
+ */
+
+ @Override
+ public int releaseBuffered(OutputStream out) throws IOException
+ {
+ int count = _inputEnd - _inputPtr;
+ if (count < 1) {
+ return 0;
+ }
+ // let's just advance ptr to end
+ int origPtr = _inputPtr;
+ out.write(_inputBuffer, origPtr, count);
+ return count;
+ }
+
+ @Override
+ public Object getInputSource() {
+ return _inputStream;
+ }
+
+ /*
+ /**********************************************************
+ /* Overrides, low-level reading
+ /**********************************************************
+ */
+
+ @Override
+ protected final boolean loadMore() throws IOException
+ {
+ final int bufSize = _inputEnd;
+
+ _currInputProcessed += _inputEnd;
+ _currInputRowStart -= _inputEnd;
+
+ // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+ // this increase to avoid "moving" name-offset, resulting most likely
+ // in negative value, which is fine as combine value remains unchanged.
+ _nameStartOffset -= bufSize;
+
+ if (_inputStream != null) {
+ int space = _inputBuffer.length;
+ if (space == 0) { // only occurs when we've been closed
+ return false;
+ }
+
+ int count = _inputStream.read(_inputBuffer, 0, space);
+ if (count > 0) {
+ _inputPtr = 0;
+ _inputEnd = count;
+ return true;
+ }
+ // End of input
+ _closeInput();
+ // Should never return 0, so let's fail
+ if (count == 0) {
+ throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes");
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Helper method that will try to load at least specified number bytes in
+ * input buffer, possible moving existing data around if necessary
+ */
+ protected final boolean _loadToHaveAtLeast(int minAvailable) throws IOException
+ {
+ // No input stream, no leading (either we are closed, or have non-stream input source)
+ if (_inputStream == null) {
+ return false;
+ }
+ // Need to move remaining data in front?
+ int amount = _inputEnd - _inputPtr;
+ if (amount > 0 && _inputPtr > 0) {
+ final int ptr = _inputPtr;
+
+ _currInputProcessed += ptr;
+ _currInputRowStart -= ptr;
+ // 26-Nov-2015, tatu: Since name-offset requires it too, must offset
+ // (note: probably has little effect here but just in case)
+ _nameStartOffset -= ptr;
+
+ System.arraycopy(_inputBuffer, ptr, _inputBuffer, 0, amount);
+ _inputEnd = amount;
+ } else {
+ _inputEnd = 0;
+ }
+ _inputPtr = 0;
+ while (_inputEnd < minAvailable) {
+ int count = _inputStream.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd);
+ if (count < 1) {
+ // End of input
+ _closeInput();
+ // Should never return 0, so let's fail
+ if (count == 0) {
+ throw new IOException("InputStream.read() returned 0 characters when trying to read "+amount+" bytes");
+ }
+ return false;
+ }
+ _inputEnd += count;
+ }
+ return true;
+ }
+
+ @Override
+ protected void _closeInput() throws IOException
+ {
+ /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
+ * on the underlying InputStream, unless we "own" it, or auto-closing
+ * feature is enabled.
+ */
+ if (_inputStream != null) {
+ if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
+ _inputStream.close();
+ }
+ _inputStream = null;
+ }
+ }
+
+ /**
+ * Method called to release internal buffers owned by the base
+ * reader. This may be called along with {@link #_closeInput} (for
+ * example, when explicitly closing this reader instance), or
+ * separately (if need be).
+ */
+ @Override
+ protected void _releaseBuffers() throws IOException
+ {
+ super._releaseBuffers();
+ // Merge found symbols, if any:
+ _symbols.release();
+ if (_bufferRecyclable) {
+ byte[] buf = _inputBuffer;
+ if (buf != null) {
+ /* 21-Nov-2014, tatu: Let's not set it to null; this way should
+ * get slightly more meaningful error messages in case someone
+ * closes parser indirectly, without realizing.
+ */
+ _inputBuffer = ByteArrayBuilder.NO_BYTES;
+ _ioContext.releaseReadIOBuffer(buf);
+ }
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, data access
+ /**********************************************************
+ */
+
+ @Override
+ public String getText() throws IOException
+ {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ return _finishAndReturnString(); // only strings can be incomplete
+ }
+ return _textBuffer.contentsAsString();
+ }
+ return _getText2(_currToken);
+ }
+
+ // // // Let's override default impls for improved performance
+
+ // @since 2.1
+ @Override
+ public String getValueAsString() throws IOException
+ {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ return _finishAndReturnString(); // only strings can be incomplete
+ }
+ return _textBuffer.contentsAsString();
+ }
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return getCurrentName();
+ }
+ return super.getValueAsString(null);
+ }
+
+ // @since 2.1
+ @Override
+ public String getValueAsString(String defValue) throws IOException
+ {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ return _finishAndReturnString(); // only strings can be incomplete
+ }
+ return _textBuffer.contentsAsString();
+ }
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return getCurrentName();
+ }
+ return super.getValueAsString(defValue);
+ }
+
+ // since 2.6
+ @Override
+ public int getValueAsInt() throws IOException
+ {
+ JsonToken t = _currToken;
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+ // inlined 'getIntValue()'
+ if ((_numTypesValid & NR_INT) == 0) {
+ if (_numTypesValid == NR_UNKNOWN) {
+ return _parseIntValue();
+ }
+ if ((_numTypesValid & NR_INT) == 0) {
+ convertNumberToInt();
+ }
+ }
+ return _numberInt;
+ }
+ return super.getValueAsInt(0);
+ }
+
+ // since 2.6
+ @Override
+ public int getValueAsInt(int defValue) throws IOException
+ {
+ JsonToken t = _currToken;
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+ // inlined 'getIntValue()'
+ if ((_numTypesValid & NR_INT) == 0) {
+ if (_numTypesValid == NR_UNKNOWN) {
+ return _parseIntValue();
+ }
+ if ((_numTypesValid & NR_INT) == 0) {
+ convertNumberToInt();
+ }
+ }
+ return _numberInt;
+ }
+ return super.getValueAsInt(defValue);
+ }
+
+ protected final String _getText2(JsonToken t)
+ {
+ if (t == null) {
+ return null;
+ }
+ switch (t.id()) {
+ case ID_FIELD_NAME:
+ return _parsingContext.getCurrentName();
+
+ case ID_STRING:
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.contentsAsString();
+ default:
+ return t.asString();
+ }
+ }
+
+ @Override
+ public char[] getTextCharacters() throws IOException
+ {
+ if (_currToken != null) { // null only before/after document
+ switch (_currToken.id()) {
+
+ case ID_FIELD_NAME:
+ if (!_nameCopied) {
+ String name = _parsingContext.getCurrentName();
+ int nameLen = name.length();
+ if (_nameCopyBuffer == null) {
+ _nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
+ } else if (_nameCopyBuffer.length < nameLen) {
+ _nameCopyBuffer = new char[nameLen];
+ }
+ name.getChars(0, nameLen, _nameCopyBuffer, 0);
+ _nameCopied = true;
+ }
+ return _nameCopyBuffer;
+
+ case ID_STRING:
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.getTextBuffer();
+
+ default:
+ return _currToken.asCharArray();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int getTextLength() throws IOException
+ {
+ if (_currToken != null) { // null only before/after document
+ switch (_currToken.id()) {
+
+ case ID_FIELD_NAME:
+ return _parsingContext.getCurrentName().length();
+ case ID_STRING:
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.size();
+
+ default:
+ return _currToken.asCharArray().length;
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public int getTextOffset() throws IOException
+ {
+ // Most have offset of 0, only some may have other values:
+ if (_currToken != null) {
+ switch (_currToken.id()) {
+ case ID_FIELD_NAME:
+ return 0;
+ case ID_STRING:
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ _finishString(); // only strings can be incomplete
+ }
+ // fall through
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return _textBuffer.getTextOffset();
+ default:
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
+ {
+ if (_currToken != JsonToken.VALUE_STRING &&
+ (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
+ _reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
+ }
+ /* To ensure that we won't see inconsistent data, better clear up
+ * state...
+ */
+ if (_tokenIncomplete) {
+ try {
+ _binaryValue = _decodeBase64(b64variant);
+ } catch (IllegalArgumentException iae) {
+ throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
+ }
+ /* let's clear incomplete only now; allows for accessing other
+ * textual content in error cases
+ */
+ _tokenIncomplete = false;
+ } else { // may actually require conversion...
+ if (_binaryValue == null) {
+ @SuppressWarnings("resource")
+ ByteArrayBuilder builder = _getByteArrayBuilder();
+ _decodeBase64(getText(), builder, b64variant);
+ _binaryValue = builder.toByteArray();
+ }
+ }
+ return _binaryValue;
+ }
+
+ @Override
+ public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
+ {
+ // if we have already read the token, just use whatever we may have
+ if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
+ byte[] b = getBinaryValue(b64variant);
+ out.write(b);
+ return b.length;
+ }
+ // otherwise do "real" incremental parsing...
+ byte[] buf = _ioContext.allocBase64Buffer();
+ try {
+ return _readBinary(b64variant, out, buf);
+ } finally {
+ _ioContext.releaseBase64Buffer(buf);
+ }
+ }
+
+ protected int _readBinary(Base64Variant b64variant, OutputStream out,
+ byte[] buffer) throws IOException
+ {
+ int outputPtr = 0;
+ final int outputEnd = buffer.length - 3;
+ int outputCount = 0;
+
+ while (true) {
+ // first, we'll skip preceding white space, if any
+ int ch;
+ do {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ } while (ch <= INT_SPACE);
+ int bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) { // reached the end, fair and square?
+ if (ch == INT_QUOTE) {
+ break;
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 0);
+ if (bits < 0) { // white space to skip
+ continue;
+ }
+ }
+
+ // enough room? If not, flush
+ if (outputPtr > outputEnd) {
+ outputCount += outputPtr;
+ out.write(buffer, 0, outputPtr);
+ outputPtr = 0;
+ }
+
+ int decodedData = bits;
+
+ // then second base64 char; can't get padding yet, nor ws
+
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ bits = _decodeBase64Escape(b64variant, ch, 1);
+ }
+ decodedData = (decodedData << 6) | bits;
+
+ // third base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ bits = b64variant.decodeBase64Char(ch);
+
+ // First branch: can get padding (-> 1 byte)
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 4;
+ buffer[outputPtr++] = (byte) decodedData;
+ break;
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 2);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ // Ok, must get padding
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ if (!b64variant.usesPaddingChar(ch)) {
+ throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
+ }
+ // Got 12 bits, only need 8, need to shift
+ decodedData >>= 4;
+ buffer[outputPtr++] = (byte) decodedData;
+ continue;
+ }
+ }
+ // Nope, 2 or 3 bytes
+ decodedData = (decodedData << 6) | bits;
+ // fourth and last base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 2;
+ buffer[outputPtr++] = (byte) (decodedData >> 8);
+ buffer[outputPtr++] = (byte) decodedData;
+ break;
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 3);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ /* With padding we only get 2 bytes; but we have
+ * to shift it a bit so it is identical to triplet
+ * case with partial output.
+ * 3 chars gives 3x6 == 18 bits, of which 2 are
+ * dummies, need to discard:
+ */
+ decodedData >>= 2;
+ buffer[outputPtr++] = (byte) (decodedData >> 8);
+ buffer[outputPtr++] = (byte) decodedData;
+ continue;
+ }
+ }
+ // otherwise, our triplet is now complete
+ decodedData = (decodedData << 6) | bits;
+ buffer[outputPtr++] = (byte) (decodedData >> 16);
+ buffer[outputPtr++] = (byte) (decodedData >> 8);
+ buffer[outputPtr++] = (byte) decodedData;
+ }
+ _tokenIncomplete = false;
+ if (outputPtr > 0) {
+ outputCount += outputPtr;
+ out.write(buffer, 0, outputPtr);
+ }
+ return outputCount;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, traversal, basic
+ /**********************************************************
+ */
+
+ /**
+ * @return Next token from the stream, if any found, or null
+ * to indicate end-of-input
+ */
+ @Override
+ public JsonToken nextToken() throws IOException
+ {
+ /* First: field names are special -- we will always tokenize
+ * (part of) value along with field name to simplify
+ * state handling. If so, can and need to use secondary token:
+ */
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return _nextAfterName();
+ }
+ // But if we didn't already have a name, and (partially?) decode number,
+ // need to ensure no numeric information is leaked
+ _numTypesValid = NR_UNKNOWN;
+ if (_tokenIncomplete) {
+ _skipString(); // only strings can be partial
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) { // end-of-input
+ // Close/release things like input source, symbol table and recyclable buffers
+ close();
+ return (_currToken = null);
+ }
+ // clear any data retained so far
+ _binaryValue = null;
+
+ // Closing scope?
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ return (_currToken = JsonToken.END_ARRAY);
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ return (_currToken = JsonToken.END_OBJECT);
+ }
+
+ // Nope: do we then expect a comma?
+ if (_parsingContext.expectComma()) {
+ if (i != INT_COMMA) {
+ _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+ }
+ i = _skipWS();
+ }
+
+ /* And should we now have a name? Always true for
+ * Object contexts, since the intermediate 'expect-value'
+ * state is never retained.
+ */
+ if (!_parsingContext.inObject()) {
+ _updateLocation();
+ return _nextTokenNotInObject(i);
+ }
+ // So first parse the field name itself:
+ _updateNameLocation();
+ String n = _parseName(i);
+ _parsingContext.setCurrentName(n);
+ _currToken = JsonToken.FIELD_NAME;
+
+ i = _skipColon();
+ _updateLocation();
+
+ // Ok: we must have a value... what is it? Strings are very common, check first:
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return _currToken;
+ }
+ JsonToken t;
+
+ switch (i) {
+ case '-':
+ t = _parseNegNumber();
+ break;
+
+ /* Should we have separate handling for plus? Although
+ * it is not allowed per se, it may be erroneously used,
+ * and could be indicate by a more specific error message.
+ */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ case 'f':
+ _matchToken("false", 1);
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchToken("null", 1);
+ t = JsonToken.VALUE_NULL;
+ break;
+ case 't':
+ _matchToken("true", 1);
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case '[':
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ t = JsonToken.START_OBJECT;
+ break;
+
+ default:
+ t = _handleUnexpectedValue(i);
+ }
+ _nextToken = t;
+ return _currToken;
+ }
+
+ private final JsonToken _nextTokenNotInObject(int i) throws IOException
+ {
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ return (_currToken = JsonToken.VALUE_STRING);
+ }
+ switch (i) {
+ case '[':
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ return (_currToken = JsonToken.START_ARRAY);
+ case '{':
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ return (_currToken = JsonToken.START_OBJECT);
+ case 't':
+ _matchToken("true", 1);
+ return (_currToken = JsonToken.VALUE_TRUE);
+ case 'f':
+ _matchToken("false", 1);
+ return (_currToken = JsonToken.VALUE_FALSE);
+ case 'n':
+ _matchToken("null", 1);
+ return (_currToken = JsonToken.VALUE_NULL);
+ case '-':
+ return (_currToken = _parseNegNumber());
+ /* Should we have separate handling for plus? Although
+ * it is not allowed per se, it may be erroneously used,
+ * and could be indicated by a more specific error message.
+ */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return (_currToken = _parsePosNumber(i));
+ }
+ return (_currToken = _handleUnexpectedValue(i));
+ }
+
+ private final JsonToken _nextAfterName()
+ {
+ _nameCopied = false; // need to invalidate if it was copied
+ JsonToken t = _nextToken;
+ _nextToken = null;
+
+ // !!! 16-Nov-2015, tatu: TODO: fix [databind#37], copy next location to current here
+
+ // Also: may need to start new context?
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return (_currToken = t);
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, traversal, nextXxxValue/nextFieldName
+ /**********************************************************
+ */
+
+ @Override
+ public boolean nextFieldName(SerializableString str) throws IOException
+ {
+ // // // Note: most of code below is copied from nextToken()
+ _numTypesValid = NR_UNKNOWN;
+ if (_currToken == JsonToken.FIELD_NAME) { // can't have name right after name
+ _nextAfterName();
+ return false;
+ }
+ if (_tokenIncomplete) {
+ _skipString();
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) { // end-of-input
+ close();
+ _currToken = null;
+ return false;
+ }
+ _binaryValue = null;
+
+ // Closing scope?
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_ARRAY;
+ return false;
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_OBJECT;
+ return false;
+ }
+
+ // Nope: do we then expect a comma?
+ if (_parsingContext.expectComma()) {
+ if (i != INT_COMMA) {
+ _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+ }
+ i = _skipWS();
+ }
+
+ if (!_parsingContext.inObject()) {
+ _updateLocation();
+ _nextTokenNotInObject(i);
+ return false;
+ }
+
+ // // // This part differs, name parsing
+ _updateNameLocation();
+ if (i == INT_QUOTE) {
+ // when doing literal match, must consider escaping:
+ byte[] nameBytes = str.asQuotedUTF8();
+ final int len = nameBytes.length;
+ // 22-May-2014, tatu: Actually, let's require 4 more bytes for faster skipping
+ // of colon that follows name
+ if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
+ // first check length match by
+ final int end = _inputPtr+len;
+ if (_inputBuffer[end] == INT_QUOTE) {
+ int offset = 0;
+ int ptr = _inputPtr;
+ while (true) {
+ if (ptr == end) { // yes, match!
+ _parsingContext.setCurrentName(str.getValue());
+ i = _skipColonFast(ptr+1);
+ _isNextTokenNameYes(i);
+ return true;
+ }
+ if (nameBytes[offset] != _inputBuffer[ptr]) {
+ break;
+ }
+ ++offset;
+ ++ptr;
+ }
+ }
+ }
+ }
+ return _isNextTokenNameMaybe(i, str);
+ }
+
+ @Override
+ public String nextFieldName() throws IOException
+ {
+ // // // Note: this is almost a verbatim copy of nextToken()
+
+ _numTypesValid = NR_UNKNOWN;
+ if (_currToken == JsonToken.FIELD_NAME) {
+ _nextAfterName();
+ return null;
+ }
+ if (_tokenIncomplete) {
+ _skipString();
+ }
+ int i = _skipWSOrEnd();
+ if (i < 0) {
+ close();
+ _currToken = null;
+ return null;
+ }
+ _binaryValue = null;
+
+ if (i == INT_RBRACKET) {
+ _updateLocation();
+ if (!_parsingContext.inArray()) {
+ _reportMismatchedEndMarker(i, '}');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_ARRAY;
+ return null;
+ }
+ if (i == INT_RCURLY) {
+ _updateLocation();
+ if (!_parsingContext.inObject()) {
+ _reportMismatchedEndMarker(i, ']');
+ }
+ _parsingContext = _parsingContext.clearAndGetParent();
+ _currToken = JsonToken.END_OBJECT;
+ return null;
+ }
+
+ // Nope: do we then expect a comma?
+ if (_parsingContext.expectComma()) {
+ if (i != INT_COMMA) {
+ _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
+ }
+ i = _skipWS();
+ }
+ if (!_parsingContext.inObject()) {
+ _updateLocation();
+ _nextTokenNotInObject(i);
+ return null;
+ }
+
+ _updateNameLocation();
+ final String nameStr = _parseName(i);
+ _parsingContext.setCurrentName(nameStr);
+ _currToken = JsonToken.FIELD_NAME;
+
+ i = _skipColon();
+ _updateLocation();
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return nameStr;
+ }
+ JsonToken t;
+ switch (i) {
+ case '-':
+ t = _parseNegNumber();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ case 'f':
+ _matchToken("false", 1);
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchToken("null", 1);
+ t = JsonToken.VALUE_NULL;
+ break;
+ case 't':
+ _matchToken("true", 1);
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case '[':
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ t = JsonToken.START_OBJECT;
+ break;
+
+ default:
+ t = _handleUnexpectedValue(i);
+ }
+ _nextToken = t;
+ return nameStr;
+ }
+
+ // Variant called when we know there's at least 4 more bytes available
+ private final int _skipColonFast(int ptr) throws IOException
+ {
+ int i = _inputBuffer[ptr++];
+ if (i == INT_COLON) { // common case, no leading space
+ i = _inputBuffer[ptr++];
+ if (i > INT_SPACE) { // nor trailing
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ } else if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ }
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(true); // true -> skipped colon
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = _inputBuffer[ptr++];
+ }
+ if (i == INT_COLON) {
+ i = _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ } else if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[ptr++];
+ if (i > INT_SPACE) {
+ if (i != INT_SLASH && i != INT_HASH) {
+ _inputPtr = ptr;
+ return i;
+ }
+ }
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(true);
+ }
+ _inputPtr = ptr-1;
+ return _skipColon2(false);
+ }
+
+ private final void _isNextTokenNameYes(int i) throws IOException
+ {
+ _currToken = JsonToken.FIELD_NAME;
+ _updateLocation();
+
+ switch (i) {
+ case '"':
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return;
+ case '[':
+ _nextToken = JsonToken.START_ARRAY;
+ return;
+ case '{':
+ _nextToken = JsonToken.START_OBJECT;
+ return;
+ case 't':
+ _matchToken("true", 1);
+ _nextToken = JsonToken.VALUE_TRUE;
+ return;
+ case 'f':
+ _matchToken("false", 1);
+ _nextToken = JsonToken.VALUE_FALSE;
+ return;
+ case 'n':
+ _matchToken("null", 1);
+ _nextToken = JsonToken.VALUE_NULL;
+ return;
+ case '-':
+ _nextToken = _parseNegNumber();
+ return;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ _nextToken = _parsePosNumber(i);
+ return;
+ }
+ _nextToken = _handleUnexpectedValue(i);
+ }
+
+ private final boolean _isNextTokenNameMaybe(int i, SerializableString str) throws IOException
+ {
+ // // // and this is back to standard nextToken()
+
+ String n = _parseName(i);
+ _parsingContext.setCurrentName(n);
+ final boolean match = n.equals(str.getValue());
+ _currToken = JsonToken.FIELD_NAME;
+ i = _skipColon();
+ _updateLocation();
+
+ // Ok: we must have a value... what is it? Strings are very common, check first:
+ if (i == INT_QUOTE) {
+ _tokenIncomplete = true;
+ _nextToken = JsonToken.VALUE_STRING;
+ return match;
+ }
+ JsonToken t;
+
+ switch (i) {
+ case '[':
+ t = JsonToken.START_ARRAY;
+ break;
+ case '{':
+ t = JsonToken.START_OBJECT;
+ break;
+ case 't':
+ _matchToken("true", 1);
+ t = JsonToken.VALUE_TRUE;
+ break;
+ case 'f':
+ _matchToken("false", 1);
+ t = JsonToken.VALUE_FALSE;
+ break;
+ case 'n':
+ _matchToken("null", 1);
+ t = JsonToken.VALUE_NULL;
+ break;
+ case '-':
+ t = _parseNegNumber();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ t = _parsePosNumber(i);
+ break;
+ default:
+ t = _handleUnexpectedValue(i);
+ }
+ _nextToken = t;
+ return match;
+ }
+
+ @Override
+ public String nextTextValue() throws IOException
+ {
+ // two distinct cases; either got name and we know next type, or 'other'
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_STRING) {
+ if (_tokenIncomplete) {
+ _tokenIncomplete = false;
+ return _finishAndReturnString();
+ }
+ return _textBuffer.contentsAsString();
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return null;
+ }
+ // !!! TODO: optimize this case as well
+ return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+ }
+
+ @Override
+ public int nextIntValue(int defaultValue) throws IOException
+ {
+ // two distinct cases; either got name and we know next type, or 'other'
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return getIntValue();
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return defaultValue;
+ }
+ // !!! TODO: optimize this case as well
+ return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+ }
+
+ @Override
+ public long nextLongValue(long defaultValue) throws IOException
+ {
+ // two distinct cases; either got name and we know next type, or 'other'
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_NUMBER_INT) {
+ return getLongValue();
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return defaultValue;
+ }
+ // !!! TODO: optimize this case as well
+ return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+ }
+
+ @Override
+ public Boolean nextBooleanValue() throws IOException
+ {
+ // two distinct cases; either got name and we know next type, or 'other'
+ if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
+ _nameCopied = false;
+ JsonToken t = _nextToken;
+ _nextToken = null;
+ _currToken = t;
+ if (t == JsonToken.VALUE_TRUE) {
+ return Boolean.TRUE;
+ }
+ if (t == JsonToken.VALUE_FALSE) {
+ return Boolean.FALSE;
+ }
+ if (t == JsonToken.START_ARRAY) {
+ _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
+ } else if (t == JsonToken.START_OBJECT) {
+ _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
+ }
+ return null;
+ }
+
+ JsonToken t = nextToken();
+ if (t == JsonToken.VALUE_TRUE) {
+ return Boolean.TRUE;
+ }
+ if (t == JsonToken.VALUE_FALSE) {
+ return Boolean.FALSE;
+ }
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, number parsing
+ /**********************************************************
+ */
+
+ /**
+ * Initial parsing method for number values. It needs to be able
+ * to parse enough input to be able to determine whether the
+ * value is to be considered a simple integer value, or a more
+ * generic decimal value: latter of which needs to be expressed
+ * as a floating point number. The basic rule is that if the number
+ * has no fractional or exponential part, it is an integer; otherwise
+ * a floating point number.
+ *
+ * Because much of input has to be processed in any case, no partial
+ * parsing is done: all input text will be stored for further
+ * processing. However, actual numeric value conversion will be
+ * deferred, since it is usually the most complicated and costliest
+ * part of processing.
+ */
+ protected JsonToken _parsePosNumber(int c) throws IOException
+ {
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+ // One special case: if first char is 0, must not be followed by a digit
+ if (c == INT_0) {
+ c = _verifyNoLeadingZeroes();
+ }
+ // Ok: we can first just add digit we saw first:
+ outBuf[0] = (char) c;
+ int intLen = 1;
+ int outPtr = 1;
+ // And then figure out how far we can read without further checks
+ // for either input or output
+ int end = _inputPtr + outBuf.length - 1; // 1 == outPtr
+ if (end > _inputEnd) {
+ end = _inputEnd;
+ }
+ // With this, we have a nice and tight loop:
+ while (true) {
+ if (_inputPtr >= end) { // split across boundary, offline
+ return _parseNumber2(outBuf, outPtr, false, intLen);
+ }
+ c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ if (c < INT_0 || c > INT_9) {
+ break;
+ }
+ ++intLen;
+ outBuf[outPtr++] = (char) c;
+ }
+ if (c == '.' || c == 'e' || c == 'E') {
+ return _parseFloat(outBuf, outPtr, c, false, intLen);
+ }
+ --_inputPtr; // to push back trailing char (comma etc)
+ _textBuffer.setCurrentLength(outPtr);
+ // As per #105, need separating space between root values; check here
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(c);
+ }
+ // And there we have it!
+ return resetInt(false, intLen);
+ }
+
+ protected JsonToken _parseNegNumber() throws IOException
+ {
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+ int outPtr = 0;
+
+ // Need to prepend sign?
+ outBuf[outPtr++] = '-';
+ // Must have something after sign too
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ // Note: must be followed by a digit
+ if (c < INT_0 || c > INT_9) {
+ return _handleInvalidNumberStart(c, true);
+ }
+
+ // One special case: if first char is 0, must not be followed by a digit
+ if (c == INT_0) {
+ c = _verifyNoLeadingZeroes();
+ }
+
+ // Ok: we can first just add digit we saw first:
+ outBuf[outPtr++] = (char) c;
+ int intLen = 1;
+
+ // And then figure out how far we can read without further checks
+ // for either input or output
+ int end = _inputPtr + outBuf.length - outPtr;
+ if (end > _inputEnd) {
+ end = _inputEnd;
+ }
+
+ // With this, we have a nice and tight loop:
+ while (true) {
+ if (_inputPtr >= end) {
+ // Long enough to be split across boundary, so:
+ return _parseNumber2(outBuf, outPtr, true, intLen);
+ }
+ c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ if (c < INT_0 || c > INT_9) {
+ break;
+ }
+ ++intLen;
+ outBuf[outPtr++] = (char) c;
+ }
+ if (c == '.' || c == 'e' || c == 'E') {
+ return _parseFloat(outBuf, outPtr, c, true, intLen);
+ }
+
+ --_inputPtr; // to push back trailing char (comma etc)
+ _textBuffer.setCurrentLength(outPtr);
+ // As per #105, need separating space between root values; check here
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(c);
+ }
+
+ // And there we have it!
+ return resetInt(true, intLen);
+ }
+
+ /**
+ * Method called to handle parsing when input is split across buffer boundary
+ * (or output is longer than segment used to store it)
+ */
+ private final JsonToken _parseNumber2(char[] outBuf, int outPtr, boolean negative,
+ int intPartLength) throws IOException
+ {
+ // Ok, parse the rest
+ while (true) {
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ _textBuffer.setCurrentLength(outPtr);
+ return resetInt(negative, intPartLength);
+ }
+ int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ if (c > INT_9 || c < INT_0) {
+ if (c == INT_PERIOD || c == INT_e || c == INT_E) {
+ return _parseFloat(outBuf, outPtr, c, negative, intPartLength);
+ }
+ break;
+ }
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = (char) c;
+ ++intPartLength;
+ }
+ --_inputPtr; // to push back trailing char (comma etc)
+ _textBuffer.setCurrentLength(outPtr);
+ // As per #105, need separating space between root values; check here
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(_inputBuffer[_inputPtr++] & 0xFF);
+ }
+
+ // And there we have it!
+ return resetInt(negative, intPartLength);
+
+ }
+
+ /**
+ * Method called when we have seen one zero, and want to ensure
+ * it is not followed by another
+ */
+ private final int _verifyNoLeadingZeroes() throws IOException
+ {
+ // Ok to have plain "0"
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ return INT_0;
+ }
+ int ch = _inputBuffer[_inputPtr] & 0xFF;
+ // if not followed by a number (probably '.'); return zero as is, to be included
+ if (ch < INT_0 || ch > INT_9) {
+ return INT_0;
+ }
+ // [JACKSON-358]: we may want to allow them, after all...
+ if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) {
+ reportInvalidNumber("Leading zeroes not allowed");
+ }
+ // if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
+ ++_inputPtr; // Leading zero to be skipped
+ if (ch == INT_0) {
+ while (_inputPtr < _inputEnd || loadMore()) {
+ ch = _inputBuffer[_inputPtr] & 0xFF;
+ if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
+ return INT_0;
+ }
+ ++_inputPtr; // skip previous zeroes
+ if (ch != INT_0) { // followed by other number; return
+ break;
+ }
+ }
+ }
+ return ch;
+ }
+
+ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
+ boolean negative, int integerPartLength) throws IOException
+ {
+ int fractLen = 0;
+ boolean eof = false;
+
+ // And then see if we get other parts
+ if (c == INT_PERIOD) { // yes, fraction
+ outBuf[outPtr++] = (char) c;
+
+ fract_loop:
+ while (true) {
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ eof = true;
+ break fract_loop;
+ }
+ c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ if (c < INT_0 || c > INT_9) {
+ break fract_loop;
+ }
+ ++fractLen;
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = (char) c;
+ }
+ // must be followed by sequence of ints, one minimum
+ if (fractLen == 0) {
+ reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
+ }
+ }
+
+ int expLen = 0;
+ if (c == INT_e || c == INT_E) { // exponent?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = (char) c;
+ // Not optional, can require that we get one more char
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ // Sign indicator?
+ if (c == '-' || c == '+') {
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = (char) c;
+ // Likewise, non optional:
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ }
+
+ exp_loop:
+ while (c <= INT_9 && c >= INT_0) {
+ ++expLen;
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ outBuf[outPtr++] = (char) c;
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ eof = true;
+ break exp_loop;
+ }
+ c = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ }
+ // must be followed by sequence of ints, one minimum
+ if (expLen == 0) {
+ reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
+ }
+ }
+
+ // Ok; unless we hit end-of-input, need to push last char read back
+ if (!eof) {
+ --_inputPtr;
+ // As per #105, need separating space between root values; check here
+ if (_parsingContext.inRoot()) {
+ _verifyRootSpace(c);
+ }
+ }
+ _textBuffer.setCurrentLength(outPtr);
+
+ // And there we have it!
+ return resetFloat(negative, integerPartLength, fractLen, expLen);
+ }
+
+ /**
+ * Method called to ensure that a root-value is followed by a space
+ * token.
+ *
+ * NOTE: caller MUST ensure there is at least one character available;
+ * and that input pointer is AT given char (not past)
+ */
+ private final void _verifyRootSpace(int ch) throws IOException
+ {
+ // caller had pushed it back, before calling; reset
+ ++_inputPtr;
+ // TODO? Handle UTF-8 char decoding for error reporting
+ switch (ch) {
+ case ' ':
+ case '\t':
+ return;
+ case '\r':
+ _skipCR();
+ return;
+ case '\n':
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ return;
+ }
+ _reportMissingRootWS(ch);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, secondary parsing
+ /**********************************************************
+ */
+
+ protected final String _parseName(int i) throws IOException
+ {
+ if (i != INT_QUOTE) {
+ return _handleOddName(i);
+ }
+ // First: can we optimize out bounds checks?
+ if ((_inputPtr + 13) > _inputEnd) { // Need up to 12 chars, plus one trailing (quote)
+ return slowParseName();
+ }
+
+ // If so, can also unroll loops nicely
+ /* 25-Nov-2008, tatu: This may seem weird, but here we do
+ * NOT want to worry about UTF-8 decoding. Rather, we'll
+ * assume that part is ok (if not it will get caught
+ * later on), and just handle quotes and backslashes here.
+ */
+ final byte[] input = _inputBuffer;
+ final int[] codes = _icLatin1;
+
+ int q = input[_inputPtr++] & 0xFF;
+
+ if (codes[q] == 0) {
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] == 0) {
+ q = (q << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] == 0) {
+ q = (q << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] == 0) {
+ q = (q << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] == 0) {
+ _quad1 = q;
+ return parseMediumName(i);
+ }
+ if (i == INT_QUOTE) { // 4 byte/char case or broken
+ return findName(q, 4);
+ }
+ return parseName(q, i, 4);
+ }
+ if (i == INT_QUOTE) { // 3 byte/char case or broken
+ return findName(q, 3);
+ }
+ return parseName(q, i, 3);
+ }
+ if (i == INT_QUOTE) { // 2 byte/char case or broken
+ return findName(q, 2);
+ }
+ return parseName(q, i, 2);
+ }
+ if (i == INT_QUOTE) { // one byte/char case or broken
+ return findName(q, 1);
+ }
+ return parseName(q, i, 1);
+ }
+ if (q == INT_QUOTE) { // special case, ""
+ return "";
+ }
+ return parseName(0, q, 0); // quoting or invalid char
+ }
+
+ protected final String parseMediumName(int q2) throws IOException
+ {
+ final byte[] input = _inputBuffer;
+ final int[] codes = _icLatin1;
+
+ // Ok, got 5 name bytes so far
+ int i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 5 bytes
+ return findName(_quad1, q2, 1);
+ }
+ return parseName(_quad1, q2, i, 1); // quoting or invalid char
+ }
+ q2 = (q2 << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 6 bytes
+ return findName(_quad1, q2, 2);
+ }
+ return parseName(_quad1, q2, i, 2);
+ }
+ q2 = (q2 << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 7 bytes
+ return findName(_quad1, q2, 3);
+ }
+ return parseName(_quad1, q2, i, 3);
+ }
+ q2 = (q2 << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 8 bytes
+ return findName(_quad1, q2, 4);
+ }
+ return parseName(_quad1, q2, i, 4);
+ }
+ return parseMediumName2(i, q2);
+ }
+
+ /**
+ * @since 2.6
+ */
+ protected final String parseMediumName2(int q3, final int q2) throws IOException
+ {
+ final byte[] input = _inputBuffer;
+ final int[] codes = _icLatin1;
+
+ // Got 9 name bytes so far
+ int i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 9 bytes
+ return findName(_quad1, q2, q3, 1);
+ }
+ return parseName(_quad1, q2, q3, i, 1);
+ }
+ q3 = (q3 << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 10 bytes
+ return findName(_quad1, q2, q3, 2);
+ }
+ return parseName(_quad1, q2, q3, i, 2);
+ }
+ q3 = (q3 << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 11 bytes
+ return findName(_quad1, q2, q3, 3);
+ }
+ return parseName(_quad1, q2, q3, i, 3);
+ }
+ q3 = (q3 << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) { // 12 bytes
+ return findName(_quad1, q2, q3, 4);
+ }
+ return parseName(_quad1, q2, q3, i, 4);
+ }
+ return parseLongName(i, q2, q3);
+ }
+
+ protected final String parseLongName(int q, final int q2, int q3) throws IOException
+ {
+ _quadBuffer[0] = _quad1;
+ _quadBuffer[1] = q2;
+ _quadBuffer[2] = q3;
+
+ // As explained above, will ignore UTF-8 encoding at this point
+ final byte[] input = _inputBuffer;
+ final int[] codes = _icLatin1;
+ int qlen = 3;
+
+ while ((_inputPtr + 4) <= _inputEnd) {
+ int i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) {
+ return findName(_quadBuffer, qlen, q, 1);
+ }
+ return parseEscapedName(_quadBuffer, qlen, q, i, 1);
+ }
+
+ q = (q << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) {
+ return findName(_quadBuffer, qlen, q, 2);
+ }
+ return parseEscapedName(_quadBuffer, qlen, q, i, 2);
+ }
+
+ q = (q << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) {
+ return findName(_quadBuffer, qlen, q, 3);
+ }
+ return parseEscapedName(_quadBuffer, qlen, q, i, 3);
+ }
+
+ q = (q << 8) | i;
+ i = input[_inputPtr++] & 0xFF;
+ if (codes[i] != 0) {
+ if (i == INT_QUOTE) {
+ return findName(_quadBuffer, qlen, q, 4);
+ }
+ return parseEscapedName(_quadBuffer, qlen, q, i, 4);
+ }
+
+ // Nope, no end in sight. Need to grow quad array etc
+ if (qlen >= _quadBuffer.length) {
+ _quadBuffer = growArrayBy(_quadBuffer, qlen);
+ }
+ _quadBuffer[qlen++] = q;
+ q = i;
+ }
+
+ /* Let's offline if we hit buffer boundary (otherwise would
+ * need to [try to] align input, which is bit complicated
+ * and may not always be possible)
+ */
+ return parseEscapedName(_quadBuffer, qlen, 0, q, 0);
+ }
+
+ /**
+ * Method called when not even first 8 bytes are guaranteed
+ * to come consecutively. Happens rarely, so this is offlined;
+ * plus we'll also do full checks for escaping etc.
+ */
+ protected String slowParseName() throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(": was expecting closing '\"' for name");
+ }
+ }
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
+ if (i == INT_QUOTE) { // special case, ""
+ return "";
+ }
+ return parseEscapedName(_quadBuffer, 0, 0, i, 0);
+ }
+
+ private final String parseName(int q1, int ch, int lastQuadBytes) throws IOException {
+ return parseEscapedName(_quadBuffer, 0, q1, ch, lastQuadBytes);
+ }
+
+ private final String parseName(int q1, int q2, int ch, int lastQuadBytes) throws IOException {
+ _quadBuffer[0] = q1;
+ return parseEscapedName(_quadBuffer, 1, q2, ch, lastQuadBytes);
+ }
+
+ private final String parseName(int q1, int q2, int q3, int ch, int lastQuadBytes) throws IOException {
+ _quadBuffer[0] = q1;
+ _quadBuffer[1] = q2;
+ return parseEscapedName(_quadBuffer, 2, q3, ch, lastQuadBytes);
+ }
+
+ /**
+ * Slower parsing method which is generally branched to when
+ * an escape sequence is detected (or alternatively for long
+ * names, one crossing input buffer boundary).
+ * Needs to be able to handle more exceptional cases, gets slower,
+ * and hance is offlined to a separate method.
+ */
+ protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int ch,
+ int currQuadBytes) throws IOException
+ {
+ /* 25-Nov-2008, tatu: This may seem weird, but here we do not want to worry about
+ * UTF-8 decoding yet. Rather, we'll assume that part is ok (if not it will get
+ * caught later on), and just handle quotes and backslashes here.
+ */
+ final int[] codes = _icLatin1;
+
+ while (true) {
+ if (codes[ch] != 0) {
+ if (ch == INT_QUOTE) { // we are done
+ break;
+ }
+ // Unquoted white space?
+ if (ch != INT_BACKSLASH) {
+ // As per [JACKSON-208], call can now return:
+ _throwUnquotedSpace(ch, "name");
+ } else {
+ // Nope, escape sequence
+ ch = _decodeEscaped();
+ }
+ /* Oh crap. May need to UTF-8 (re-)encode it, if it's
+ * beyond 7-bit ascii. Gets pretty messy.
+ * If this happens often, may want to use different name
+ * canonicalization to avoid these hits.
+ */
+ if (ch > 127) {
+ // Ok, we'll need room for first byte right away
+ if (currQuadBytes >= 4) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = 0;
+ currQuadBytes = 0;
+ }
+ if (ch < 0x800) { // 2-byte
+ currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
+ ++currQuadBytes;
+ // Second byte gets output below:
+ } else { // 3 bytes; no need to worry about surrogates here
+ currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
+ ++currQuadBytes;
+ // need room for middle byte?
+ if (currQuadBytes >= 4) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = 0;
+ currQuadBytes = 0;
+ }
+ currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
+ ++currQuadBytes;
+ }
+ // And same last byte in both cases, gets output below:
+ ch = 0x80 | (ch & 0x3f);
+ }
+ }
+ // Ok, we have one more byte to add at any rate:
+ if (currQuadBytes < 4) {
+ ++currQuadBytes;
+ currQuad = (currQuad << 8) | ch;
+ } else {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = ch;
+ currQuadBytes = 1;
+ }
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in field name");
+ }
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ }
+
+ if (currQuadBytes > 0) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = pad(currQuad, currQuadBytes);
+ }
+ String name = _symbols.findName(quads, qlen);
+ if (name == null) {
+ name = addName(quads, qlen, currQuadBytes);
+ }
+ return name;
+ }
+
+ /**
+ * Method called when we see non-white space character other
+ * than double quote, when expecting a field name.
+ * In standard mode will just throw an exception; but
+ * in non-standard modes may be able to parse name.
+ */
+ protected String _handleOddName(int ch) throws IOException
+ {
+ // [JACKSON-173]: allow single quotes
+ if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+ return _parseAposName();
+ }
+ // [JACKSON-69]: allow unquoted names if feature enabled:
+ if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) {
+ char c = (char) _decodeCharForError(ch);
+ _reportUnexpectedChar(c, "was expecting double-quote to start field name");
+ }
+ /* Also: note that although we use a different table here,
+ * it does NOT handle UTF-8 decoding. It'll just pass those
+ * high-bit codes as acceptable for later decoding.
+ */
+ final int[] codes = CharTypes.getInputCodeUtf8JsNames();
+ // Also: must start with a valid character...
+ if (codes[ch] != 0) {
+ _reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
+ }
+
+ /* Ok, now; instead of ultra-optimizing parsing here (as with
+ * regular JSON names), let's just use the generic "slow"
+ * variant. Can measure its impact later on if need be
+ */
+ int[] quads = _quadBuffer;
+ int qlen = 0;
+ int currQuad = 0;
+ int currQuadBytes = 0;
+
+ while (true) {
+ // Ok, we have one more byte to add at any rate:
+ if (currQuadBytes < 4) {
+ ++currQuadBytes;
+ currQuad = (currQuad << 8) | ch;
+ } else {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = ch;
+ currQuadBytes = 1;
+ }
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in field name");
+ }
+ }
+ ch = _inputBuffer[_inputPtr] & 0xFF;
+ if (codes[ch] != 0) {
+ break;
+ }
+ ++_inputPtr;
+ }
+
+ if (currQuadBytes > 0) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ }
+ String name = _symbols.findName(quads, qlen);
+ if (name == null) {
+ name = addName(quads, qlen, currQuadBytes);
+ }
+ return name;
+ }
+
+ /* Parsing to support [JACKSON-173]. Plenty of duplicated code;
+ * main reason being to try to avoid slowing down fast path
+ * for valid JSON -- more alternatives, more code, generally
+ * bit slower execution.
+ */
+ protected String _parseAposName() throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(": was expecting closing '\'' for name");
+ }
+ }
+ int ch = _inputBuffer[_inputPtr++] & 0xFF;
+ if (ch == '\'') { // special case, ''
+ return "";
+ }
+ int[] quads = _quadBuffer;
+ int qlen = 0;
+ int currQuad = 0;
+ int currQuadBytes = 0;
+
+ // Copied from parseEscapedFieldName, with minor mods:
+
+ final int[] codes = _icLatin1;
+
+ while (true) {
+ if (ch == '\'') {
+ break;
+ }
+ // additional check to skip handling of double-quotes
+ if (ch != '"' && codes[ch] != 0) {
+ if (ch != '\\') {
+ // Unquoted white space?
+ // As per [JACKSON-208], call can now return:
+ _throwUnquotedSpace(ch, "name");
+ } else {
+ // Nope, escape sequence
+ ch = _decodeEscaped();
+ }
+ /* Oh crap. May need to UTF-8 (re-)encode it, if it's
+ * beyond 7-bit ascii. Gets pretty messy.
+ * If this happens often, may want to use different name
+ * canonicalization to avoid these hits.
+ */
+ if (ch > 127) {
+ // Ok, we'll need room for first byte right away
+ if (currQuadBytes >= 4) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = 0;
+ currQuadBytes = 0;
+ }
+ if (ch < 0x800) { // 2-byte
+ currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
+ ++currQuadBytes;
+ // Second byte gets output below:
+ } else { // 3 bytes; no need to worry about surrogates here
+ currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
+ ++currQuadBytes;
+ // need room for middle byte?
+ if (currQuadBytes >= 4) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = 0;
+ currQuadBytes = 0;
+ }
+ currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
+ ++currQuadBytes;
+ }
+ // And same last byte in both cases, gets output below:
+ ch = 0x80 | (ch & 0x3f);
+ }
+ }
+ // Ok, we have one more byte to add at any rate:
+ if (currQuadBytes < 4) {
+ ++currQuadBytes;
+ currQuad = (currQuad << 8) | ch;
+ } else {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = currQuad;
+ currQuad = ch;
+ currQuadBytes = 1;
+ }
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in field name");
+ }
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ }
+
+ if (currQuadBytes > 0) {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = pad(currQuad, currQuadBytes);
+ }
+ String name = _symbols.findName(quads, qlen);
+ if (name == null) {
+ name = addName(quads, qlen, currQuadBytes);
+ }
+ return name;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, symbol (name) handling
+ /**********************************************************
+ */
+
+ private final String findName(int q1, int lastQuadBytes) throws JsonParseException
+ {
+ q1 = pad(q1, lastQuadBytes);
+ // Usually we'll find it from the canonical symbol table already
+ String name = _symbols.findName(q1);
+ if (name != null) {
+ return name;
+ }
+ // If not, more work. We'll need add stuff to buffer
+ _quadBuffer[0] = q1;
+ return addName(_quadBuffer, 1, lastQuadBytes);
+ }
+
+ private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
+ {
+ q2 = pad(q2, lastQuadBytes);
+ // Usually we'll find it from the canonical symbol table already
+ String name = _symbols.findName(q1, q2);
+ if (name != null) {
+ return name;
+ }
+ // If not, more work. We'll need add stuff to buffer
+ _quadBuffer[0] = q1;
+ _quadBuffer[1] = q2;
+ return addName(_quadBuffer, 2, lastQuadBytes);
+ }
+
+ private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
+ {
+ q3 = pad(q3, lastQuadBytes);
+ String name = _symbols.findName(q1, q2, q3);
+ if (name != null) {
+ return name;
+ }
+ int[] quads = _quadBuffer;
+ quads[0] = q1;
+ quads[1] = q2;
+ quads[2] = pad(q3, lastQuadBytes);
+ return addName(quads, 3, lastQuadBytes);
+ }
+
+ private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
+ {
+ if (qlen >= quads.length) {
+ _quadBuffer = quads = growArrayBy(quads, quads.length);
+ }
+ quads[qlen++] = pad(lastQuad, lastQuadBytes);
+ String name = _symbols.findName(quads, qlen);
+ if (name == null) {
+ return addName(quads, qlen, lastQuadBytes);
+ }
+ return name;
+ }
+
+ /**
+ * This is the main workhorse method used when we take a symbol
+ * table miss. It needs to demultiplex individual bytes, decode
+ * multi-byte chars (if any), and then construct Name instance
+ * and add it to the symbol table.
+ */
+ private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
+ {
+ /* Ok: must decode UTF-8 chars. No other validation is
+ * needed, since unescaping has been done earlier as necessary
+ * (as well as error reporting for unescaped control chars)
+ */
+ // 4 bytes per quad, except last one maybe less
+ int byteLen = (qlen << 2) - 4 + lastQuadBytes;
+
+ /* And last one is not correctly aligned (leading zero bytes instead
+ * need to shift a bit, instead of trailing). Only need to shift it
+ * for UTF-8 decoding; need revert for storage (since key will not
+ * be aligned, to optimize lookup speed)
+ */
+ int lastQuad;
+
+ if (lastQuadBytes < 4) {
+ lastQuad = quads[qlen-1];
+ // 8/16/24 bit left shift
+ quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3));
+ } else {
+ lastQuad = 0;
+ }
+
+ // Need some working space, TextBuffer works well:
+ char[] cbuf = _textBuffer.emptyAndGetCurrentSegment();
+ int cix = 0;
+
+ for (int ix = 0; ix < byteLen; ) {
+ int ch = quads[ix >> 2]; // current quad, need to shift+mask
+ int byteIx = (ix & 3);
+ ch = (ch >> ((3 - byteIx) << 3)) & 0xFF;
+ ++ix;
+
+ if (ch > 127) { // multi-byte
+ int needed;
+ if ((ch & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
+ ch &= 0x1F;
+ needed = 1;
+ } else if ((ch & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
+ ch &= 0x0F;
+ needed = 2;
+ } else if ((ch & 0xF8) == 0xF0) { // 4 bytes; double-char with surrogates and all...
+ ch &= 0x07;
+ needed = 3;
+ } else { // 5- and 6-byte chars not valid xml chars
+ _reportInvalidInitial(ch);
+ needed = ch = 1; // never really gets this far
+ }
+ if ((ix + needed) > byteLen) {
+ _reportInvalidEOF(" in field name");
+ }
+
+ // Ok, always need at least one more:
+ int ch2 = quads[ix >> 2]; // current quad, need to shift+mask
+ byteIx = (ix & 3);
+ ch2 = (ch2 >> ((3 - byteIx) << 3));
+ ++ix;
+
+ if ((ch2 & 0xC0) != 0x080) {
+ _reportInvalidOther(ch2);
+ }
+ ch = (ch << 6) | (ch2 & 0x3F);
+ if (needed > 1) {
+ ch2 = quads[ix >> 2];
+ byteIx = (ix & 3);
+ ch2 = (ch2 >> ((3 - byteIx) << 3));
+ ++ix;
+
+ if ((ch2 & 0xC0) != 0x080) {
+ _reportInvalidOther(ch2);
+ }
+ ch = (ch << 6) | (ch2 & 0x3F);
+ if (needed > 2) { // 4 bytes? (need surrogates on output)
+ ch2 = quads[ix >> 2];
+ byteIx = (ix & 3);
+ ch2 = (ch2 >> ((3 - byteIx) << 3));
+ ++ix;
+ if ((ch2 & 0xC0) != 0x080) {
+ _reportInvalidOther(ch2 & 0xFF);
+ }
+ ch = (ch << 6) | (ch2 & 0x3F);
+ }
+ }
+ if (needed > 2) { // surrogate pair? once again, let's output one here, one later on
+ ch -= 0x10000; // to normalize it starting with 0x0
+ if (cix >= cbuf.length) {
+ cbuf = _textBuffer.expandCurrentSegment();
+ }
+ cbuf[cix++] = (char) (0xD800 + (ch >> 10));
+ ch = 0xDC00 | (ch & 0x03FF);
+ }
+ }
+ if (cix >= cbuf.length) {
+ cbuf = _textBuffer.expandCurrentSegment();
+ }
+ cbuf[cix++] = (char) ch;
+ }
+
+ // Ok. Now we have the character array, and can construct the String
+ String baseName = new String(cbuf, 0, cix);
+ // And finally, un-align if necessary
+ if (lastQuadBytes < 4) {
+ quads[qlen-1] = lastQuad;
+ }
+ return _symbols.addName(baseName, quads, qlen);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, String value parsing
+ /**********************************************************
+ */
+
+ @Override
+ protected void _finishString() throws IOException
+ {
+ // First, single tight loop for ASCII content, not split across input buffer boundary:
+ int ptr = _inputPtr;
+ if (ptr >= _inputEnd) {
+ loadMoreGuaranteed();
+ ptr = _inputPtr;
+ }
+ int outPtr = 0;
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+ final int[] codes = _icUTF8;
+
+ final int max = Math.min(_inputEnd, (ptr + outBuf.length));
+ final byte[] inputBuffer = _inputBuffer;
+ while (ptr < max) {
+ int c = (int) inputBuffer[ptr] & 0xFF;
+ if (codes[c] != 0) {
+ if (c == INT_QUOTE) {
+ _inputPtr = ptr+1;
+ _textBuffer.setCurrentLength(outPtr);
+ return;
+ }
+ break;
+ }
+ ++ptr;
+ outBuf[outPtr++] = (char) c;
+ }
+ _inputPtr = ptr;
+ _finishString2(outBuf, outPtr);
+ }
+
+ /**
+ * @since 2.6
+ */
+ protected String _finishAndReturnString() throws IOException
+ {
+ // First, single tight loop for ASCII content, not split across input buffer boundary:
+ int ptr = _inputPtr;
+ if (ptr >= _inputEnd) {
+ loadMoreGuaranteed();
+ ptr = _inputPtr;
+ }
+ int outPtr = 0;
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+ final int[] codes = _icUTF8;
+
+ final int max = Math.min(_inputEnd, (ptr + outBuf.length));
+ final byte[] inputBuffer = _inputBuffer;
+ while (ptr < max) {
+ int c = (int) inputBuffer[ptr] & 0xFF;
+ if (codes[c] != 0) {
+ if (c == INT_QUOTE) {
+ _inputPtr = ptr+1;
+ return _textBuffer.setCurrentAndReturn(outPtr);
+ }
+ break;
+ }
+ ++ptr;
+ outBuf[outPtr++] = (char) c;
+ }
+ _inputPtr = ptr;
+ _finishString2(outBuf, outPtr);
+ return _textBuffer.contentsAsString();
+ }
+
+ private final void _finishString2(char[] outBuf, int outPtr)
+ throws IOException
+ {
+ int c;
+
+ // Here we do want to do full decoding, hence:
+ final int[] codes = _icUTF8;
+ final byte[] inputBuffer = _inputBuffer;
+
+ main_loop:
+ while (true) {
+ // Then the tight ASCII non-funny-char loop:
+ ascii_loop:
+ while (true) {
+ int ptr = _inputPtr;
+ if (ptr >= _inputEnd) {
+ loadMoreGuaranteed();
+ ptr = _inputPtr;
+ }
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
+ while (ptr < max) {
+ c = (int) inputBuffer[ptr++] & 0xFF;
+ if (codes[c] != 0) {
+ _inputPtr = ptr;
+ break ascii_loop;
+ }
+ outBuf[outPtr++] = (char) c;
+ }
+ _inputPtr = ptr;
+ }
+ // Ok: end marker, escape or multi-byte?
+ if (c == INT_QUOTE) {
+ break main_loop;
+ }
+
+ switch (codes[c]) {
+ case 1: // backslash
+ c = _decodeEscaped();
+ break;
+ case 2: // 2-byte UTF
+ c = _decodeUtf8_2(c);
+ break;
+ case 3: // 3-byte UTF
+ if ((_inputEnd - _inputPtr) >= 2) {
+ c = _decodeUtf8_3fast(c);
+ } else {
+ c = _decodeUtf8_3(c);
+ }
+ break;
+ case 4: // 4-byte UTF
+ c = _decodeUtf8_4(c);
+ // Let's add first part right away:
+ outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ c = 0xDC00 | (c & 0x3FF);
+ // And let the other char output down below
+ break;
+ default:
+ if (c < INT_SPACE) {
+ // As per [JACKSON-208], call can now return:
+ _throwUnquotedSpace(c, "string value");
+ } else {
+ // Is this good enough error message?
+ _reportInvalidChar(c);
+ }
+ }
+ // Need more room?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ // Ok, let's add char to output:
+ outBuf[outPtr++] = (char) c;
+ }
+ _textBuffer.setCurrentLength(outPtr);
+ }
+
+ /**
+ * Method called to skim through rest of unparsed String value,
+ * if it is not needed. This can be done bit faster if contents
+ * need not be stored for future access.
+ */
+ protected void _skipString() throws IOException
+ {
+ _tokenIncomplete = false;
+
+ // Need to be fully UTF-8 aware here:
+ final int[] codes = _icUTF8;
+ final byte[] inputBuffer = _inputBuffer;
+
+ main_loop:
+ while (true) {
+ int c;
+
+ ascii_loop:
+ while (true) {
+ int ptr = _inputPtr;
+ int max = _inputEnd;
+ if (ptr >= max) {
+ loadMoreGuaranteed();
+ ptr = _inputPtr;
+ max = _inputEnd;
+ }
+ while (ptr < max) {
+ c = (int) inputBuffer[ptr++] & 0xFF;
+ if (codes[c] != 0) {
+ _inputPtr = ptr;
+ break ascii_loop;
+ }
+ }
+ _inputPtr = ptr;
+ }
+ // Ok: end marker, escape or multi-byte?
+ if (c == INT_QUOTE) {
+ break main_loop;
+ }
+
+ switch (codes[c]) {
+ case 1: // backslash
+ _decodeEscaped();
+ break;
+ case 2: // 2-byte UTF
+ _skipUtf8_2(c);
+ break;
+ case 3: // 3-byte UTF
+ _skipUtf8_3(c);
+ break;
+ case 4: // 4-byte UTF
+ _skipUtf8_4(c);
+ break;
+ default:
+ if (c < INT_SPACE) {
+ // As per [JACKSON-208], call can now return:
+ _throwUnquotedSpace(c, "string value");
+ } else {
+ // Is this good enough error message?
+ _reportInvalidChar(c);
+ }
+ }
+ }
+ }
+
+ /**
+ * Method for handling cases where first non-space character
+ * of an expected value token is not legal for standard JSON content.
+ */
+ protected JsonToken _handleUnexpectedValue(int c)
+ throws IOException
+ {
+ // Most likely an error, unless we are to allow single-quote-strings
+ switch (c) {
+ case ']':
+ case '}':
+ // Error: neither is valid at this point; valid closers have
+ // been handled earlier
+ _reportUnexpectedChar(c, "expected a value");
+ case '\'':
+ if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+ return _handleApos();
+ }
+ break;
+ case 'N':
+ _matchToken("NaN", 1);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN("NaN", Double.NaN);
+ }
+ _reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ break;
+ case 'I':
+ _matchToken("Infinity", 1);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
+ }
+ _reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ break;
+ case '+': // note: '-' is taken as number
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOFInValue();
+ }
+ }
+ return _handleInvalidNumberStart(_inputBuffer[_inputPtr++] & 0xFF, false);
+ }
+ // [Issue#77] Try to decode most likely token
+ if (Character.isJavaIdentifierStart(c)) {
+ _reportInvalidToken(""+((char) c), "('true', 'false' or 'null')");
+ }
+ // but if it doesn't look like a token:
+ _reportUnexpectedChar(c, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
+ return null;
+ }
+
+ protected JsonToken _handleApos()
+ throws IOException
+ {
+ int c = 0;
+ // Otherwise almost verbatim copy of _finishString()
+ int outPtr = 0;
+ char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
+
+ // Here we do want to do full decoding, hence:
+ final int[] codes = _icUTF8;
+ final byte[] inputBuffer = _inputBuffer;
+
+ main_loop:
+ while (true) {
+ // Then the tight ascii non-funny-char loop:
+ ascii_loop:
+ while (true) {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ int max = _inputEnd;
+ {
+ int max2 = _inputPtr + (outBuf.length - outPtr);
+ if (max2 < max) {
+ max = max2;
+ }
+ }
+ while (_inputPtr < max) {
+ c = (int) inputBuffer[_inputPtr++] & 0xFF;
+ if (c == '\'' || codes[c] != 0) {
+ break ascii_loop;
+ }
+ outBuf[outPtr++] = (char) c;
+ }
+ }
+
+ // Ok: end marker, escape or multi-byte?
+ if (c == '\'') {
+ break main_loop;
+ }
+
+ switch (codes[c]) {
+ case 1: // backslash
+ if (c != '\'') { // marked as special, isn't here
+ c = _decodeEscaped();
+ }
+ break;
+ case 2: // 2-byte UTF
+ c = _decodeUtf8_2(c);
+ break;
+ case 3: // 3-byte UTF
+ if ((_inputEnd - _inputPtr) >= 2) {
+ c = _decodeUtf8_3fast(c);
+ } else {
+ c = _decodeUtf8_3(c);
+ }
+ break;
+ case 4: // 4-byte UTF
+ c = _decodeUtf8_4(c);
+ // Let's add first part right away:
+ outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ c = 0xDC00 | (c & 0x3FF);
+ // And let the other char output down below
+ break;
+ default:
+ if (c < INT_SPACE) {
+ _throwUnquotedSpace(c, "string value");
+ }
+ // Is this good enough error message?
+ _reportInvalidChar(c);
+ }
+ // Need more room?
+ if (outPtr >= outBuf.length) {
+ outBuf = _textBuffer.finishCurrentSegment();
+ outPtr = 0;
+ }
+ // Ok, let's add char to output:
+ outBuf[outPtr++] = (char) c;
+ }
+ _textBuffer.setCurrentLength(outPtr);
+
+ return JsonToken.VALUE_STRING;
+ }
+
+ /**
+ * Method called if expected numeric value (due to leading sign) does not
+ * look like a number
+ */
+ protected JsonToken _handleInvalidNumberStart(int ch, boolean neg)
+ throws IOException
+ {
+ while (ch == 'I') {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOFInValue();
+ }
+ }
+ ch = _inputBuffer[_inputPtr++];
+ String match;
+ if (ch == 'N') {
+ match = neg ? "-INF" :"+INF";
+ } else if (ch == 'n') {
+ match = neg ? "-Infinity" :"+Infinity";
+ } else {
+ break;
+ }
+ _matchToken(match, 3);
+ if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
+ return resetAsNaN(match, neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
+ }
+ _reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
+ }
+ reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
+ return null;
+ }
+
+ protected final void _matchToken(String matchStr, int i) throws IOException
+ {
+ final int len = matchStr.length();
+ if ((_inputPtr + len) >= _inputEnd) {
+ _matchToken2(matchStr, i);
+ return;
+ }
+ do {
+ if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
+ _reportInvalidToken(matchStr.substring(0, i));
+ }
+ ++_inputPtr;
+ } while (++i < len);
+
+ int ch = _inputBuffer[_inputPtr] & 0xFF;
+ if (ch >= '0' && ch != ']' && ch != '}') { // expected/allowed chars
+ _checkMatchEnd(matchStr, i, ch);
+ }
+ }
+
+ private final void _matchToken2(String matchStr, int i) throws IOException
+ {
+ final int len = matchStr.length();
+ do {
+ if (((_inputPtr >= _inputEnd) && !loadMore())
+ || (_inputBuffer[_inputPtr] != matchStr.charAt(i))) {
+ _reportInvalidToken(matchStr.substring(0, i));
+ }
+ ++_inputPtr;
+ } while (++i < len);
+
+ // but let's also ensure we either get EOF, or non-alphanum char...
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ return;
+ }
+ int ch = _inputBuffer[_inputPtr] & 0xFF;
+ if (ch >= '0' && ch != ']' && ch != '}') { // expected/allowed chars
+ _checkMatchEnd(matchStr, i, ch);
+ }
+ }
+
+ private final void _checkMatchEnd(String matchStr, int i, int ch) throws IOException {
+ // but actually only alphanums are problematic
+ char c = (char) _decodeCharForError(ch);
+ if (Character.isJavaIdentifierPart(c)) {
+ _reportInvalidToken(matchStr.substring(0, i));
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, ws skipping, escape/unescape
+ /**********************************************************
+ */
+
+ private final int _skipWS() throws IOException
+ {
+ while (_inputPtr < _inputEnd) {
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ --_inputPtr;
+ return _skipWS2();
+ }
+ return i;
+ }
+ if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ return _skipWS2();
+ }
+
+ private final int _skipWS2() throws IOException
+ {
+ while (_inputPtr < _inputEnd || loadMore()) {
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH) {
+ _skipComment();
+ continue;
+ }
+ if (i == INT_HASH) {
+ if (_skipYAMLComment()) {
+ continue;
+ }
+ }
+ return i;
+ }
+ if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
+ }
+
+ private final int _skipWSOrEnd() throws IOException
+ {
+ // Let's handle first character separately since it is likely that
+ // it is either non-whitespace; or we have longer run of white space
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ return _eofAsNextChar();
+ }
+ }
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ --_inputPtr;
+ return _skipWSOrEnd2();
+ }
+ return i;
+ }
+ if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+
+ while (_inputPtr < _inputEnd) {
+ i = _inputBuffer[_inputPtr++] & 0xFF;
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ --_inputPtr;
+ return _skipWSOrEnd2();
+ }
+ return i;
+ }
+ if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ return _skipWSOrEnd2();
+ }
+
+ private final int _skipWSOrEnd2() throws IOException
+ {
+ while ((_inputPtr < _inputEnd) || loadMore()) {
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH) {
+ _skipComment();
+ continue;
+ }
+ if (i == INT_HASH) {
+ if (_skipYAMLComment()) {
+ continue;
+ }
+ }
+ return i;
+ } else if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ // We ran out of input...
+ return _eofAsNextChar();
+ }
+
+ private final int _skipColon() throws IOException
+ {
+ if ((_inputPtr + 4) >= _inputEnd) {
+ return _skipColon2(false);
+ }
+ // Fast path: colon with optional single-space/tab before and/or after:
+ int i = _inputBuffer[_inputPtr];
+ if (i == INT_COLON) { // common case, no leading space
+ i = _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) { // nor trailing
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ }
+ return _skipColon2(true); // true -> skipped colon
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = _inputBuffer[++_inputPtr];
+ }
+ if (i == INT_COLON) {
+ i = _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ if (i == INT_SPACE || i == INT_TAB) {
+ i = (int) _inputBuffer[++_inputPtr];
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH || i == INT_HASH) {
+ return _skipColon2(true);
+ }
+ ++_inputPtr;
+ return i;
+ }
+ }
+ return _skipColon2(true);
+ }
+ return _skipColon2(false);
+ }
+
+ private final int _skipColon2(boolean gotColon) throws IOException
+ {
+ while (_inputPtr < _inputEnd || loadMore()) {
+ int i = _inputBuffer[_inputPtr++] & 0xFF;
+
+ if (i > INT_SPACE) {
+ if (i == INT_SLASH) {
+ _skipComment();
+ continue;
+ }
+ if (i == INT_HASH) {
+ if (_skipYAMLComment()) {
+ continue;
+ }
+ }
+ if (gotColon) {
+ return i;
+ }
+ if (i != INT_COLON) {
+ if (i < INT_SPACE) {
+ _throwInvalidSpace(i);
+ }
+ _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
+ }
+ gotColon = true;
+ } else if (i != INT_SPACE) {
+ if (i == INT_LF) {
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ } else if (i == INT_CR) {
+ _skipCR();
+ } else if (i != INT_TAB) {
+ _throwInvalidSpace(i);
+ }
+ }
+ }
+ throw _constructError("Unexpected end-of-input within/between "+_parsingContext.getTypeDesc()+" entries");
+ }
+
+ private final void _skipComment() throws IOException
+ {
+ if (!isEnabled(Feature.ALLOW_COMMENTS)) {
+ _reportUnexpectedChar('/', "maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)");
+ }
+ // First: check which comment (if either) it is:
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ _reportInvalidEOF(" in a comment");
+ }
+ int c = _inputBuffer[_inputPtr++] & 0xFF;
+ if (c == '/') {
+ _skipLine();
+ } else if (c == '*') {
+ _skipCComment();
+ } else {
+ _reportUnexpectedChar(c, "was expecting either '*' or '/' for a comment");
+ }
+ }
+
+ private final void _skipCComment() throws IOException
+ {
+ // Need to be UTF-8 aware here to decode content (for skipping)
+ final int[] codes = CharTypes.getInputCodeComment();
+
+ // Ok: need the matching '*/'
+ main_loop:
+ while ((_inputPtr < _inputEnd) || loadMore()) {
+ int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ int code = codes[i];
+ if (code != 0) {
+ switch (code) {
+ case '*':
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ break main_loop;
+ }
+ if (_inputBuffer[_inputPtr] == INT_SLASH) {
+ ++_inputPtr;
+ return;
+ }
+ break;
+ case INT_LF:
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ break;
+ case INT_CR:
+ _skipCR();
+ break;
+ case 2: // 2-byte UTF
+ _skipUtf8_2(i);
+ break;
+ case 3: // 3-byte UTF
+ _skipUtf8_3(i);
+ break;
+ case 4: // 4-byte UTF
+ _skipUtf8_4(i);
+ break;
+ default: // e.g. -1
+ // Is this good enough error message?
+ _reportInvalidChar(i);
+ }
+ }
+ }
+ _reportInvalidEOF(" in a comment");
+ }
+
+ private final boolean _skipYAMLComment() throws IOException
+ {
+ if (!isEnabled(Feature.ALLOW_YAML_COMMENTS)) {
+ return false;
+ }
+ _skipLine();
+ return true;
+ }
+
+ /**
+ * Method for skipping contents of an input line; usually for CPP
+ * and YAML style comments.
+ */
+ private final void _skipLine() throws IOException
+ {
+ // Ok: need to find EOF or linefeed
+ final int[] codes = CharTypes.getInputCodeComment();
+ while ((_inputPtr < _inputEnd) || loadMore()) {
+ int i = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ int code = codes[i];
+ if (code != 0) {
+ switch (code) {
+ case INT_LF:
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ return;
+ case INT_CR:
+ _skipCR();
+ return;
+ case '*': // nop for these comments
+ break;
+ case 2: // 2-byte UTF
+ _skipUtf8_2(i);
+ break;
+ case 3: // 3-byte UTF
+ _skipUtf8_3(i);
+ break;
+ case 4: // 4-byte UTF
+ _skipUtf8_4(i);
+ break;
+ default: // e.g. -1
+ if (code < 0) {
+ // Is this good enough error message?
+ _reportInvalidChar(i);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ protected char _decodeEscaped() throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in character escape sequence");
+ }
+ }
+ int c = (int) _inputBuffer[_inputPtr++];
+
+ switch (c) {
+ // First, ones that are mapped
+ case 'b':
+ return '\b';
+ case 't':
+ return '\t';
+ case 'n':
+ return '\n';
+ case 'f':
+ return '\f';
+ case 'r':
+ return '\r';
+
+ // And these are to be returned as they are
+ case '"':
+ case '/':
+ case '\\':
+ return (char) c;
+
+ case 'u': // and finally hex-escaped
+ break;
+
+ default:
+ return _handleUnrecognizedCharacterEscape((char) _decodeCharForError(c));
+ }
+
+ // Ok, a hex escape. Need 4 characters
+ int value = 0;
+ for (int i = 0; i < 4; ++i) {
+ if (_inputPtr >= _inputEnd) {
+ if (!loadMore()) {
+ _reportInvalidEOF(" in character escape sequence");
+ }
+ }
+ int ch = (int) _inputBuffer[_inputPtr++];
+ int digit = CharTypes.charToHex(ch);
+ if (digit < 0) {
+ _reportUnexpectedChar(ch, "expected a hex-digit for character escape sequence");
+ }
+ value = (value << 4) | digit;
+ }
+ return (char) value;
+ }
+
+ protected int _decodeCharForError(int firstByte) throws IOException
+ {
+ int c = firstByte & 0xFF;
+ if (c > 0x7F) { // if >= 0, is ascii and fine as is
+ int needed;
+
+ // Ok; if we end here, we got multi-byte combination
+ if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
+ c &= 0x1F;
+ needed = 1;
+ } else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
+ c &= 0x0F;
+ needed = 2;
+ } else if ((c & 0xF8) == 0xF0) {
+ // 4 bytes; double-char with surrogates and all...
+ c &= 0x07;
+ needed = 3;
+ } else {
+ _reportInvalidInitial(c & 0xFF);
+ needed = 1; // never gets here
+ }
+
+ int d = nextByte();
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF);
+ }
+ c = (c << 6) | (d & 0x3F);
+
+ if (needed > 1) { // needed == 1 means 2 bytes total
+ d = nextByte(); // 3rd byte
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF);
+ }
+ c = (c << 6) | (d & 0x3F);
+ if (needed > 2) { // 4 bytes? (need surrogates)
+ d = nextByte();
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF);
+ }
+ c = (c << 6) | (d & 0x3F);
+ }
+ }
+ }
+ return c;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods,UTF8 decoding
+ /**********************************************************
+ */
+
+ private final int _decodeUtf8_2(int c) throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ int d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ return ((c & 0x1F) << 6) | (d & 0x3F);
+ }
+
+ private final int _decodeUtf8_3(int c1) throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ c1 &= 0x0F;
+ int d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ int c = (c1 << 6) | (d & 0x3F);
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ c = (c << 6) | (d & 0x3F);
+ return c;
+ }
+
+ private final int _decodeUtf8_3fast(int c1) throws IOException
+ {
+ c1 &= 0x0F;
+ int d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ int c = (c1 << 6) | (d & 0x3F);
+ d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ c = (c << 6) | (d & 0x3F);
+ return c;
+ }
+
+ /**
+ * @return Character value minus 0x10000; this so that caller
+ * can readily expand it to actual surrogates
+ */
+ private final int _decodeUtf8_4(int c) throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ int d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ c = ((c & 0x07) << 6) | (d & 0x3F);
+
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ c = (c << 6) | (d & 0x3F);
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+
+ /* note: won't change it to negative here, since caller
+ * already knows it'll need a surrogate
+ */
+ return ((c << 6) | (d & 0x3F)) - 0x10000;
+ }
+
+ private final void _skipUtf8_2(int c) throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ c = (int) _inputBuffer[_inputPtr++];
+ if ((c & 0xC0) != 0x080) {
+ _reportInvalidOther(c & 0xFF, _inputPtr);
+ }
+ }
+
+ /* Alas, can't heavily optimize skipping, since we still have to
+ * do validity checks...
+ */
+ private final void _skipUtf8_3(int c) throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ //c &= 0x0F;
+ c = (int) _inputBuffer[_inputPtr++];
+ if ((c & 0xC0) != 0x080) {
+ _reportInvalidOther(c & 0xFF, _inputPtr);
+ }
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ c = (int) _inputBuffer[_inputPtr++];
+ if ((c & 0xC0) != 0x080) {
+ _reportInvalidOther(c & 0xFF, _inputPtr);
+ }
+ }
+
+ private final void _skipUtf8_4(int c) throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ int d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ d = (int) _inputBuffer[_inputPtr++];
+ if ((d & 0xC0) != 0x080) {
+ _reportInvalidOther(d & 0xFF, _inputPtr);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, input loading
+ /**********************************************************
+ */
+
+ /**
+ * We actually need to check the character value here
+ * (to see if we have \n following \r).
+ */
+ protected final void _skipCR() throws IOException
+ {
+ if (_inputPtr < _inputEnd || loadMore()) {
+ if (_inputBuffer[_inputPtr] == BYTE_LF) {
+ ++_inputPtr;
+ }
+ }
+ ++_currInputRow;
+ _currInputRowStart = _inputPtr;
+ }
+
+ private int nextByte() throws IOException
+ {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ return _inputBuffer[_inputPtr++] & 0xFF;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, error reporting
+ /**********************************************************
+ */
+
+ protected void _reportInvalidToken(String matchedPart) throws IOException
+ {
+ _reportInvalidToken(matchedPart, "'null', 'true', 'false' or NaN");
+ }
+
+ protected void _reportInvalidToken(String matchedPart, String msg) throws IOException
+ {
+ StringBuilder sb = new StringBuilder(matchedPart);
+
+ /* Let's just try to find what appears to be the token, using
+ * regular Java identifier character rules. It's just a heuristic,
+ * nothing fancy here (nor fast).
+ */
+ while (true) {
+ if (_inputPtr >= _inputEnd && !loadMore()) {
+ break;
+ }
+ int i = (int) _inputBuffer[_inputPtr++];
+ char c = (char) _decodeCharForError(i);
+ if (!Character.isJavaIdentifierPart(c)) {
+ break;
+ }
+ sb.append(c);
+ }
+ _reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
+ }
+
+ protected void _reportInvalidChar(int c)
+ throws JsonParseException
+ {
+ // Either invalid WS or illegal UTF-8 start char
+ if (c < INT_SPACE) {
+ _throwInvalidSpace(c);
+ }
+ _reportInvalidInitial(c);
+ }
+
+ protected void _reportInvalidInitial(int mask)
+ throws JsonParseException
+ {
+ _reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask));
+ }
+
+ protected void _reportInvalidOther(int mask)
+ throws JsonParseException
+ {
+ _reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask));
+ }
+
+ protected void _reportInvalidOther(int mask, int ptr)
+ throws JsonParseException
+ {
+ _inputPtr = ptr;
+ _reportInvalidOther(mask);
+ }
+
+ public static int[] growArrayBy(int[] arr, int more)
+ {
+ if (arr == null) {
+ return new int[more];
+ }
+ return Arrays.copyOf(arr, arr.length + more);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, binary access
+ /**********************************************************
+ */
+
+ /**
+ * Efficient handling for incremental parsing of base64-encoded
+ * textual content.
+ */
+ @SuppressWarnings("resource")
+ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOException
+ {
+ ByteArrayBuilder builder = _getByteArrayBuilder();
+
+ //main_loop:
+ while (true) {
+ // first, we'll skip preceding white space, if any
+ int ch;
+ do {
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
+ } while (ch <= INT_SPACE);
+ int bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) { // reached the end, fair and square?
+ if (ch == INT_QUOTE) {
+ return builder.toByteArray();
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 0);
+ if (bits < 0) { // white space to skip
+ continue;
+ }
+ }
+ int decodedData = bits;
+
+ // then second base64 char; can't get padding yet, nor ws
+
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ bits = _decodeBase64Escape(b64variant, ch, 1);
+ }
+ decodedData = (decodedData << 6) | bits;
+
+ // third base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ bits = b64variant.decodeBase64Char(ch);
+
+ // First branch: can get padding (-> 1 byte)
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 4;
+ builder.append(decodedData);
+ return builder.toByteArray();
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 2);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ // Ok, must get padding
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ if (!b64variant.usesPaddingChar(ch)) {
+ throw reportInvalidBase64Char(b64variant, ch, 3, "expected padding character '"+b64variant.getPaddingChar()+"'");
+ }
+ // Got 12 bits, only need 8, need to shift
+ decodedData >>= 4;
+ builder.append(decodedData);
+ continue;
+ }
+ }
+ // Nope, 2 or 3 bytes
+ decodedData = (decodedData << 6) | bits;
+ // fourth and last base64 char; can be padding, but not ws
+ if (_inputPtr >= _inputEnd) {
+ loadMoreGuaranteed();
+ }
+ ch = _inputBuffer[_inputPtr++] & 0xFF;
+ bits = b64variant.decodeBase64Char(ch);
+ if (bits < 0) {
+ if (bits != Base64Variant.BASE64_VALUE_PADDING) {
+ // as per [JACKSON-631], could also just be 'missing' padding
+ if (ch == '"' && !b64variant.usesPadding()) {
+ decodedData >>= 2;
+ builder.appendTwoBytes(decodedData);
+ return builder.toByteArray();
+ }
+ bits = _decodeBase64Escape(b64variant, ch, 3);
+ }
+ if (bits == Base64Variant.BASE64_VALUE_PADDING) {
+ /* With padding we only get 2 bytes; but we have
+ * to shift it a bit so it is identical to triplet
+ * case with partial output.
+ * 3 chars gives 3x6 == 18 bits, of which 2 are
+ * dummies, need to discard:
+ */
+ decodedData >>= 2;
+ builder.appendTwoBytes(decodedData);
+ continue;
+ }
+ }
+ // otherwise, our triplet is now complete
+ decodedData = (decodedData << 6) | bits;
+ builder.appendThreeBytes(decodedData);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Improved location updating (refactored in 2.7)
+ /**********************************************************
+ */
+
+ // As per [core#108], must ensure we call the right method
+ @Override
+ public JsonLocation getTokenLocation()
+ {
+ final Object src = _ioContext.getSourceReference();
+ if (_currToken == JsonToken.FIELD_NAME) {
+ long total = _currInputProcessed + (_nameStartOffset-1);
+ return new JsonLocation(src,
+ total, -1L, _nameStartRow, _nameStartCol);
+ }
+ return new JsonLocation(src,
+ _tokenInputTotal-1, -1L, _tokenInputRow, _tokenInputCol);
+ }
+
+ // As per [core#108], must ensure we call the right method
+ @Override
+ public JsonLocation getCurrentLocation()
+ {
+ int col = _inputPtr - _currInputRowStart + 1; // 1-based
+ return new JsonLocation(_ioContext.getSourceReference(),
+ _currInputProcessed + _inputPtr, -1L, // bytes, chars
+ _currInputRow, col);
+ }
+
+ // @since 2.7
+ private final void _updateLocation()
+ {
+ _tokenInputRow = _currInputRow;
+ final int ptr = _inputPtr;
+ _tokenInputTotal = _currInputProcessed + ptr;
+ _tokenInputCol = ptr - _currInputRowStart;
+ }
+
+ // @since 2.7
+ private final void _updateNameLocation()
+ {
+ _nameStartRow = _currInputRow;
+ final int ptr = _inputPtr;
+ _nameStartOffset = ptr;
+ _nameStartCol = ptr - _currInputRowStart;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, other
+ /**********************************************************
+ */
+
+ /**
+ * Helper method needed to fix [Issue#148], masking of 0x00 character
+ */
+ private final static int pad(int q, int bytes) {
+ return (bytes == 4) ? q : (q | (-1 << (bytes << 3)));
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,1883 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.*;
+
+/**
+ * {@link JsonGenerator} that outputs JSON content using a {@link java.io.Writer}
+ * which handles character encoding.
+ */
+public final class WriterBasedJsonGenerator
+ extends JsonGeneratorImpl
+{
+ final protected static int SHORT_WRITE = 32;
+
+ final protected static char[] HEX_CHARS = CharTypes.copyHexChars();
+
+ /*
+ /**********************************************************
+ /* Output buffering
+ /**********************************************************
+ */
+
+ final protected Writer _writer;
+
+ /**
+ * Intermediate buffer in which contents are buffered before
+ * being written using {@link #_writer}.
+ */
+ protected char[] _outputBuffer;
+
+ /**
+ * Pointer to the first buffered character to output
+ */
+ protected int _outputHead;
+
+ /**
+ * Pointer to the position right beyond the last character to output
+ * (end marker; may point to position right beyond the end of the buffer)
+ */
+ protected int _outputTail;
+
+ /**
+ * End marker of the output buffer; one past the last valid position
+ * within the buffer.
+ */
+ protected int _outputEnd;
+
+ /**
+ * Short (14 char) temporary buffer allocated if needed, for constructing
+ * escape sequences
+ */
+ protected char[] _entityBuffer;
+
+ /**
+ * When custom escapes are used, this member variable is used
+ * internally to hold a reference to currently used escape
+ */
+ protected SerializableString _currentEscape;
+
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public WriterBasedJsonGenerator(IOContext ctxt, int features,
+ ObjectCodec codec, Writer w)
+ {
+ super(ctxt, features, codec);
+ _writer = w;
+ _outputBuffer = ctxt.allocConcatBuffer();
+ _outputEnd = _outputBuffer.length;
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden configuration methods
+ /**********************************************************
+ */
+
+ @Override
+ public Object getOutputTarget() {
+ return _writer;
+ }
+
+ @Override
+ public int getOutputBuffered() {
+ // Assuming tail and head are kept but... trust and verify:
+ int len = _outputTail - _outputHead;
+ return Math.max(0, len);
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden methods
+ /**********************************************************
+ */
+
+ @Override
+ public void writeFieldName(String name) throws IOException
+ {
+ int status = _writeContext.writeFieldName(name);
+ if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
+ _reportError("Can not write a field name, expecting a value");
+ }
+ _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
+ }
+
+ @Override
+ public void writeFieldName(SerializableString name) throws IOException
+ {
+ // Object is a value, need to verify it's allowed
+ int status = _writeContext.writeFieldName(name.getValue());
+ if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
+ _reportError("Can not write a field name, expecting a value");
+ }
+ _writeFieldName(name, (status == JsonWriteContext.STATUS_OK_AFTER_COMMA));
+ }
+
+ protected void _writeFieldName(String name, boolean commaBefore) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ _writePPFieldName(name, commaBefore);
+ return;
+ }
+ // for fast+std case, need to output up to 2 chars, comma, dquote
+ if ((_outputTail + 1) >= _outputEnd) {
+ _flushBuffer();
+ }
+ if (commaBefore) {
+ _outputBuffer[_outputTail++] = ',';
+ }
+ // Alternate mode, in which quoting of field names disabled?
+ if (_cfgUnqNames) {
+ _writeString(name);
+ return;
+ }
+ // we know there's room for at least one more char
+ _outputBuffer[_outputTail++] = '"';
+ // The beef:
+ _writeString(name);
+ // and closing quotes; need room for one more char:
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ protected void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ _writePPFieldName(name, commaBefore);
+ return;
+ }
+ // for fast+std case, need to output up to 2 chars, comma, dquote
+ if ((_outputTail + 1) >= _outputEnd) {
+ _flushBuffer();
+ }
+ if (commaBefore) {
+ _outputBuffer[_outputTail++] = ',';
+ }
+ // Alternate mode, in which quoting of field names disabled?
+ final char[] quoted = name.asQuotedChars();
+ if (_cfgUnqNames) {
+ writeRaw(quoted, 0, quoted.length);
+ return;
+ }
+ // we know there's room for at least one more char
+ _outputBuffer[_outputTail++] = '"';
+ // The beef:
+ final int qlen = quoted.length;
+ if ((_outputTail + qlen + 1) >= _outputEnd) {
+ writeRaw(quoted, 0, qlen);
+ // and closing quotes; need room for one more char:
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ } else {
+ System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
+ _outputTail += qlen;
+ _outputBuffer[_outputTail++] = '"';
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, structural
+ /**********************************************************
+ */
+
+ @Override
+ public void writeStartArray() throws IOException, JsonGenerationException
+ {
+ _verifyValueWrite("start an array");
+ _writeContext = _writeContext.createChildArrayContext();
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeStartArray(this);
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '[';
+ }
+ }
+
+ @Override
+ public void writeEndArray() throws IOException, JsonGenerationException
+ {
+ if (!_writeContext.inArray()) {
+ _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc());
+ }
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = ']';
+ }
+ _writeContext = _writeContext.clearAndGetParent();
+ }
+
+ @Override
+ public void writeStartObject() throws IOException, JsonGenerationException
+ {
+ _verifyValueWrite("start an object");
+ _writeContext = _writeContext.createChildObjectContext();
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeStartObject(this);
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '{';
+ }
+ }
+
+ @Override
+ public void writeEndObject() throws IOException, JsonGenerationException
+ {
+ if (!_writeContext.inObject()) {
+ _reportError("Current context not an object but "+_writeContext.getTypeDesc());
+ }
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '}';
+ }
+ _writeContext = _writeContext.clearAndGetParent();
+ }
+
+ /**
+ * Specialized version of
+ * Note: when called, textual content to write is within output
+ * buffer, right after buffered content (if any). That's why only
+ * length of that text is passed, as buffer and offset are implied.
+ */
+ private void _writeSegment(int end) throws IOException
+ {
+ final int[] escCodes = _outputEscapes;
+ final int escLen = escCodes.length;
+
+ int ptr = 0;
+ int start = ptr;
+
+ output_loop:
+ while (ptr < end) {
+ // Fast loop for chars not needing escaping
+ char c;
+ while (true) {
+ c = _outputBuffer[ptr];
+ if (c < escLen && escCodes[c] != 0) {
+ break;
+ }
+ if (++ptr >= end) {
+ break;
+ }
+ }
+
+ // Ok, bumped into something that needs escaping.
+ /* First things first: need to flush the buffer.
+ * Inlined, as we don't want to lose tail pointer
+ */
+ int flushLen = (ptr - start);
+ if (flushLen > 0) {
+ _writer.write(_outputBuffer, start, flushLen);
+ if (ptr >= end) {
+ break output_loop;
+ }
+ }
+ ++ptr;
+ // So; either try to prepend (most likely), or write directly:
+ start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCodes[c]);
+ }
+ }
+
+ /**
+ * This method called when the string content is already in
+ * a char buffer, and need not be copied for processing.
+ */
+ private void _writeString(char[] text, int offset, int len) throws IOException
+ {
+ if (_characterEscapes != null) {
+ _writeStringCustom(text, offset, len);
+ return;
+ }
+ if (_maximumNonEscapedChar != 0) {
+ _writeStringASCII(text, offset, len, _maximumNonEscapedChar);
+ return;
+ }
+
+ /* Let's just find longest spans of non-escapable
+ * content, and for each see if it makes sense
+ * to copy them, or write through
+ */
+ len += offset; // -> len marks the end from now on
+ final int[] escCodes = _outputEscapes;
+ final int escLen = escCodes.length;
+ while (offset < len) {
+ int start = offset;
+
+ while (true) {
+ char c = text[offset];
+ if (c < escLen && escCodes[c] != 0) {
+ break;
+ }
+ if (++offset >= len) {
+ break;
+ }
+ }
+
+ // Short span? Better just copy it to buffer first:
+ int newAmount = offset - start;
+ if (newAmount < SHORT_WRITE) {
+ // Note: let's reserve room for escaped char (up to 6 chars)
+ if ((_outputTail + newAmount) > _outputEnd) {
+ _flushBuffer();
+ }
+ if (newAmount > 0) {
+ System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
+ _outputTail += newAmount;
+ }
+ } else { // Nope: better just write through
+ _flushBuffer();
+ _writer.write(text, start, newAmount);
+ }
+ // Was this the end?
+ if (offset >= len) { // yup
+ break;
+ }
+ // Nope, need to escape the char.
+ char c = text[offset++];
+ _appendCharacterEscape(c, escCodes[c]);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, text segment
+ /* with additional escaping (ASCII or such)
+ /**********************************************************
+ */
+
+ /* Same as "_writeString2()", except needs additional escaping
+ * for subset of characters
+ */
+ private void _writeStringASCII(final int len, final int maxNonEscaped)
+ throws IOException, JsonGenerationException
+ {
+ // And then we'll need to verify need for escaping etc:
+ int end = _outputTail + len;
+ final int[] escCodes = _outputEscapes;
+ final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
+ int escCode = 0;
+
+ output_loop:
+ while (_outputTail < end) {
+ char c;
+ // Fast loop for chars not needing escaping
+ escape_loop:
+ while (true) {
+ c = _outputBuffer[_outputTail];
+ if (c < escLimit) {
+ escCode = escCodes[c];
+ if (escCode != 0) {
+ break escape_loop;
+ }
+ } else if (c > maxNonEscaped) {
+ escCode = CharacterEscapes.ESCAPE_STANDARD;
+ break escape_loop;
+ }
+ if (++_outputTail >= end) {
+ break output_loop;
+ }
+ }
+ int flushLen = (_outputTail - _outputHead);
+ if (flushLen > 0) {
+ _writer.write(_outputBuffer, _outputHead, flushLen);
+ }
+ ++_outputTail;
+ _prependOrWriteCharacterEscape(c, escCode);
+ }
+ }
+
+ private void _writeSegmentASCII(int end, final int maxNonEscaped)
+ throws IOException, JsonGenerationException
+ {
+ final int[] escCodes = _outputEscapes;
+ final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
+
+ int ptr = 0;
+ int escCode = 0;
+ int start = ptr;
+
+ output_loop:
+ while (ptr < end) {
+ // Fast loop for chars not needing escaping
+ char c;
+ while (true) {
+ c = _outputBuffer[ptr];
+ if (c < escLimit) {
+ escCode = escCodes[c];
+ if (escCode != 0) {
+ break;
+ }
+ } else if (c > maxNonEscaped) {
+ escCode = CharacterEscapes.ESCAPE_STANDARD;
+ break;
+ }
+ if (++ptr >= end) {
+ break;
+ }
+ }
+ int flushLen = (ptr - start);
+ if (flushLen > 0) {
+ _writer.write(_outputBuffer, start, flushLen);
+ if (ptr >= end) {
+ break output_loop;
+ }
+ }
+ ++ptr;
+ start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode);
+ }
+ }
+
+ private void _writeStringASCII(char[] text, int offset, int len,
+ final int maxNonEscaped)
+ throws IOException, JsonGenerationException
+ {
+ len += offset; // -> len marks the end from now on
+ final int[] escCodes = _outputEscapes;
+ final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
+
+ int escCode = 0;
+
+ while (offset < len) {
+ int start = offset;
+ char c;
+
+ while (true) {
+ c = text[offset];
+ if (c < escLimit) {
+ escCode = escCodes[c];
+ if (escCode != 0) {
+ break;
+ }
+ } else if (c > maxNonEscaped) {
+ escCode = CharacterEscapes.ESCAPE_STANDARD;
+ break;
+ }
+ if (++offset >= len) {
+ break;
+ }
+ }
+
+ // Short span? Better just copy it to buffer first:
+ int newAmount = offset - start;
+ if (newAmount < SHORT_WRITE) {
+ // Note: let's reserve room for escaped char (up to 6 chars)
+ if ((_outputTail + newAmount) > _outputEnd) {
+ _flushBuffer();
+ }
+ if (newAmount > 0) {
+ System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
+ _outputTail += newAmount;
+ }
+ } else { // Nope: better just write through
+ _flushBuffer();
+ _writer.write(text, start, newAmount);
+ }
+ // Was this the end?
+ if (offset >= len) { // yup
+ break;
+ }
+ // Nope, need to escape the char.
+ ++offset;
+ _appendCharacterEscape(c, escCode);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, text segment
+ /* with custom escaping (possibly coupling with ASCII limits)
+ /**********************************************************
+ */
+
+ /* Same as "_writeString2()", except needs additional escaping
+ * for subset of characters
+ */
+ private void _writeStringCustom(final int len)
+ throws IOException, JsonGenerationException
+ {
+ // And then we'll need to verify need for escaping etc:
+ int end = _outputTail + len;
+ final int[] escCodes = _outputEscapes;
+ final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
+ final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
+ int escCode = 0;
+ final CharacterEscapes customEscapes = _characterEscapes;
+
+ output_loop:
+ while (_outputTail < end) {
+ char c;
+ // Fast loop for chars not needing escaping
+ escape_loop:
+ while (true) {
+ c = _outputBuffer[_outputTail];
+ if (c < escLimit) {
+ escCode = escCodes[c];
+ if (escCode != 0) {
+ break escape_loop;
+ }
+ } else if (c > maxNonEscaped) {
+ escCode = CharacterEscapes.ESCAPE_STANDARD;
+ break escape_loop;
+ } else {
+ if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
+ escCode = CharacterEscapes.ESCAPE_CUSTOM;
+ break escape_loop;
+ }
+ }
+ if (++_outputTail >= end) {
+ break output_loop;
+ }
+ }
+ int flushLen = (_outputTail - _outputHead);
+ if (flushLen > 0) {
+ _writer.write(_outputBuffer, _outputHead, flushLen);
+ }
+ ++_outputTail;
+ _prependOrWriteCharacterEscape(c, escCode);
+ }
+ }
+
+ private void _writeSegmentCustom(int end)
+ throws IOException, JsonGenerationException
+ {
+ final int[] escCodes = _outputEscapes;
+ final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
+ final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
+ final CharacterEscapes customEscapes = _characterEscapes;
+
+ int ptr = 0;
+ int escCode = 0;
+ int start = ptr;
+
+ output_loop:
+ while (ptr < end) {
+ // Fast loop for chars not needing escaping
+ char c;
+ while (true) {
+ c = _outputBuffer[ptr];
+ if (c < escLimit) {
+ escCode = escCodes[c];
+ if (escCode != 0) {
+ break;
+ }
+ } else if (c > maxNonEscaped) {
+ escCode = CharacterEscapes.ESCAPE_STANDARD;
+ break;
+ } else {
+ if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
+ escCode = CharacterEscapes.ESCAPE_CUSTOM;
+ break;
+ }
+ }
+ if (++ptr >= end) {
+ break;
+ }
+ }
+ int flushLen = (ptr - start);
+ if (flushLen > 0) {
+ _writer.write(_outputBuffer, start, flushLen);
+ if (ptr >= end) {
+ break output_loop;
+ }
+ }
+ ++ptr;
+ start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode);
+ }
+ }
+
+ private void _writeStringCustom(char[] text, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ len += offset; // -> len marks the end from now on
+ final int[] escCodes = _outputEscapes;
+ final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
+ final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
+ final CharacterEscapes customEscapes = _characterEscapes;
+
+ int escCode = 0;
+
+ while (offset < len) {
+ int start = offset;
+ char c;
+
+ while (true) {
+ c = text[offset];
+ if (c < escLimit) {
+ escCode = escCodes[c];
+ if (escCode != 0) {
+ break;
+ }
+ } else if (c > maxNonEscaped) {
+ escCode = CharacterEscapes.ESCAPE_STANDARD;
+ break;
+ } else {
+ if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
+ escCode = CharacterEscapes.ESCAPE_CUSTOM;
+ break;
+ }
+ }
+ if (++offset >= len) {
+ break;
+ }
+ }
+
+ // Short span? Better just copy it to buffer first:
+ int newAmount = offset - start;
+ if (newAmount < SHORT_WRITE) {
+ // Note: let's reserve room for escaped char (up to 6 chars)
+ if ((_outputTail + newAmount) > _outputEnd) {
+ _flushBuffer();
+ }
+ if (newAmount > 0) {
+ System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
+ _outputTail += newAmount;
+ }
+ } else { // Nope: better just write through
+ _flushBuffer();
+ _writer.write(text, start, newAmount);
+ }
+ // Was this the end?
+ if (offset >= len) { // yup
+ break;
+ }
+ // Nope, need to escape the char.
+ ++offset;
+ _appendCharacterEscape(c, escCode);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing; binary
+ /**********************************************************
+ */
+
+ protected void _writeBinary(Base64Variant b64variant, byte[] input, int inputPtr, final int inputEnd)
+ throws IOException, JsonGenerationException
+ {
+ // Encoding is by chunks of 3 input, 4 output chars, so:
+ int safeInputEnd = inputEnd - 3;
+ // Let's also reserve room for possible (and quoted) lf char each round
+ int safeOutputEnd = _outputEnd - 6;
+ int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+
+ // Ok, first we loop through all full triplets of data:
+ while (inputPtr <= safeInputEnd) {
+ if (_outputTail > safeOutputEnd) { // need to flush
+ _flushBuffer();
+ }
+ // First, mash 3 bytes into lsb of 32-bit int
+ int b24 = ((int) input[inputPtr++]) << 8;
+ b24 |= ((int) input[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
+ _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
+ if (--chunksBeforeLF <= 0) {
+ // note: must quote in JSON value
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = 'n';
+ chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+ }
+ }
+
+ // And then we may have 1 or 2 leftover bytes to encode
+ int inputLeft = inputEnd - inputPtr; // 0, 1 or 2
+ if (inputLeft > 0) { // yes, but do we have room for output?
+ if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
+ _flushBuffer();
+ }
+ int b24 = ((int) input[inputPtr++]) << 16;
+ if (inputLeft == 2) {
+ b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
+ }
+ _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
+ }
+ }
+
+ // write-method called when length is definitely known
+ protected int _writeBinary(Base64Variant b64variant,
+ InputStream data, byte[] readBuffer, int bytesLeft)
+ throws IOException, JsonGenerationException
+ {
+ int inputPtr = 0;
+ int inputEnd = 0;
+ int lastFullOffset = -3;
+
+ // Let's also reserve room for possible (and quoted) lf char each round
+ int safeOutputEnd = _outputEnd - 6;
+ int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+
+ while (bytesLeft > 2) { // main loop for full triplets
+ if (inputPtr > lastFullOffset) {
+ inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
+ inputPtr = 0;
+ if (inputEnd < 3) { // required to try to read to have at least 3 bytes
+ break;
+ }
+ lastFullOffset = inputEnd-3;
+ }
+ if (_outputTail > safeOutputEnd) { // need to flush
+ _flushBuffer();
+ }
+ int b24 = ((int) readBuffer[inputPtr++]) << 8;
+ b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ bytesLeft -= 3;
+ _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
+ if (--chunksBeforeLF <= 0) {
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = 'n';
+ chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+ }
+ }
+
+ // And then we may have 1 or 2 leftover bytes to encode
+ if (bytesLeft > 0) {
+ inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
+ inputPtr = 0;
+ if (inputEnd > 0) { // yes, but do we have room for output?
+ if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
+ _flushBuffer();
+ }
+ int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int amount;
+ if (inputPtr < inputEnd) {
+ b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ amount = 2;
+ } else {
+ amount = 1;
+ }
+ _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
+ bytesLeft -= amount;
+ }
+ }
+ return bytesLeft;
+ }
+
+ // write method when length is unknown
+ protected int _writeBinary(Base64Variant b64variant,
+ InputStream data, byte[] readBuffer)
+ throws IOException, JsonGenerationException
+ {
+ int inputPtr = 0;
+ int inputEnd = 0;
+ int lastFullOffset = -3;
+ int bytesDone = 0;
+
+ // Let's also reserve room for possible (and quoted) LF char each round
+ int safeOutputEnd = _outputEnd - 6;
+ int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+
+ // Ok, first we loop through all full triplets of data:
+ while (true) {
+ if (inputPtr > lastFullOffset) { // need to load more
+ inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
+ inputPtr = 0;
+ if (inputEnd < 3) { // required to try to read to have at least 3 bytes
+ break;
+ }
+ lastFullOffset = inputEnd-3;
+ }
+ if (_outputTail > safeOutputEnd) { // need to flush
+ _flushBuffer();
+ }
+ // First, mash 3 bytes into lsb of 32-bit int
+ int b24 = ((int) readBuffer[inputPtr++]) << 8;
+ b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ bytesDone += 3;
+ _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
+ if (--chunksBeforeLF <= 0) {
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = 'n';
+ chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+ }
+ }
+
+ // And then we may have 1 or 2 leftover bytes to encode
+ if (inputPtr < inputEnd) { // yes, but do we have room for output?
+ if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
+ _flushBuffer();
+ }
+ int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int amount = 1;
+ if (inputPtr < inputEnd) {
+ b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ amount = 2;
+ }
+ bytesDone += amount;
+ _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
+ }
+ return bytesDone;
+ }
+
+ private int _readMore(InputStream in,
+ byte[] readBuffer, int inputPtr, int inputEnd,
+ int maxRead) throws IOException
+ {
+ // anything to shift to front?
+ int i = 0;
+ while (inputPtr < inputEnd) {
+ readBuffer[i++] = readBuffer[inputPtr++];
+ }
+ inputPtr = 0;
+ inputEnd = i;
+ maxRead = Math.min(maxRead, readBuffer.length);
+
+ do {
+ int length = maxRead - inputEnd;
+ if (length == 0) {
+ break;
+ }
+ int count = in.read(readBuffer, inputEnd, length);
+ if (count < 0) {
+ return inputEnd;
+ }
+ inputEnd += count;
+ } while (inputEnd < 3);
+ return inputEnd;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, other
+ /**********************************************************
+ */
+
+ private final void _writeNull() throws IOException
+ {
+ if ((_outputTail + 4) >= _outputEnd) {
+ _flushBuffer();
+ }
+ int ptr = _outputTail;
+ char[] buf = _outputBuffer;
+ buf[ptr] = 'n';
+ buf[++ptr] = 'u';
+ buf[++ptr] = 'l';
+ buf[++ptr] = 'l';
+ _outputTail = ptr+1;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, escapes
+ /**********************************************************
+ */
+
+ /**
+ * Method called to try to either prepend character escape at front of
+ * given buffer; or if not possible, to write it out directly.
+ * Uses head and tail pointers (and updates as necessary)
+ */
+ private void _prependOrWriteCharacterEscape(char ch, int escCode)
+ throws IOException, JsonGenerationException
+ {
+ if (escCode >= 0) { // \\N (2 char)
+ if (_outputTail >= 2) { // fits, just prepend
+ int ptr = _outputTail - 2;
+ _outputHead = ptr;
+ _outputBuffer[ptr++] = '\\';
+ _outputBuffer[ptr] = (char) escCode;
+ return;
+ }
+ // won't fit, write
+ char[] buf = _entityBuffer;
+ if (buf == null) {
+ buf = _allocateEntityBuffer();
+ }
+ _outputHead = _outputTail;
+ buf[1] = (char) escCode;
+ _writer.write(buf, 0, 2);
+ return;
+ }
+ if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX
+ if (_outputTail >= 6) { // fits, prepend to buffer
+ char[] buf = _outputBuffer;
+ int ptr = _outputTail - 6;
+ _outputHead = ptr;
+ buf[ptr] = '\\';
+ buf[++ptr] = 'u';
+ // We know it's a control char, so only the last 2 chars are non-0
+ if (ch > 0xFF) { // beyond 8 bytes
+ int hi = (ch >> 8) & 0xFF;
+ buf[++ptr] = HEX_CHARS[hi >> 4];
+ buf[++ptr] = HEX_CHARS[hi & 0xF];
+ ch &= 0xFF;
+ } else {
+ buf[++ptr] = '0';
+ buf[++ptr] = '0';
+ }
+ buf[++ptr] = HEX_CHARS[ch >> 4];
+ buf[++ptr] = HEX_CHARS[ch & 0xF];
+ return;
+ }
+ // won't fit, flush and write
+ char[] buf = _entityBuffer;
+ if (buf == null) {
+ buf = _allocateEntityBuffer();
+ }
+ _outputHead = _outputTail;
+ if (ch > 0xFF) { // beyond 8 bytes
+ int hi = (ch >> 8) & 0xFF;
+ int lo = ch & 0xFF;
+ buf[10] = HEX_CHARS[hi >> 4];
+ buf[11] = HEX_CHARS[hi & 0xF];
+ buf[12] = HEX_CHARS[lo >> 4];
+ buf[13] = HEX_CHARS[lo & 0xF];
+ _writer.write(buf, 8, 6);
+ } else { // We know it's a control char, so only the last 2 chars are non-0
+ buf[6] = HEX_CHARS[ch >> 4];
+ buf[7] = HEX_CHARS[ch & 0xF];
+ _writer.write(buf, 2, 6);
+ }
+ return;
+ }
+ String escape;
+
+ if (_currentEscape == null) {
+ escape = _characterEscapes.getEscapeSequence(ch).getValue();
+ } else {
+ escape = _currentEscape.getValue();
+ _currentEscape = null;
+ }
+ int len = escape.length();
+ if (_outputTail >= len) { // fits in, prepend
+ int ptr = _outputTail - len;
+ _outputHead = ptr;
+ escape.getChars(0, len, _outputBuffer, ptr);
+ return;
+ }
+ // won't fit, write separately
+ _outputHead = _outputTail;
+ _writer.write(escape);
+ }
+
+ /**
+ * Method called to try to either prepend character escape at front of
+ * given buffer; or if not possible, to write it out directly.
+ *
+ * @return Pointer to start of prepended entity (if prepended); or 'ptr'
+ * if not.
+ */
+ private int _prependOrWriteCharacterEscape(char[] buffer, int ptr, int end,
+ char ch, int escCode)
+ throws IOException, JsonGenerationException
+ {
+ if (escCode >= 0) { // \\N (2 char)
+ if (ptr > 1 && ptr < end) { // fits, just prepend
+ ptr -= 2;
+ buffer[ptr] = '\\';
+ buffer[ptr+1] = (char) escCode;
+ } else { // won't fit, write
+ char[] ent = _entityBuffer;
+ if (ent == null) {
+ ent = _allocateEntityBuffer();
+ }
+ ent[1] = (char) escCode;
+ _writer.write(ent, 0, 2);
+ }
+ return ptr;
+ }
+ if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX
+ if (ptr > 5 && ptr < end) { // fits, prepend to buffer
+ ptr -= 6;
+ buffer[ptr++] = '\\';
+ buffer[ptr++] = 'u';
+ // We know it's a control char, so only the last 2 chars are non-0
+ if (ch > 0xFF) { // beyond 8 bytes
+ int hi = (ch >> 8) & 0xFF;
+ buffer[ptr++] = HEX_CHARS[hi >> 4];
+ buffer[ptr++] = HEX_CHARS[hi & 0xF];
+ ch &= 0xFF;
+ } else {
+ buffer[ptr++] = '0';
+ buffer[ptr++] = '0';
+ }
+ buffer[ptr++] = HEX_CHARS[ch >> 4];
+ buffer[ptr] = HEX_CHARS[ch & 0xF];
+ ptr -= 5;
+ } else {
+ // won't fit, flush and write
+ char[] ent = _entityBuffer;
+ if (ent == null) {
+ ent = _allocateEntityBuffer();
+ }
+ _outputHead = _outputTail;
+ if (ch > 0xFF) { // beyond 8 bytes
+ int hi = (ch >> 8) & 0xFF;
+ int lo = ch & 0xFF;
+ ent[10] = HEX_CHARS[hi >> 4];
+ ent[11] = HEX_CHARS[hi & 0xF];
+ ent[12] = HEX_CHARS[lo >> 4];
+ ent[13] = HEX_CHARS[lo & 0xF];
+ _writer.write(ent, 8, 6);
+ } else { // We know it's a control char, so only the last 2 chars are non-0
+ ent[6] = HEX_CHARS[ch >> 4];
+ ent[7] = HEX_CHARS[ch & 0xF];
+ _writer.write(ent, 2, 6);
+ }
+ }
+ return ptr;
+ }
+ String escape;
+ if (_currentEscape == null) {
+ escape = _characterEscapes.getEscapeSequence(ch).getValue();
+ } else {
+ escape = _currentEscape.getValue();
+ _currentEscape = null;
+ }
+ int len = escape.length();
+ if (ptr >= len && ptr < end) { // fits in, prepend
+ ptr -= len;
+ escape.getChars(0, len, buffer, ptr);
+ } else { // won't fit, write separately
+ _writer.write(escape);
+ }
+ return ptr;
+ }
+
+ /**
+ * Method called to append escape sequence for given character, at the
+ * end of standard output buffer; or if not possible, write out directly.
+ */
+ private void _appendCharacterEscape(char ch, int escCode)
+ throws IOException, JsonGenerationException
+ {
+ if (escCode >= 0) { // \\N (2 char)
+ if ((_outputTail + 2) > _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = (char) escCode;
+ return;
+ }
+ if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX
+ if ((_outputTail + 5) >= _outputEnd) {
+ _flushBuffer();
+ }
+ int ptr = _outputTail;
+ char[] buf = _outputBuffer;
+ buf[ptr++] = '\\';
+ buf[ptr++] = 'u';
+ // We know it's a control char, so only the last 2 chars are non-0
+ if (ch > 0xFF) { // beyond 8 bytes
+ int hi = (ch >> 8) & 0xFF;
+ buf[ptr++] = HEX_CHARS[hi >> 4];
+ buf[ptr++] = HEX_CHARS[hi & 0xF];
+ ch &= 0xFF;
+ } else {
+ buf[ptr++] = '0';
+ buf[ptr++] = '0';
+ }
+ buf[ptr++] = HEX_CHARS[ch >> 4];
+ buf[ptr++] = HEX_CHARS[ch & 0xF];
+ _outputTail = ptr;
+ return;
+ }
+ String escape;
+ if (_currentEscape == null) {
+ escape = _characterEscapes.getEscapeSequence(ch).getValue();
+ } else {
+ escape = _currentEscape.getValue();
+ _currentEscape = null;
+ }
+ int len = escape.length();
+ if ((_outputTail + len) > _outputEnd) {
+ _flushBuffer();
+ if (len > _outputEnd) { // very very long escape; unlikely but theoretically possible
+ _writer.write(escape);
+ return;
+ }
+ }
+ escape.getChars(0, len, _outputBuffer, _outputTail);
+ _outputTail += len;
+ }
+
+ private char[] _allocateEntityBuffer()
+ {
+ char[] buf = new char[14];
+ // first 2 chars, non-numeric escapes (like \n)
+ buf[0] = '\\';
+ // next 6; 8-bit escapes (control chars mostly)
+ buf[2] = '\\';
+ buf[3] = 'u';
+ buf[4] = '0';
+ buf[5] = '0';
+ // last 6, beyond 8 bits
+ buf[8] = '\\';
+ buf[9] = 'u';
+ _entityBuffer = buf;
+ return buf;
+ }
+
+ protected void _flushBuffer() throws IOException
+ {
+ int len = _outputTail - _outputHead;
+ if (len > 0) {
+ int offset = _outputHead;
+ _outputTail = _outputHead = 0;
+ _writer.write(_outputBuffer, offset, len);
+ }
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/package-info.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/package-info.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/package-info.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,7 @@
+/**
+ * JSON-specific parser and generator implementation classes that
+ * Jackson defines and uses.
+ * Application code should not (need to) use contents of this package;
+ * nor are these implementations likely to be of use for sub-classing.
+ */
+package com.fasterxml.jackson.core.json;
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/package-info.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/package-info.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/package-info.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,28 @@
+/**
+ * Main public API classes of the core streaming JSON
+ * processor: most importantly {@link com.fasterxml.jackson.core.JsonFactory}
+ * used for constructing
+ * JSON parser ({@link com.fasterxml.jackson.core.JsonParser})
+ * and generator
+ * ({@link com.fasterxml.jackson.core.JsonGenerator})
+ * instances.
+ *
+ * Public API of the higher-level mapping interfaces ("Mapping API")
+ * is found from the "jackson-databind" bundle, except for following
+ * base interfaces that are defined here:
+ *
+ * NOTE: non-final to allow disabling intern()ing in case of excessive
+ * collisions.
+ */
+ protected boolean _intern;
+
+ /**
+ * Flag that indicates whether we should throw an exception if enough
+ * hash collisions are detected (true); or just worked around (false).
+ *
+ * @since 2.4
+ */
+ protected final boolean _failOnDoS;
+
+ /*
+ /**********************************************************
+ /* First, main hash area info
+ /**********************************************************
+ */
+
+ /**
+ * Primary hash information area: consists of
+ * Default value is 2, for buckets of 4 slots; grows bigger with
+ * bigger table sizes.
+ */
+ protected int _tertiaryShift;
+
+ /**
+ * Total number of Strings in the symbol table; only used for child tables.
+ */
+ protected int _count;
+
+ /**
+ * Array that contains
+ * This flag needs to be checked both when adding new main entries,
+ * and when adding new collision list queues (i.e. creating a new
+ * collision list head entry)
+ */
+ private boolean _hashShared;
+
+ /*
+ /**********************************************************
+ /* Life-cycle: constructors
+ /**********************************************************
+ */
+
+ /**
+ * Constructor used for creating per-
+ * For optimal performance, usage pattern should be one where matches
+ * should be very common (especially after "warm-up"), and as with most hash-based
+ * maps/sets, that hash codes are uniformly distributed. Also, collisions
+ * are slightly more expensive than with HashMap or HashSet, since hash codes
+ * are not used in resolving collisions; that is, equals() comparison is
+ * done with all symbols in same bucket index.
+ * Usual usage pattern is to create a single "master" instance, and either
+ * use that instance in sequential fashion, or to create derived "child"
+ * instances, which after use, are asked to return possible symbol additions
+ * to master instance. In either case benefit is that symbol table gets
+ * initialized so that further uses are more efficient, as eventually all
+ * symbols needed will already be in symbol table. At that point no more
+ * Symbol String allocations are needed, nor changes to symbol table itself.
+ *
+ * Note that while individual SymbolTable instances are NOT thread-safe
+ * (much like generic collection classes), concurrently used "child"
+ * instances can be freely used without synchronization. However, using
+ * master table concurrently with child instances can only be done if
+ * access to master instance is read-only (i.e. no modifications done).
+ */
+public final class CharsToNameCanonicalizer
+{
+ /* If we use "multiply-add" based hash algorithm, this is the multiplier
+ * we use.
+ *
+ * Note that JDK uses 31; but it seems that 33 produces fewer collisions,
+ * at least with tests we have.
+ */
+ public final static int HASH_MULT = 33;
+
+ /**
+ * Default initial table size. Shouldn't be miniscule (as there's
+ * cost to both array realloc and rehashing), but let's keep
+ * it reasonably small. For systems that properly
+ * reuse factories it doesn't matter either way; but when
+ * recreating factories often, initial overhead may dominate.
+ */
+ protected static final int DEFAULT_T_SIZE = 64;
+
+ /**
+ * Let's not expand symbol tables past some maximum size;
+ * this should protected against OOMEs caused by large documents
+ * with unique (~= random) names.
+ */
+ protected static final int MAX_T_SIZE = 0x10000; // 64k entries == 256k mem
+
+ /**
+ * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 16k;
+ * this corresponds to 64k main hash index. This should allow for enough distinct
+ * names for almost any case.
+ */
+ final static int MAX_ENTRIES_FOR_REUSE = 12000;
+
+ /**
+ * Also: to thwart attacks based on hash collisions (which may or may not
+ * be cheap to calculate), we will need to detect "too long"
+ * collision chains. Let's start with static value of 255 entries
+ * for the longest legal chain.
+ *
+ * Note: longest chain we have been able to produce without malicious
+ * intent has been 38 (with "com.fasterxml.jackson.core.main.TestWithTonsaSymbols");
+ * our setting should be reasonable here.
+ *
+ * Also note that value was lowered from 255 (2.3 and earlier) to 100 for 2.4
+ *
+ * @since 2.1
+ */
+ final static int MAX_COLL_CHAIN_LENGTH = 100;
+
+ final static CharsToNameCanonicalizer sBootstrapSymbolTable = new CharsToNameCanonicalizer();
+
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Sharing of learnt symbols is done by optional linking of symbol
+ * table instances with their parents. When parent linkage is
+ * defined, and child instance is released (call to
+ * Note: Number of buckets is half of number of symbol entries, on
+ * assumption there's less need for buckets.
+ */
+ protected Bucket[] _buckets;
+
+ /**
+ * Current size (number of entries); needed to know if and when
+ * rehash.
+ */
+ protected int _size;
+
+ /**
+ * Limit that indicates maximum size this instance can hold before
+ * it needs to be expanded and rehashed. Calculated using fill
+ * factor passed in to constructor.
+ */
+ protected int _sizeThreshold;
+
+ /**
+ * Mask used to get index from hash values; equal to
+ *
+ * Note: while this method is synchronized, it is generally not
+ * safe to both use makeChild/mergeChild, AND to use instance
+ * actively. Instead, a separate 'root' instance should be used
+ * on which only makeChild/mergeChild are called, but instance itself
+ * is not used as a symbol table.
+ */
+ public CharsToNameCanonicalizer makeChild(int flags) {
+ /* 24-Jul-2012, tatu: Trying to reduce scope of synchronization, assuming
+ * that synchronizing construction is the (potentially) expensive part,
+ * and not so much short copy-the-variables thing.
+ */
+ final String[] symbols;
+ final Bucket[] buckets;
+ final int size;
+ final int hashSeed;
+ final int longestCollisionList;
+
+ synchronized (this) {
+ symbols = _symbols;
+ buckets = _buckets;
+ size = _size;
+ hashSeed = _hashSeed;
+ longestCollisionList = _longestCollisionList;
+ }
+ return new CharsToNameCanonicalizer(this, flags,
+ symbols, buckets, size, hashSeed, longestCollisionList);
+ }
+
+ private CharsToNameCanonicalizer makeOrphan(int seed) {
+ return new CharsToNameCanonicalizer(null, -1, _symbols, _buckets, _size, seed, _longestCollisionList);
+ }
+
+ /**
+ * Method that allows contents of child table to potentially be
+ * "merged in" with contents of this symbol table.
+ *
+ * Note that caller has to make sure symbol table passed in is
+ * really a child or sibling of this symbol table.
+ */
+ private void mergeChild(CharsToNameCanonicalizer child) {
+ /* One caveat: let's try to avoid problems with
+ * degenerate cases of documents with generated "random"
+ * names: for these, symbol tables would bloat indefinitely.
+ * One way to do this is to just purge tables if they grow
+ * too large, and that's what we'll do here.
+ */
+ if (child.size() > MAX_ENTRIES_FOR_REUSE) {
+ // Should there be a way to get notified about this event, to log it or such?
+ // (as it's somewhat abnormal thing to happen)
+ // At any rate, need to clean up the tables, then:
+ synchronized (this) {
+ initTables(DEFAULT_T_SIZE * 4); // no point in starting from tiny tho
+ // Dirty flag... well, let's just clear it. Shouldn't really matter for master tables
+ // (which this is, given something is merged to it)
+ _dirty = false;
+ }
+ } else {
+ // Otherwise, we'll merge changed stuff in, if there are more entries (which
+ // may not be the case if one of siblings has added symbols first or such)
+ if (child.size() <= size()) { // nothing to add
+ return;
+ }
+ // Okie dokie, let's get the data in!
+ synchronized (this) {
+ _symbols = child._symbols;
+ _buckets = child._buckets;
+ _size = child._size;
+ _sizeThreshold = child._sizeThreshold;
+ _indexMask = child._indexMask;
+ _longestCollisionList = child._longestCollisionList;
+ // Dirty flag... well, let's just clear it. Shouldn't really matter for master tables
+ // (which this is, given something is merged to it)
+ _dirty = false;
+ }
+ }
+ }
+
+ public void release(){
+ // If nothing has been added, nothing to do
+ if (!maybeDirty()) { return; }
+ if (_parent != null && _canonicalize) { // canonicalize set to false if max size was reached
+ _parent.mergeChild(this);
+ /* Let's also mark this instance as dirty, so that just in
+ * case release was too early, there's no corruption
+ * of possibly shared data.
+ */
+ _dirty = false;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, generic accessors:
+ /**********************************************************
+ */
+
+ public int size() { return _size; }
+
+ /**
+ * Method for checking number of primary hash buckets this symbol
+ * table uses.
+ *
+ * @since 2.1
+ */
+ public int bucketCount() { return _symbols.length; }
+ public boolean maybeDirty() { return _dirty; }
+ public int hashSeed() { return _hashSeed; }
+
+ /**
+ * Method mostly needed by unit tests; calculates number of
+ * entries that are in collision list. Value can be at most
+ * ({@link #size} - 1), but should usually be much lower, ideally 0.
+ *
+ * @since 2.1
+ */
+ public int collisionCount() {
+ int count = 0;
+
+ for (Bucket bucket : _buckets) {
+ if (bucket != null) {
+ count += bucket.length;
+ }
+ }
+ return count;
+ }
+
+ /**
+ * Method mostly needed by unit tests; calculates length of the
+ * longest collision chain. This should typically be a low number,
+ * but may be up to {@link #size} - 1 in the pathological case
+ *
+ * @since 2.1
+ */
+ public int maxCollisionLength() { return _longestCollisionList; }
+
+ /*
+ /**********************************************************
+ /* Public API, accessing symbols:
+ /**********************************************************
+ */
+
+ public String findSymbol(char[] buffer, int start, int len, int h)
+ {
+ if (len < 1) { // empty Strings are simplest to handle up front
+ return "";
+ }
+ if (!_canonicalize) { // [JACKSON-259]
+ return new String(buffer, start, len);
+ }
+
+ /* Related to problems with sub-standard hashing (somewhat
+ * relevant for collision attacks too), let's try little
+ * bit of shuffling to improve hash codes.
+ * (note, however, that this can't help with full collisions)
+ */
+ int index = _hashToIndex(h);
+ String sym = _symbols[index];
+
+ // Optimal case; checking existing primary symbol for hash index:
+ if (sym != null) {
+ // Let's inline primary String equality checking:
+ if (sym.length() == len) {
+ int i = 0;
+ while (sym.charAt(i) == buffer[start+i]) {
+ // Optimal case; primary match found
+ if (++i == len) {
+ return sym;
+ }
+ }
+ }
+ Bucket b = _buckets[index>>1];
+ if (b != null) {
+ sym = b.has(buffer, start, len);
+ if (sym != null) {
+ return sym;
+ }
+ sym = _findSymbol2(buffer, start, len, b.next);
+ if (sym != null) {
+ return sym;
+ }
+ }
+ }
+ return _addSymbol(buffer, start, len, h, index);
+ }
+
+ private String _findSymbol2(char[] buffer, int start, int len, Bucket b) {
+ while (b != null) {
+ String sym = b.has(buffer, start, len);
+ if (sym != null) {
+ return sym;
+ }
+ b = b.next;
+ }
+ return null;
+ }
+
+ private String _addSymbol(char[] buffer, int start, int len, int h, int index)
+ {
+ if (!_dirty) { //need to do copy-on-write?
+ copyArrays();
+ _dirty = true;
+ } else if (_size >= _sizeThreshold) { // Need to expand?
+ rehash();
+ /* Need to recalc hash; rare occurence (index mask has been
+ * recalculated as part of rehash)
+ */
+ index = _hashToIndex(calcHash(buffer, start, len));
+ }
+
+ String newSymbol = new String(buffer, start, len);
+ if (JsonFactory.Feature.INTERN_FIELD_NAMES.enabledIn(_flags)) {
+ newSymbol = InternCache.instance.intern(newSymbol);
+ }
+ ++_size;
+ // Ok; do we need to add primary entry, or a bucket?
+ if (_symbols[index] == null) {
+ _symbols[index] = newSymbol;
+ } else {
+ final int bix = (index >> 1);
+ Bucket newB = new Bucket(newSymbol, _buckets[bix]);
+ int collLen = newB.length;
+ if (collLen > MAX_COLL_CHAIN_LENGTH) {
+ /* 23-May-2014, tatu: Instead of throwing an exception right away, let's handle
+ * in bit smarter way.
+ */
+ _handleSpillOverflow(bix, newB);
+ } else {
+ _buckets[bix] = newB;
+ _longestCollisionList = Math.max(collLen, _longestCollisionList);
+ }
+ }
+
+ return newSymbol;
+ }
+
+ private void _handleSpillOverflow(int bindex, Bucket newBucket)
+ {
+ if (_overflows == null) {
+ _overflows = new BitSet();
+ _overflows.set(bindex);
+ } else {
+ if (_overflows.get(bindex)) {
+ // Has happened once already, so not a coincident...
+ if (JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW.enabledIn(_flags)) {
+ reportTooManyCollisions(MAX_COLL_CHAIN_LENGTH);
+ }
+ // but even if we don't fail, we will stop canonicalizing:
+ _canonicalize = false;
+ } else {
+ _overflows.set(bindex);
+ }
+ }
+ // regardless, if we get this far, clear up the bucket, adjust size appropriately.
+ _symbols[bindex + bindex] = newBucket.symbol;
+ _buckets[bindex] = null;
+ // newBucket contains new symbol; but we wil
+ _size -= (newBucket.length);
+ // we could calculate longest; but for now just mark as invalid
+ _longestCollisionList = -1;
+ }
+
+ /**
+ * Helper method that takes in a "raw" hash value, shuffles it as necessary,
+ * and truncates to be used as the index.
+ */
+ public int _hashToIndex(int rawHash) {
+ // doing these seems to help a bit
+ rawHash += (rawHash >>> 15);
+ rawHash ^= (rawHash << 7);
+ rawHash += (rawHash >>> 3);
+ return (rawHash & _indexMask);
+ }
+
+ /**
+ * Implementation of a hashing method for variable length
+ * Strings. Most of the time intention is that this calculation
+ * is done by caller during parsing, not here; however, sometimes
+ * it needs to be done for parsed "String" too.
+ *
+ * @param len Length of String; has to be at least 1 (caller guarantees
+ * this pre-condition)
+ */
+ public int calcHash(char[] buffer, int start, int len) {
+ int hash = _hashSeed;
+ for (int i = start, end = start+len; i < end; ++i) {
+ hash = (hash * HASH_MULT) + (int) buffer[i];
+ }
+ // NOTE: shuffling, if any, is done in 'findSymbol()', not here:
+ return (hash == 0) ? 1 : hash;
+ }
+
+ public int calcHash(String key)
+ {
+ final int len = key.length();
+
+ int hash = _hashSeed;
+ for (int i = 0; i < len; ++i) {
+ hash = (hash * HASH_MULT) + (int) key.charAt(i);
+ }
+ // NOTE: shuffling, if any, is done in 'findSymbol()', not here:
+ return (hash == 0) ? 1 : hash;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods
+ /**********************************************************
+ */
+
+ /**
+ * Method called when copy-on-write is needed; generally when first
+ * change is made to a derived symbol table.
+ */
+ private void copyArrays() {
+ final String[] oldSyms = _symbols;
+ _symbols = Arrays.copyOf(oldSyms, oldSyms.length);
+ final Bucket[] oldBuckets = _buckets;
+ _buckets = Arrays.copyOf(oldBuckets, oldBuckets.length);
+ }
+
+ /**
+ * Method called when size (number of entries) of symbol table grows
+ * so big that load factor is exceeded. Since size has to remain
+ * power of two, arrays will then always be doubled. Main work
+ * is really redistributing old entries into new String/Bucket
+ * entries.
+ */
+ private void rehash() {
+ int size = _symbols.length;
+ int newSize = size + size;
+
+ /* 12-Mar-2010, tatu: Let's actually limit maximum size we are
+ * prepared to use, to guard against OOME in case of unbounded
+ * name sets (unique [non-repeating] names)
+ */
+ if (newSize > MAX_T_SIZE) {
+ /* If this happens, there's no point in either growing or shrinking hash areas.
+ * Rather, let's just cut our losses and stop canonicalizing.
+ */
+ _size = 0;
+ _canonicalize = false;
+ // in theory, could just leave these as null, but...
+ _symbols = new String[DEFAULT_T_SIZE];
+ _buckets = new Bucket[DEFAULT_T_SIZE>>1];
+ _indexMask = DEFAULT_T_SIZE-1;
+ _dirty = true;
+ return;
+ }
+
+ String[] oldSyms = _symbols;
+ Bucket[] oldBuckets = _buckets;
+ _symbols = new String[newSize];
+ _buckets = new Bucket[newSize >> 1];
+ // Let's update index mask, threshold, now (needed for rehashing)
+ _indexMask = newSize - 1;
+ _sizeThreshold = _thresholdSize(newSize);
+
+ int count = 0; // let's do sanity check
+
+ /* Need to do two loops, unfortunately, since spill-over area is
+ * only half the size:
+ */
+ int maxColl = 0;
+ for (int i = 0; i < size; ++i) {
+ String symbol = oldSyms[i];
+ if (symbol != null) {
+ ++count;
+ int index = _hashToIndex(calcHash(symbol));
+ if (_symbols[index] == null) {
+ _symbols[index] = symbol;
+ } else {
+ int bix = (index >> 1);
+ Bucket newB = new Bucket(symbol, _buckets[bix]);
+ _buckets[bix] = newB;
+ maxColl = Math.max(maxColl, newB.length);
+ }
+ }
+ }
+
+ size >>= 1;
+ for (int i = 0; i < size; ++i) {
+ Bucket b = oldBuckets[i];
+ while (b != null) {
+ ++count;
+ String symbol = b.symbol;
+ int index = _hashToIndex(calcHash(symbol));
+ if (_symbols[index] == null) {
+ _symbols[index] = symbol;
+ } else {
+ int bix = (index >> 1);
+ Bucket newB = new Bucket(symbol, _buckets[bix]);
+ _buckets[bix] = newB;
+ maxColl = Math.max(maxColl, newB.length);
+ }
+ b = b.next;
+ }
+ }
+ _longestCollisionList = maxColl;
+ _overflows = null;
+
+ if (count != _size) {
+ throw new Error("Internal error on SymbolTable.rehash(): had "+_size+" entries; now have "+count+".");
+ }
+ }
+
+ /**
+ * @since 2.1
+ */
+ protected void reportTooManyCollisions(int maxLen) {
+ throw new IllegalStateException("Longest collision chain in symbol table (of size "+_size
+ +") now exceeds maximum, "+maxLen+" -- suspect a DoS attack based on hash collisions");
+ }
+
+ // For debugging, comment out
+ /*
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ int primaryCount = 0;
+ for (String s : _symbols) {
+ if (s != null) ++primaryCount;
+ }
+
+ sb.append("[BytesToNameCanonicalizer, size: ");
+ sb.append(_size);
+ sb.append('/');
+ sb.append(_symbols.length);
+ sb.append(", ");
+ sb.append(primaryCount);
+ sb.append('/');
+ sb.append(_size - primaryCount);
+ sb.append(" coll; avg length: ");
+
+ // Average length: minimum of 1 for all (1 == primary hit);
+ // and then 1 per each traversal for collisions/buckets
+ //int maxDist = 1;
+ int pathCount = _size;
+ for (Bucket b : _buckets) {
+ if (b != null) {
+ int spillLen = b.length;
+ for (int j = 1; j <= spillLen; ++j) {
+ pathCount += j;
+ }
+ }
+ }
+ double avgLength;
+
+ if (_size == 0) {
+ avgLength = 0.0;
+ } else {
+ avgLength = (double) pathCount / (double) _size;
+ }
+ // let's round up a bit (two 2 decimal places)
+ //avgLength -= (avgLength % 0.01);
+
+ sb.append(avgLength);
+ sb.append(']');
+ return sb.toString();
+ }
+*/
+
+ /*
+ /**********************************************************
+ /* Bucket class
+ /**********************************************************
+ */
+
+ /**
+ * This class is a symbol table entry. Each entry acts as a node
+ * in a linked list.
+ */
+ static final class Bucket
+ {
+ public final String symbol;
+ public final Bucket next;
+ public final int length;
+
+ public Bucket(String s, Bucket n) {
+ symbol = s;
+ next = n;
+ length = (n == null) ? 1 : n.length+1;
+ }
+
+ public String has(char[] buf, int start, int len) {
+ if (symbol.length() != len) {
+ return null;
+ }
+ int i = 0;
+ do {
+ if (symbol.charAt(i) != buf[start+i]) {
+ return null;
+ }
+ } while (++i < len);
+ return symbol;
+ }
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,55 @@
+package com.fasterxml.jackson.core.sym;
+
+/**
+ * Base class for tokenized names (key strings in objects) that have
+ * been tokenized from byte-based input sources (like
+ * {@link java.io.InputStream}.
+ *
+ * @author Tatu Saloranta
+ */
+public abstract class Name
+{
+ protected final String _name;
+
+ protected final int _hashCode;
+
+ protected Name(String name, int hashCode) {
+ _name = name;
+ _hashCode = hashCode;
+ }
+
+ public String getName() { return _name; }
+
+ /*
+ /**********************************************************
+ /* Methods for package/core parser
+ /**********************************************************
+ */
+
+ public abstract boolean equals(int q1);
+
+ public abstract boolean equals(int q1, int q2);
+
+ /**
+ * @since 2.6
+ */
+ public abstract boolean equals(int q1, int q2, int q3);
+
+ public abstract boolean equals(int[] quads, int qlen);
+
+ /*
+ /**********************************************************
+ /* Overridden standard methods
+ /**********************************************************
+ */
+
+ @Override public String toString() { return _name; }
+
+ @Override public final int hashCode() { return _hashCode; }
+
+ @Override public boolean equals(Object o)
+ {
+ // Canonical instances, can usually just do identity comparison
+ return (o == this);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name1.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name1.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name1.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,29 @@
+package com.fasterxml.jackson.core.sym;
+
+/**
+ * Specialized implementation of PName: can be used for short Strings
+ * that consists of at most 4 bytes. Usually this means short
+ * ascii-only names.
+ *
+ * The reason for such specialized classes is mostly space efficiency;
+ * and to a lesser degree performance. Both are achieved for short
+ * Strings by avoiding another level of indirection (via quad arrays)
+ */
+public final class Name1 extends Name
+{
+ private final static Name1 EMPTY = new Name1("", 0, 0);
+ private final int q;
+
+ Name1(String name, int hash, int quad) {
+ super(name, hash);
+ q = quad;
+ }
+
+ public static Name1 getEmptyName() { return EMPTY; }
+
+ @Override public boolean equals(int quad) { return (quad == q); }
+ @Override public boolean equals(int quad1, int quad2) { return (quad1 == q) && (quad2 == 0); }
+ @Override public boolean equals(int q1, int q2, int q3) { return false; }
+
+ @Override public boolean equals(int[] quads, int qlen) { return (qlen == 1 && quads[0] == q); }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name2.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name2.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name2.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,32 @@
+package com.fasterxml.jackson.core.sym;
+
+/**
+ * Specialized implementation of PName: can be used for short Strings
+ * that consists of 5 to 8 bytes. Usually this means relatively short
+ * ascii-only names.
+ *
+ * The reason for such specialized classes is mostly space efficiency;
+ * and to a lesser degree performance. Both are achieved for short
+ * Strings by avoiding another level of indirection (via quad arrays)
+ */
+public final class Name2 extends Name
+{
+ private final int q1, q2;
+
+ Name2(String name, int hash, int quad1, int quad2) {
+ super(name, hash);
+ q1 = quad1;
+ q2 = quad2;
+ }
+
+ @Override
+ public boolean equals(int quad) { return false; }
+
+ @Override
+ public boolean equals(int quad1, int quad2) { return (quad1 == q1) && (quad2 == q2); }
+
+ @Override public boolean equals(int quad1, int quad2, int q3) { return false; }
+
+ @Override
+ public boolean equals(int[] quads, int qlen) { return (qlen == 2 && quads[0] == q1 && quads[1] == q2); }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name3.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name3.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/Name3.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,36 @@
+package com.fasterxml.jackson.core.sym;
+
+/**
+ * Specialized implementation of PName: can be used for short Strings
+ * that consists of 9 to 12 bytes. It's the longest special purpose
+ * implementaion; longer ones are expressed using {@link NameN}.
+ */
+public final class Name3 extends Name
+{
+ private final int q1, q2, q3;
+
+ Name3(String name, int hash, int i1, int i2, int i3) {
+ super(name, hash);
+ q1 = i1;
+ q2 = i2;
+ q3 = i3;
+ }
+
+ // Implies quad length == 1, never matches
+ @Override
+ public boolean equals(int quad) { return false; }
+
+ // Implies quad length == 2, never matches
+ @Override
+ public boolean equals(int quad1, int quad2) { return false; }
+
+ @Override
+ public boolean equals(int quad1, int quad2, int quad3) {
+ return (q1 == quad1) && (q2 == quad2) && (q3 == quad3);
+ }
+
+ @Override
+ public boolean equals(int[] quads, int qlen) {
+ return (qlen == 3) && (quads[0] == q1) && (quads[1] == q2) && (quads[2] == q3);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/NameN.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/NameN.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/NameN.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,100 @@
+package com.fasterxml.jackson.core.sym;
+
+import java.util.Arrays;
+
+/**
+ * Generic implementation of PName used for "long" names, where long
+ * means that its byte (UTF-8) representation is 13 bytes or more.
+ */
+public final class NameN extends Name
+{
+ private final int q1, q2, q3, q4; // first four quads
+ private final int qlen; // total number of quads (4 + q.length)
+ private final int[] q;
+
+ NameN(String name, int hash, int q1, int q2, int q3, int q4,
+ int[] quads, int quadLen) {
+ super(name, hash);
+ this.q1 = q1;
+ this.q2 = q2;
+ this.q3 = q3;
+ this.q4 = q4;
+ q = quads;
+ qlen = quadLen;
+ }
+
+ public static NameN construct(String name, int hash, int[] q, int qlen)
+ {
+ /* We have specialized implementations for shorter
+ * names, so let's not allow runt instances here
+ */
+ if (qlen < 4) {
+ throw new IllegalArgumentException();
+ }
+ int q1 = q[0];
+ int q2 = q[1];
+ int q3 = q[2];
+ int q4 = q[3];
+
+ int rem = qlen - 4;
+
+ int[] buf;
+
+ if (rem > 0) {
+ buf = Arrays.copyOfRange(q, 4, qlen);
+ } else {
+ buf = null;
+ }
+ return new NameN(name, hash, q1, q2, q3, q4, buf, qlen);
+
+ }
+
+ // Implies quad length == 1, never matches
+ @Override
+ public boolean equals(int quad) { return false; }
+
+ // Implies quad length == 2, never matches
+ @Override
+ public boolean equals(int quad1, int quad2) { return false; }
+
+ // Implies quad length == 3, never matches
+ @Override
+ public boolean equals(int quad1, int quad2, int quad3) { return false; }
+
+ @Override
+ public boolean equals(int[] quads, int len) {
+ if (len != qlen) { return false; }
+
+ // Will always have >= 4 quads, can unroll
+ if (quads[0] != q1) return false;
+ if (quads[1] != q2) return false;
+ if (quads[2] != q3) return false;
+ if (quads[3] != q4) return false;
+
+ switch (len) {
+ default:
+ return _equals2(quads);
+ case 8:
+ if (quads[7] != q[3]) return false;
+ case 7:
+ if (quads[6] != q[2]) return false;
+ case 6:
+ if (quads[5] != q[1]) return false;
+ case 5:
+ if (quads[4] != q[0]) return false;
+ case 4:
+ }
+ return true;
+ }
+
+ private final boolean _equals2(int[] quads)
+ {
+ final int end = qlen-4;
+ for (int i = 0; i < end; ++i) {
+ if (quads[i+4] != q[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/package-info.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/package-info.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/package-info.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,5 @@
+/**
+ * Internal implementation classes for efficient handling of
+ * of symbols in JSON (field names in Objects)
+ */
+package com.fasterxml.jackson.core.sym;
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/type/ResolvedType.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/type/ResolvedType.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/type/ResolvedType.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,169 @@
+package com.fasterxml.jackson.core.type;
+
+/**
+ * Type abstraction that represents Java type that has been resolved
+ * (i.e. has all generic information, if any, resolved to concrete
+ * types).
+ * Note that this is an intermediate type, and all concrete instances
+ * MUST be of type
+ * For example: for type like {@link java.util.HashMap}, raw type is
+ * {@link java.util.HashMap}; but this method would return
+ * {@link java.util.Map}, because relevant type parameters that are
+ * resolved (and accessible using {@link #containedType(int)} and
+ * {@link #getKeyType()}) are parameter for {@link java.util.Map}
+ * (which may or may not be same as type parameters for subtype;
+ * in case of {@link java.util.HashMap} they are, but for further
+ * subtypes they may be different parameters or possibly none at all).
+ *
+ * @since 2.5
+ *
+ * @deprecated Since 2.7: does not have meaning as parameters depend on type
+ * resolved.
+ */
+ @Deprecated // since 2.7
+ public Class> getParameterSource() {
+ return null;
+ }
+
+ /**
+ * Method for accessing key type for this type, assuming type
+ * has such a concept (only Map types do)
+ */
+ public abstract ResolvedType getKeyType();
+
+ /**
+ * Method for accessing content type of this type, if type has
+ * such a thing: simple types do not, structured types do
+ * (like arrays, Collections and Maps)
+ */
+ public abstract ResolvedType getContentType();
+
+ /**
+ * Method for accessing type of value that instances of this
+ * type references, if any.
+ *
+ * @return Referenced type, if any; null if not.
+ *
+ * @since 2.6
+ */
+ public abstract ResolvedType getReferencedType();
+
+ /**
+ * Method for checking how many contained types this type
+ * has. Contained types are usually generic types, so that
+ * generic Maps have 2 contained types.
+ */
+ public abstract int containedTypeCount();
+
+ /**
+ * Method for accessing definitions of contained ("child")
+ * types.
+ *
+ * @param index Index of contained type to return
+ *
+ * @return Contained type at index, or null if no such type
+ * exists (no exception thrown)
+ */
+ public abstract ResolvedType containedType(int index);
+
+ /**
+ * Method for accessing name of type variable in indicated
+ * position. If no name is bound, will use placeholders (derived
+ * from 0-based index); if no type variable or argument exists
+ * with given index, null is returned.
+ *
+ * @param index Index of contained type to return
+ *
+ * @return Contained type at index, or null if no such type
+ * exists (no exception thrown)
+ */
+ public abstract String containedTypeName(int index);
+
+ /*
+ /**********************************************************
+ /* Public API, other
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to serialize type into form from which
+ * it can be fully deserialized from at a later point (using
+ *
+ * Usage is by sub-classing: here is one way to instantiate reference
+ * to generic type
+ * Also implements {@link OutputStream} to allow
+ * efficient aggregation of output content as a byte array, similar
+ * to how {@link java.io.ByteArrayOutputStream} works, but somewhat more
+ * efficiently for many use cases.
+ */
+public final class ByteArrayBuilder extends OutputStream
+{
+ public final static byte[] NO_BYTES = new byte[0];
+
+ // Size of the first block we will allocate.
+ private final static int INITIAL_BLOCK_SIZE = 500;
+
+ // Maximum block size we will use for individual non-aggregated
+ // blocks. Let's limit to using 256k chunks.
+ private final static int MAX_BLOCK_SIZE = (1 << 18);
+
+ final static int DEFAULT_BLOCK_ARRAY_SIZE = 40;
+
+ // Optional buffer recycler instance that we can use for allocating the first block.
+ private final BufferRecycler _bufferRecycler;
+ private final LinkedList
+ * Note: simply constructs a {@link SerializedString} out of parameter,
+ * calls {@link #DefaultPrettyPrinter(SerializableString)}
+ *
+ * @param rootSeparator
+ *
+ * @since 2.1
+ */
+ public DefaultPrettyPrinter(String rootSeparator) {
+ this((rootSeparator == null) ? null : new SerializedString(rootSeparator));
+ }
+
+ /**
+ * Constructor that specifies separator String to use between root values;
+ * if null, no separator is printed.
+ *
+ * @param rootSeparator
+ *
+ * @since 2.1
+ */
+ public DefaultPrettyPrinter(SerializableString rootSeparator) {
+ _rootSeparator = rootSeparator;
+ }
+
+ public DefaultPrettyPrinter(DefaultPrettyPrinter base) {
+ this(base, base._rootSeparator);
+ }
+
+ public DefaultPrettyPrinter(DefaultPrettyPrinter base,
+ SerializableString rootSeparator)
+ {
+ _arrayIndenter = base._arrayIndenter;
+ _objectIndenter = base._objectIndenter;
+ _spacesInObjectEntries = base._spacesInObjectEntries;
+ _nesting = base._nesting;
+
+ _rootSeparator = rootSeparator;
+ }
+
+ public DefaultPrettyPrinter withRootSeparator(SerializableString rootSeparator)
+ {
+ if (_rootSeparator == rootSeparator ||
+ (rootSeparator != null && rootSeparator.equals(_rootSeparator))) {
+ return this;
+ }
+ return new DefaultPrettyPrinter(this, rootSeparator);
+ }
+
+ /**
+ * @since 2.6.0
+ */
+ public DefaultPrettyPrinter withRootSeparator(String rootSeparator) {
+ return withRootSeparator((rootSeparator == null) ? null : new SerializedString(rootSeparator));
+ }
+
+ public void indentArraysWith(Indenter i) {
+ _arrayIndenter = (i == null) ? NopIndenter.instance : i;
+ }
+
+ public void indentObjectsWith(Indenter i) {
+ _objectIndenter = (i == null) ? NopIndenter.instance : i;
+ }
+
+ /**
+ * @deprecated Since 2.3 use {@link #withSpacesInObjectEntries} and {@link #withoutSpacesInObjectEntries()}
+ */
+ @Deprecated
+ public void spacesInObjectEntries(boolean b) { _spacesInObjectEntries = b; }
+
+ /**
+ * @since 2.3
+ */
+ public DefaultPrettyPrinter withArrayIndenter(Indenter i) {
+ if (i == null) {
+ i = NopIndenter.instance;
+ }
+ if (_arrayIndenter == i) {
+ return this;
+ }
+ DefaultPrettyPrinter pp = new DefaultPrettyPrinter(this);
+ pp._arrayIndenter = i;
+ return pp;
+ }
+
+ /**
+ * @since 2.3
+ */
+ public DefaultPrettyPrinter withObjectIndenter(Indenter i) {
+ if (i == null) {
+ i = NopIndenter.instance;
+ }
+ if (_objectIndenter == i) {
+ return this;
+ }
+ DefaultPrettyPrinter pp = new DefaultPrettyPrinter(this);
+ pp._objectIndenter = i;
+ return pp;
+ }
+
+ /**
+ * "Mutant factory" method that will return a pretty printer instance
+ * that does use spaces inside object entries; if 'this' instance already
+ * does this, it is returned; if not, a new instance will be constructed
+ * and returned.
+ *
+ * @since 2.3
+ */
+ public DefaultPrettyPrinter withSpacesInObjectEntries() {
+ return _withSpaces(true);
+ }
+
+ /**
+ * "Mutant factory" method that will return a pretty printer instance
+ * that does not use spaces inside object entries; if 'this' instance already
+ * does this, it is returned; if not, a new instance will be constructed
+ * and returned.
+ *
+ * @since 2.3
+ */
+ public DefaultPrettyPrinter withoutSpacesInObjectEntries() {
+ return _withSpaces(false);
+ }
+
+ protected DefaultPrettyPrinter _withSpaces(boolean state)
+ {
+ if (_spacesInObjectEntries == state) {
+ return this;
+ }
+ DefaultPrettyPrinter pp = new DefaultPrettyPrinter(this);
+ pp._spacesInObjectEntries = state;
+ return pp;
+ }
+
+ /*
+ /**********************************************************
+ /* Instantiatable impl
+ /**********************************************************
+ */
+
+ @Override
+ public DefaultPrettyPrinter createInstance() {
+ return new DefaultPrettyPrinter(this);
+ }
+
+ /*
+ /**********************************************************
+ /* PrettyPrinter impl
+ /**********************************************************
+ */
+
+ @Override
+ public void writeRootValueSeparator(JsonGenerator jg) throws IOException
+ {
+ if (_rootSeparator != null) {
+ jg.writeRaw(_rootSeparator);
+ }
+ }
+
+ @Override
+ public void writeStartObject(JsonGenerator jg) throws IOException
+ {
+ jg.writeRaw('{');
+ if (!_objectIndenter.isInline()) {
+ ++_nesting;
+ }
+ }
+
+ @Override
+ public void beforeObjectEntries(JsonGenerator jg) throws IOException
+ {
+ _objectIndenter.writeIndentation(jg, _nesting);
+ }
+
+ /**
+ * Method called after an object field has been output, but
+ * before the value is output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * colon to separate the two. Pretty-printer is
+ * to output a colon as well, but can surround that with other
+ * (white-space) decoration.
+ */
+ @Override
+ public void writeObjectFieldValueSeparator(JsonGenerator jg) throws IOException
+ {
+ if (_spacesInObjectEntries) {
+ jg.writeRaw(" : ");
+ } else {
+ jg.writeRaw(':');
+ }
+ }
+
+ /**
+ * Method called after an object entry (field:value) has been completely
+ * output, and before another value is to be output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * comma to separate the two. Pretty-printer is
+ * to output a comma as well, but can surround that with other
+ * (white-space) decoration.
+ */
+ @Override
+ public void writeObjectEntrySeparator(JsonGenerator jg) throws IOException
+ {
+ jg.writeRaw(',');
+ _objectIndenter.writeIndentation(jg, _nesting);
+ }
+
+ @Override
+ public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException
+ {
+ if (!_objectIndenter.isInline()) {
+ --_nesting;
+ }
+ if (nrOfEntries > 0) {
+ _objectIndenter.writeIndentation(jg, _nesting);
+ } else {
+ jg.writeRaw(' ');
+ }
+ jg.writeRaw('}');
+ }
+
+ @Override
+ public void writeStartArray(JsonGenerator jg) throws IOException
+ {
+ if (!_arrayIndenter.isInline()) {
+ ++_nesting;
+ }
+ jg.writeRaw('[');
+ }
+
+ @Override
+ public void beforeArrayValues(JsonGenerator jg) throws IOException {
+ _arrayIndenter.writeIndentation(jg, _nesting);
+ }
+
+ /**
+ * Method called after an array value has been completely
+ * output, and before another value is to be output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * comma to separate the two. Pretty-printer is
+ * to output a comma as well, but can surround that with other
+ * (white-space) decoration.
+ */
+ @Override
+ public void writeArrayValueSeparator(JsonGenerator gen) throws IOException
+ {
+ gen.writeRaw(',');
+ _arrayIndenter.writeIndentation(gen, _nesting);
+ }
+
+ @Override
+ public void writeEndArray(JsonGenerator gen, int nrOfValues) throws IOException
+ {
+ if (!_arrayIndenter.isInline()) {
+ --_nesting;
+ }
+ if (nrOfValues > 0) {
+ _arrayIndenter.writeIndentation(gen, _nesting);
+ } else {
+ gen.writeRaw(' ');
+ }
+ gen.writeRaw(']');
+ }
+
+ /*
+ /**********************************************************
+ /* Helper classes
+ /**********************************************************
+ */
+
+ /**
+ * Dummy implementation that adds no indentation whatsoever
+ */
+ public static class NopIndenter
+ implements Indenter, java.io.Serializable
+ {
+ public static final NopIndenter instance = new NopIndenter();
+
+ @Override
+ public void writeIndentation(JsonGenerator jg, int level) throws IOException { }
+
+ @Override
+ public boolean isInline() { return true; }
+ }
+
+ /**
+ * This is a very simple indenter that only adds a
+ * single space for indentation. It is used as the default
+ * indenter for array values.
+ */
+ public static class FixedSpaceIndenter extends NopIndenter
+ {
+ @SuppressWarnings("hiding")
+ public static final FixedSpaceIndenter instance = new FixedSpaceIndenter();
+
+ @Override
+ public void writeIndentation(JsonGenerator jg, int level) throws IOException
+ {
+ jg.writeRaw(' ');
+ }
+
+ @Override
+ public boolean isInline() { return true; }
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/Instantiatable.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/Instantiatable.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/Instantiatable.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,24 @@
+package com.fasterxml.jackson.core.util;
+
+/**
+ * Add-on interface used to indicate things that may be "blueprint" objects
+ * which can not be used as is, but are used for creating usable per-process
+ * (serialization, deserialization) instances, using
+ * {@link #createInstance} method.
+ *
+ * Note that some implementations may choose to implement {@link #createInstance}
+ * by simply returning 'this': this is acceptable if instances are stateless.
+ *
+ * @see DefaultPrettyPrinter
+ *
+ * @since 2.1
+ */
+public interface Instantiatable
+ * Note: that this class extends {@link LinkedHashMap} is an implementation
+ * detail -- no code should ever directly call Map methods.
+ */
+@SuppressWarnings("serial")
+public final class InternCache
+ extends ConcurrentHashMap
+ * One consideration is possible attack via colliding {@link String#hashCode};
+ * because of this, limit to reasonably low setting.
+ */
+ private final static int MAX_ENTRIES = 180;
+
+ public final static InternCache instance = new InternCache();
+
+ /**
+ * As minor optimization let's try to avoid "flush storms",
+ * cases where multiple threads might try to concurrently
+ * flush the map.
+ */
+ private final Object lock = new Object();
+
+ private InternCache() { super(MAX_ENTRIES, 0.8f, 4); }
+
+ public String intern(String input) {
+ String result = get(input);
+ if (result != null) { return result; }
+
+ /* 18-Sep-2013, tatu: We used to use LinkedHashMap, which has simple LRU
+ * method. No such functionality exists with CHM; and let's use simplest
+ * possible limitation: just clear all contents. This because otherwise
+ * we are simply likely to keep on clearing same, commonly used entries.
+ */
+ if (size() >= MAX_ENTRIES) {
+ /* Not incorrect wrt well-known double-locking anti-pattern because underlying
+ * storage gives close enough answer to real one here; and we are
+ * more concerned with flooding than starvation.
+ */
+ synchronized (lock) {
+ if (size() >= MAX_ENTRIES) {
+ clear();
+ }
+ }
+ }
+ result = input.intern();
+ put(result, result);
+ return result;
+ }
+}
+
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonGeneratorDelegate.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,421 @@
+package com.fasterxml.jackson.core.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.io.CharacterEscapes;
+
+public class JsonGeneratorDelegate extends JsonGenerator
+{
+ /**
+ * Delegate object that method calls are delegated to.
+ */
+ protected JsonGenerator delegate;
+
+ /**
+ * Whether copy methods
+ * ({@link #copyCurrentEvent}, {@link #copyCurrentStructure}, {@link #writeTree} and {@link #writeObject})
+ * are to be called (true), or handled by this object (false).
+ */
+ protected boolean delegateCopyMethods;
+
+ /*
+ /**********************************************************
+ /* Construction, initialization
+ /**********************************************************
+ */
+
+ public JsonGeneratorDelegate(JsonGenerator d) {
+ this(d, true);
+ }
+
+ /**
+ * @param delegateCopyMethods Flag assigned to
+ * Fairly simple use of {@link JsonParserDelegate}: only need
+ * to override {@link #nextToken} to handle transition
+ */
+public class JsonParserSequence extends JsonParserDelegate
+{
+ /**
+ * Parsers other than the first one (which is initially assigned
+ * as delegate)
+ */
+ protected final JsonParser[] _parsers;
+
+ /**
+ * Index of the next parser in {@link #_parsers}.
+ */
+ protected int _nextParser;
+
+ /*
+ *******************************************************
+ * Construction
+ *******************************************************
+ */
+
+ protected JsonParserSequence(JsonParser[] parsers)
+ {
+ super(parsers[0]);
+ _parsers = parsers;
+ _nextParser = 1;
+ }
+
+ /**
+ * Method that will construct a parser (possibly a sequence) that
+ * contains all given sub-parsers.
+ * All parsers given are checked to see if they are sequences: and
+ * if so, they will be "flattened", that is, contained parsers are
+ * directly added in a new sequence instead of adding sequences
+ * within sequences. This is done to minimize delegation depth,
+ * ideally only having just a single level of delegation.
+ */
+ public static JsonParserSequence createFlattened(JsonParser first, JsonParser second)
+ {
+ if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) {
+ // simple:
+ return new JsonParserSequence(new JsonParser[] { first, second });
+ }
+ ArrayList
+ * Beyond purely minimal implementation, there is limited amount of
+ * configurability which may be useful for actual use: for example,
+ * it is possible to redefine separator used between root-level
+ * values (default is single space; can be changed to line-feed).
+ *
+ * Note: does NOT implement {@link Instantiatable} since this is
+ * a stateless implementation; that is, a single instance can be
+ * shared between threads.
+ */
+public class MinimalPrettyPrinter
+ implements PrettyPrinter, java.io.Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Default String used for separating root values is single space.
+ */
+ public final static String DEFAULT_ROOT_VALUE_SEPARATOR = " ";
+
+ protected String _rootValueSeparator = DEFAULT_ROOT_VALUE_SEPARATOR;
+
+ /*
+ /**********************************************************
+ /* Life-cycle, construction, configuration
+ /**********************************************************
+ */
+
+ public MinimalPrettyPrinter() {
+ this(DEFAULT_ROOT_VALUE_SEPARATOR);
+ }
+
+ public MinimalPrettyPrinter(String rootValueSeparator) {
+ _rootValueSeparator = rootValueSeparator;
+ }
+
+ public void setRootValueSeparator(String sep) {
+ _rootValueSeparator = sep;
+ }
+
+ /*
+ /**********************************************************
+ /* PrettyPrinter impl
+ /**********************************************************
+ */
+
+ @Override
+ public void writeRootValueSeparator(JsonGenerator jg) throws IOException, JsonGenerationException
+ {
+ if (_rootValueSeparator != null) {
+ jg.writeRaw(_rootValueSeparator);
+ }
+ }
+
+ @Override
+ public void writeStartObject(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw('{');
+ }
+
+ @Override
+ public void beforeObjectEntries(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ // nothing special, since no indentation is added
+ }
+
+ /**
+ * Method called after an object field has been output, but
+ * before the value is output.
+ *
+ * Default handling will just output a single
+ * colon to separate the two, without additional spaces.
+ */
+ @Override
+ public void writeObjectFieldValueSeparator(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw(':');
+ }
+
+ /**
+ * Method called after an object entry (field:value) has been completely
+ * output, and before another value is to be output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * comma to separate the two.
+ */
+ @Override
+ public void writeObjectEntrySeparator(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw(',');
+ }
+
+ @Override
+ public void writeEndObject(JsonGenerator jg, int nrOfEntries)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw('}');
+ }
+
+ @Override
+ public void writeStartArray(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw('[');
+ }
+
+ @Override
+ public void beforeArrayValues(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ // nothing special, since no indentation is added
+ }
+
+ /**
+ * Method called after an array value has been completely
+ * output, and before another value is to be output.
+ *
+ * Default handling (without pretty-printing) will output a single
+ * comma to separate values.
+ */
+ @Override
+ public void writeArrayValueSeparator(JsonGenerator jg)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw(',');
+ }
+
+ @Override
+ public void writeEndArray(JsonGenerator jg, int nrOfValues)
+ throws IOException, JsonGenerationException
+ {
+ jg.writeRaw(']');
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/TextBuffer.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/TextBuffer.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/TextBuffer.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,740 @@
+package com.fasterxml.jackson.core.util;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import com.fasterxml.jackson.core.io.NumberInput;
+
+/**
+ * TextBuffer is a class similar to {@link StringBuffer}, with
+ * following differences:
+ *
+ * Note that this class can be used in two roles: first, as a static
+ * utility class for loading purposes, and second, as a singleton
+ * loader of per-module version information.
+ *
+ * Note that method for accessing version information changed between versions
+ * 2.1 and 2.2; earlier code used file named "VERSION.txt"; but this has serious
+ * performance issues on some platforms (Android), so a replacement system
+ * was implemented to use class generation and dynamic class loading.
+ *
+ * Note that functionality for reading "VERSION.txt" was removed completely
+ * from Jackson 2.6.
+ */
+public class VersionUtil
+{
+ private final static Pattern V_SEP = Pattern.compile("[-_./;:]");
+
+ private final Version _v;
+
+ /*
+ /**********************************************************
+ /* Instance life-cycle
+ /**********************************************************
+ */
+
+ protected VersionUtil()
+ {
+ Version v = null;
+ try {
+ /* Class we pass only matters for resource-loading: can't use this Class
+ * (as it's just being loaded at this point), nor anything that depends on it.
+ */
+ v = VersionUtil.versionFor(getClass());
+ } catch (Exception e) { // not good to dump to stderr; but that's all we have at this low level
+ System.err.println("ERROR: Failed to load Version information from "+getClass());
+ }
+ if (v == null) {
+ v = Version.unknownVersion();
+ }
+ _v = v;
+ }
+
+ public Version version() { return _v; }
+
+ /*
+ /**********************************************************
+ /* Static load methods
+ /**********************************************************
+ */
+
+ /**
+ * Helper method that will try to load version information for specified
+ * class. Implementation is as follows:
+ *
+ * First, tries to load version info from a class named
+ * "PackageVersion" in the same package as the class.
+ *
+ * If no version information is found, {@link Version#unknownVersion()} is returned.
+ */
+ public static Version versionFor(Class> cls)
+ {
+ Version version = packageVersionFor(cls);
+ return version == null ? Version.unknownVersion() : version;
+ }
+
+ /**
+ * Loads version information by introspecting a class named
+ * "PackageVersion" in the same package as the given class.
+ *
+ * If the class could not be found or does not have a public
+ * static Version field named "VERSION", returns null.
+ */
+ public static Version packageVersionFor(Class> cls)
+ {
+ Version v = null;
+ try {
+ String versionInfoClassName = cls.getPackage().getName() + ".PackageVersion";
+ Class> vClass = Class.forName(versionInfoClassName, true, cls.getClassLoader());
+ // However, if class exists, it better work correctly, no swallowing exceptions
+ try {
+ v = ((Versioned) vClass.newInstance()).version();
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to get Versioned out of "+vClass);
+ }
+ } catch (Exception e) { // ok to be missing (not good but acceptable)
+ ;
+ }
+ return (v == null) ? Version.unknownVersion() : v;
+ }
+
+ /**
+ * Will attempt to load the maven version for the given groupId and
+ * artifactId. Maven puts a pom.properties file in
+ * META-INF/maven/groupId/artifactId, containing the groupId,
+ * artifactId and version of the library.
+ *
+ * @param cl the ClassLoader to load the pom.properties file from
+ * @param groupId the groupId of the library
+ * @param artifactId the artifactId of the library
+ * @return The version
+ *
+ * @deprecated Since 2.6: functionality not used by any official Jackson component, should be
+ * moved out if anyone needs it
+ */
+ @SuppressWarnings("resource")
+ @Deprecated // since 2.6
+ public static Version mavenVersionFor(ClassLoader cl, String groupId, String artifactId)
+ {
+ InputStream pomProperties = cl.getResourceAsStream("META-INF/maven/"
+ + groupId.replaceAll("\\.", "/")+ "/" + artifactId + "/pom.properties");
+ if (pomProperties != null) {
+ try {
+ Properties props = new Properties();
+ props.load(pomProperties);
+ String versionStr = props.getProperty("version");
+ String pomPropertiesArtifactId = props.getProperty("artifactId");
+ String pomPropertiesGroupId = props.getProperty("groupId");
+ return parseVersion(versionStr, pomPropertiesGroupId, pomPropertiesArtifactId);
+ } catch (IOException e) {
+ // Ignore
+ } finally {
+ _close(pomProperties);
+ }
+ }
+ return Version.unknownVersion();
+ }
+
+ /**
+ * Method used by
+ * Note that this method does not necessarily have to do full resolution
+ * of bindings; that is, it is legal to return type that could be further
+ * resolved: caller is expected to keep calling this method on registered
+ * resolvers, until a concrete type is located.
+ *
+ * @param config Configuration in use; should always be of type
+ *
+ * Default implementation will call obsolete method for Jackson 2.7,
+ * to try to keep some level of backwards compatibility.
+ *
+ * @param config Configuration in use; should always be of type
+ *
+ * Although default implementations are based on using annotations as the only
+ * (or at least main) information source, custom implementations are not limited
+ * in such a way, and in fact there is no expectation they should be. So the name
+ * is bit of misnomer; this is a general configuration introspection facility.
+ *
+ * NOTE: due to rapid addition of new methods (and changes to existing methods),
+ * it is strongly recommended that custom implementations should not directly
+ * extend this class, but rather extend {@link NopAnnotationIntrospector}.
+ * This way added methods will not break backwards compatibility of custom annotation
+ * introspectors.
+ */
+@SuppressWarnings("serial")
+public abstract class AnnotationIntrospector
+ implements Versioned, java.io.Serializable
+{
+ /*
+ /**********************************************************
+ /* Helper types
+ /**********************************************************
+ */
+
+ /**
+ * Value type used with managed and back references; contains type and
+ * logic name, used to link related references
+ */
+ public static class ReferenceProperty
+ {
+ public enum Type {
+ /**
+ * Reference property that Jackson manages and that is serialized normally (by serializing
+ * reference object), but is used for resolving back references during
+ * deserialization.
+ * Usually this can be defined by using
+ * {@link com.fasterxml.jackson.annotation.JsonManagedReference}
+ */
+ MANAGED_REFERENCE
+
+ /**
+ * Reference property that Jackson manages by suppressing it during serialization,
+ * and reconstructing during deserialization.
+ * Usually this can be defined by using
+ * {@link com.fasterxml.jackson.annotation.JsonBackReference}
+ */
+ ,BACK_REFERENCE
+ ;
+ }
+
+ private final Type _type;
+ private final String _name;
+
+ public ReferenceProperty(Type t, String n) {
+ _type = t;
+ _name = n;
+ }
+
+ public static ReferenceProperty managed(String name) { return new ReferenceProperty(Type.MANAGED_REFERENCE, name); }
+ public static ReferenceProperty back(String name) { return new ReferenceProperty(Type.BACK_REFERENCE, name); }
+
+ public Type getType() { return _type; }
+ public String getName() { return _name; }
+
+ public boolean isManagedReference() { return _type == Type.MANAGED_REFERENCE; }
+ public boolean isBackReference() { return _type == Type.BACK_REFERENCE; }
+ }
+
+ /*
+ /**********************************************************
+ /* Factory methods
+ /**********************************************************
+ */
+
+ /**
+ * Factory method for accessing "no operation" implementation
+ * of introspector: instance that will never find any annotation-based
+ * configuration.
+ */
+ public static AnnotationIntrospector nopInstance() {
+ return NopAnnotationIntrospector.instance;
+ }
+
+ public static AnnotationIntrospector pair(AnnotationIntrospector a1, AnnotationIntrospector a2) {
+ return new AnnotationIntrospectorPair(a1, a2);
+ }
+
+ /*
+ /**********************************************************
+ /* Access to possibly chained introspectors
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to collect all "real" introspectors that
+ * this introspector contains, if any; or this introspector
+ * if it is not a container. Used to get access to all container
+ * introspectors in their priority order.
+ *
+ * Default implementation returns a Singleton list with this introspector
+ * as contents.
+ * This usually works for sub-classes, except for proxy or delegating "container
+ * introspectors" which need to override implementation.
+ */
+ public Collection
+ * Default implementation adds this introspector in result; this usually
+ * works for sub-classes, except for proxy or delegating "container
+ * introspectors" which need to override implementation.
+ */
+ public Collection
+ * NOTE: method signature changed in 2.1, to return {@link PropertyName}
+ * instead of String.
+ */
+ public PropertyName findRootName(AnnotatedClass ac) {
+ return null;
+ }
+
+ /**
+ * Method for finding list of properties to ignore for given class
+ * (null is returned if not specified).
+ * List of property names is applied
+ * after other detection mechanisms, to filter out these specific
+ * properties from being serialized and deserialized.
+ *
+ * @param forSerialization True if requesting properties to ignore for serialization;
+ * false if for deserialization
+ */
+ public String[] findPropertiesToIgnore(Annotated ac, boolean forSerialization) {
+ return null;
+ }
+
+ /**
+ * @deprecated Since 2.6, use variant that takes second argument.
+ */
+ @Deprecated
+ public String[] findPropertiesToIgnore(Annotated ac) {
+ // Changed in 2.7 to call from old to new; with 2.6 was opposite
+ return findPropertiesToIgnore(ac, true);
+ }
+
+ /**
+ * Method for checking whether an annotation indicates that all unknown properties
+ */
+ public Boolean findIgnoreUnknownProperties(AnnotatedClass ac) { return null; }
+
+ /**
+ * Method for checking whether properties that have specified type
+ * (class, not generics aware) should be completely ignored for
+ * serialization and deserialization purposes.
+ *
+ * @param ac Type to check
+ *
+ * @return Boolean.TRUE if properties of type should be ignored;
+ * Boolean.FALSE if they are not to be ignored, null for default
+ * handling (which is 'do not ignore')
+ */
+ public Boolean isIgnorableType(AnnotatedClass ac) { return null; }
+
+ /**
+ * Method for finding if annotated class has associated filter; and if so,
+ * to return id that is used to locate filter.
+ *
+ * @return Id of the filter to use for filtering properties of annotated
+ * class, if any; or null if none found.
+ */
+ public Object findFilterId(Annotated ann) { return null; }
+
+ /**
+ * Method for finding {@link PropertyNamingStrategy} for given
+ * class, if any specified by annotations; and if so, either return
+ * a {@link PropertyNamingStrategy} instance, or Class to use for
+ * creating instance
+ *
+ * @return Sub-class or instance of {@link PropertyNamingStrategy}, if one
+ * is specified for given class; null if not.
+ *
+ * @since 2.1
+ */
+ public Object findNamingStrategy(AnnotatedClass ac) { return null; }
+
+ /**
+ * Method used to check whether specified class defines a human-readable
+ * description to use for documentation.
+ * There are no further definitions for contents; for example, whether
+ * these may be marked up using HTML (or something like wiki format like Markup)
+ * is not defined.
+ *
+ * @return Human-readable description, if any.
+ *
+ * @since 2.7
+ */
+ public String findClassDescription(AnnotatedClass ac) { return null; }
+
+ /*
+ /**********************************************************
+ /* Property auto-detection
+ /**********************************************************
+ */
+
+ /**
+ * Method for checking if annotations indicate changes to minimum visibility levels
+ * needed for auto-detecting property elements (fields, methods, constructors).
+ * A baseline checker is given, and introspector is to either return it as is
+ * (if no annotations are found), or build and return a derived instance (using
+ * checker's build methods).
+ */
+ public VisibilityChecker> findAutoDetectVisibility(AnnotatedClass ac, VisibilityChecker> checker) {
+ return checker;
+ }
+
+ /*
+ /**********************************************************
+ /* Annotations for Polymorphic type handling
+ /**********************************************************
+ */
+
+ /**
+ * Method for checking if given class has annotations that indicate
+ * that specific type resolver is to be used for handling instances.
+ * This includes not only
+ * instantiating resolver builder, but also configuring it based on
+ * relevant annotations (not including ones checked with a call to
+ * {@link #findSubtypes}
+ *
+ * @param config Configuration settings in effect (for serialization or deserialization)
+ * @param ac Annotated class to check for annotations
+ * @param baseType Base java type of value for which resolver is to be found
+ *
+ * @return Type resolver builder for given type, if one found; null if none
+ */
+ public TypeResolverBuilder> findTypeResolver(MapperConfig> config,
+ AnnotatedClass ac, JavaType baseType) {
+ return null;
+ }
+
+ /**
+ * Method for checking if given property entity (field or method) has annotations
+ * that indicate that specific type resolver is to be used for handling instances.
+ * This includes not only
+ * instantiating resolver builder, but also configuring it based on
+ * relevant annotations (not including ones checked with a call to
+ * {@link #findSubtypes}
+ *
+ * @param config Configuration settings in effect (for serialization or deserialization)
+ * @param am Annotated member (field or method) to check for annotations
+ * @param baseType Base java type of property for which resolver is to be found
+ *
+ * @return Type resolver builder for properties of given entity, if one found;
+ * null if none
+ */
+ public TypeResolverBuilder> findPropertyTypeResolver(MapperConfig> config,
+ AnnotatedMember am, JavaType baseType) {
+ return null;
+ }
+
+ /**
+ * Method for checking if given structured property entity (field or method that
+ * has nominal value of Map, Collection or array type) has annotations
+ * that indicate that specific type resolver is to be used for handling type
+ * information of contained values.
+ * This includes not only
+ * instantiating resolver builder, but also configuring it based on
+ * relevant annotations (not including ones checked with a call to
+ * {@link #findSubtypes}
+ *
+ * @param config Configuration settings in effect (for serialization or deserialization)
+ * @param am Annotated member (field or method) to check for annotations
+ * @param containerType Type of property for which resolver is to be found (must be a container type)
+ *
+ * @return Type resolver builder for values contained in properties of given entity,
+ * if one found; null if none
+ */
+ public TypeResolverBuilder> findPropertyContentTypeResolver(MapperConfig> config,
+ AnnotatedMember am, JavaType containerType) {
+ return null;
+ }
+
+ /**
+ * Method for locating annotation-specified subtypes related to annotated
+ * entity (class, method, field). Note that this is only guaranteed to be
+ * a list of directly
+ * declared subtypes, no recursive processing is guarantees (i.e. caller
+ * has to do it if/as necessary)
+ *
+ * @param a Annotated entity (class, field/method) to check for annotations
+ */
+ public List
+ * This feature is typically used to convert internal values into types
+ * that Jackson can convert.
+ *
+ * Note also that this feature does not necessarily work well with polymorphic
+ * type handling, or object identity handling; if such features are needed
+ * an explicit serializer is usually better way to handle serialization.
+ *
+ * @param a Annotated property (field, method) or class to check for
+ * annotations
+ *
+ * @since 2.2
+ */
+ public Object findSerializationConverter(Annotated a) {
+ return null;
+ }
+
+ /**
+ * Method for finding {@link Converter} that annotated property
+ * has indicated needs to be used for values of container type
+ * (this also means that method should only be called for properties
+ * of container types, List/Map/array properties).
+ *
+ * If not null, either has to be actual
+ * {@link Converter} instance, or class for such converter;
+ * and resulting converter will be used first to convert property
+ * value to converter target type, and then serializer for that
+ * type is used for actual serialization.
+ *
+ * Other notes are same as those for {@link #findSerializationConverter}
+ *
+ * @param a Annotated property (field, method) to check.
+ *
+ * @since 2.2
+ */
+ public Object findSerializationContentConverter(AnnotatedMember a) {
+ return null;
+ }
+
+ /**
+ * Method for checking whether given annotated entity (class, method,
+ * field) defines which Bean/Map properties are to be included in
+ * serialization.
+ * If no annotation is found, method should return given second
+ * argument; otherwise value indicated by the annotation.
+ *
+ * Note that meaning of inclusion value depends on whether it is for
+ * a Class or property (field/method/constructor): in former case,
+ * it is the default for all properties; in latter case it is specific
+ * override for annotated property.
+ *
+ * @return Enumerated value indicating which properties to include
+ * in serialization
+ *
+ * @deprecated Since 2.7 Use {@link #findPropertyInclusion} instead
+ */
+ @Deprecated // since 2.7
+ public JsonInclude.Include findSerializationInclusion(Annotated a, JsonInclude.Include defValue) {
+ return defValue;
+ }
+
+ /**
+ * Method for checking whether content (entries) of a {@link java.util.Map} property
+ * are to be included during serialization or not.
+ * NOTE: this is NOT called for POJO properties, or array/Collection elements.
+ *
+ * @since 2.5
+ *
+ * @deprecated Since 2.7 Use {@link #findPropertyInclusion} instead
+ */
+ @Deprecated // since 2.7
+ public JsonInclude.Include findSerializationInclusionForContent(Annotated a, JsonInclude.Include defValue) {
+ return defValue;
+ }
+
+ /**
+ * Method for checking inclusion criteria for a type (Class) or property (yes, method
+ * name is bit unfortunate -- not just for properties!).
+ * In case of class, acts as the default for properties POJO contains; for properties
+ * acts as override for class defaults and possible global defaults.
+ *
+ * @since 2.6
+ */
+ public JsonInclude.Value findPropertyInclusion(Annotated a) {
+ return JsonInclude.Value.empty();
+ }
+
+ /*
+ /**********************************************************
+ /* Serialization: type refinements
+ /**********************************************************
+ */
+
+ /**
+ * Method for accessing annotated type definition that a
+ * method/field can have, to be used as the type for serialization
+ * instead of the runtime type.
+ * Type returned (if any) needs to be widening conversion (super-type).
+ * Declared return type of the method is also considered acceptable.
+ *
+ * @return Class to use instead of runtime type
+ *
+ * @deprecated Since 2.7 call {@link #refineSerializationType} instead
+ */
+ @Deprecated // since 2.7
+ public Class> findSerializationType(Annotated a) {
+ return null;
+ }
+
+ /**
+ * Method for finding possible widening type definition that a property
+ * value can have, to define less specific key type to use for serialization.
+ * It should be only be used with {@link java.util.Map} types.
+ *
+ * @return Class specifying more general type to use instead of
+ * declared type, if annotation found; null if not
+ *
+ * @deprecated Since 2.7 call {@link #refineSerializationType} instead
+ */
+ @Deprecated // since 2.7
+ public Class> findSerializationKeyType(Annotated am, JavaType baseType) {
+ return null;
+ }
+
+ /**
+ * Method for finding possible widening type definition that a property
+ * value can have, to define less specific key type to use for serialization.
+ * It should be only used with structured types (arrays, collections, maps).
+ *
+ * @return Class specifying more general type to use instead of
+ * declared type, if annotation found; null if not
+ *
+ * @deprecated Since 2.7 call {@link #refineSerializationType} instead
+ */
+ @Deprecated // since 2.7
+ public Class> findSerializationContentType(Annotated am, JavaType baseType) {
+ return null;
+ }
+
+ /**
+ * Method called to find out possible type refinements to use
+ * for deserialization.
+ *
+ * @since 2.7
+ */
+ public JavaType refineSerializationType(final MapperConfig> config,
+ final Annotated a, final JavaType baseType) throws JsonMappingException
+ {
+ JavaType type = baseType;
+ final TypeFactory tf = config.getTypeFactory();
+
+ // 10-Oct-2015, tatu: For 2.7, we'll need to delegate back to
+ // now-deprecated secondary methods; this because while
+ // direct sub-class not yet retrofitted may only override
+ // those methods. With 2.8 or later we may consider removal
+ // of these methods
+
+
+ // Ok: start by refining the main type itself; common to all types
+ Class> serClass = findSerializationType(a);
+ if (serClass != null) {
+ if (type.hasRawClass(serClass)) {
+ // 30-Nov-2015, tatu: As per [databind#1023], need to allow forcing of
+ // static typing this way
+ type = type.withStaticTyping();
+ } else {
+ try {
+ // 11-Oct-2015, tatu: For deser, we call `TypeFactory.constructSpecializedType()`,
+ // may be needed here too in future?
+ type = tf.constructGeneralizedType(type, serClass);
+ } catch (IllegalArgumentException iae) {
+ throw new JsonMappingException(null,
+ String.format("Failed to widen type %s with annotation (value %s), from '%s': %s",
+ type, serClass.getName(), a.getName(), iae.getMessage()),
+ iae);
+ }
+ }
+ }
+ // Then further processing for container types
+
+ // First, key type (for Maps, Map-like types):
+ if (type.isMapLikeType()) {
+ JavaType keyType = type.getKeyType();
+ Class> keyClass = findSerializationKeyType(a, keyType);
+ if (keyClass != null) {
+ if (keyType.hasRawClass(keyClass)) {
+ keyType = keyType.withStaticTyping();
+ } else {
+ try {
+ keyType = tf.constructGeneralizedType(keyType, keyClass);
+ } catch (IllegalArgumentException iae) {
+ throw new JsonMappingException(null,
+ String.format("Failed to widen key type of %s with concrete-type annotation (value %s), from '%s': %s",
+ type, keyClass.getName(), a.getName(), iae.getMessage()),
+ iae);
+ }
+ }
+ type = ((MapLikeType) type).withKeyType(keyType);
+ }
+ }
+
+ JavaType contentType = type.getContentType();
+ if (contentType != null) { // collection[like], map[like], array, reference
+ // And then value types for all containers:
+ Class> contentClass = findSerializationContentType(a, contentType);
+ if (contentClass != null) {
+ if (contentType.hasRawClass(contentClass)) {
+ contentType = contentType.withStaticTyping();
+ } else {
+ // 03-Apr-2016, tatu: As per [databind#1178], may need to actually
+ // specialize (narrow) type sometimes, even if more commonly opposite
+ // is needed.
+ Class> currRaw = contentType.getRawClass();
+ try {
+ if (contentClass.isAssignableFrom(currRaw)) { // common case
+ contentType = tf.constructGeneralizedType(contentType, contentClass);
+ } else if (currRaw.isAssignableFrom(contentClass)) { // specialization, ok as well
+ contentType = tf.constructSpecializedType(contentType, contentClass);
+ } else {
+ throw new JsonMappingException(null,
+ String.format("Can not refine serialization content type %s into %s; types not related",
+ contentType, contentClass.getName()));
+ }
+ } catch (IllegalArgumentException iae) { // shouldn't really happen
+ throw new JsonMappingException(null,
+ String.format("Internal error: failed to refine value type of %s with concrete-type annotation (value %s), from '%s': %s",
+ type, contentClass.getName(), a.getName(), iae.getMessage()),
+ iae);
+ }
+ }
+ type = type.withContentType(contentType);
+ }
+ }
+ return type;
+ }
+
+ /*
+ /**********************************************************
+ /* Serialization: class annotations
+ /**********************************************************
+ */
+
+ /**
+ * Method for accessing defined property serialization order (which may be
+ * partial). May return null if no ordering is defined.
+ */
+ public String[] findSerializationPropertyOrder(AnnotatedClass ac) {
+ return null;
+ }
+
+ /**
+ * Method for checking whether an annotation indicates that serialized properties
+ * for which no explicit is defined should be alphabetically (lexicograpically)
+ * ordered
+ */
+ public Boolean findSerializationSortAlphabetically(Annotated ann) {
+ return null;
+ }
+
+ /**
+ * Method for adding possible virtual properties to be serialized along
+ * with regular properties.
+ *
+ * @since 2.5
+ */
+ public void findAndAddVirtualProperties(MapperConfig> config, AnnotatedClass ac,
+ List
+ * Default implementation will simply delegate to {@link #findEnumValue}, which is close
+ * enough, although unfortunately NOT 100% equivalent (as it will also consider
+ * This feature is typically used to convert intermediate Jackson types
+ * (that default deserializers can produce) into custom type instances.
+ *
+ * Note also that this feature does not necessarily work well with polymorphic
+ * type handling, or object identity handling; if such features are needed
+ * an explicit deserializer is usually better way to handle deserialization.
+ *
+ * @param a Annotated property (field, method) or class to check for
+ * annotations
+ *
+ * @since 2.2
+ */
+ public Object findDeserializationConverter(Annotated a) {
+ return null;
+ }
+
+ /**
+ * Method for finding {@link Converter} that annotated property
+ * has indicated needs to be used for values of container type
+ * (this also means that method should only be called for properties
+ * of container types, List/Map/array properties).
+ *
+ * If not null, either has to be actual
+ * {@link Converter} instance, or class for such converter;
+ * and resulting converter will be used after Jackson has deserializer
+ * data into intermediate type (Converter input type), and Converter
+ * needs to convert this into its target type to be set as property value.
+ *
+ * Other notes are same as those for {@link #findDeserializationConverter}
+ *
+ * @param a Annotated property (field, method) to check.
+ *
+ * @since 2.2
+ */
+ public Object findDeserializationContentConverter(AnnotatedMember a) {
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Deserialization: type refinements
+ /**********************************************************
+ */
+
+ /**
+ * Method called to find out possible type refinements to use
+ * for deserialization.
+ *
+ * @since 2.7
+ */
+ public JavaType refineDeserializationType(final MapperConfig> config,
+ final Annotated a, final JavaType baseType) throws JsonMappingException
+ {
+ JavaType type = baseType;
+ final TypeFactory tf = config.getTypeFactory();
+
+ // 10-Oct-2015, tatu: For 2.7, we'll need to delegate back to
+ // now-deprecated secondary methods; this because while
+ // direct sub-class not yet retrofitted may only override
+ // those methods. With 2.8 or later we may consider removal
+ // of these methods
+
+
+ // Ok: start by refining the main type itself; common to all types
+ Class> valueClass = findDeserializationType(a, type);
+ if ((valueClass != null) && !type.hasRawClass(valueClass)) {
+ try {
+ type = tf.constructSpecializedType(type, valueClass);
+ } catch (IllegalArgumentException iae) {
+ throw new JsonMappingException(null,
+ String.format("Failed to narrow type %s with annotation (value %s), from '%s': %s",
+ type, valueClass.getName(), a.getName(), iae.getMessage()),
+ iae);
+ }
+ }
+ // Then further processing for container types
+
+ // First, key type (for Maps, Map-like types):
+ if (type.isMapLikeType()) {
+ JavaType keyType = type.getKeyType();
+ Class> keyClass = findDeserializationKeyType(a, keyType);
+ if (keyClass != null) {
+ try {
+ keyType = tf.constructSpecializedType(keyType, keyClass);
+ type = ((MapLikeType) type).withKeyType(keyType);
+ } catch (IllegalArgumentException iae) {
+ throw new JsonMappingException(null,
+ String.format("Failed to narrow key type of %s with concrete-type annotation (value %s), from '%s': %s",
+ type, keyClass.getName(), a.getName(), iae.getMessage()),
+ iae);
+ }
+ }
+ }
+ JavaType contentType = type.getContentType();
+ if (contentType != null) { // collection[like], map[like], array, reference
+ // And then value types for all containers:
+ Class> contentClass = findDeserializationContentType(a, contentType);
+ if (contentClass != null) {
+ try {
+ contentType = tf.constructSpecializedType(contentType, contentClass);
+ type = type.withContentType(contentType);
+ } catch (IllegalArgumentException iae) {
+ throw new JsonMappingException(null,
+ String.format("Failed to narrow value type of %s with concrete-type annotation (value %s), from '%s': %s",
+ type, contentClass.getName(), a.getName(), iae.getMessage()),
+ iae);
+ }
+ }
+ }
+ return type;
+ }
+
+ /**
+ * Method for accessing annotated type definition that a
+ * property can have, to be used as the type for deserialization
+ * instead of the static (declared) type.
+ * Type is usually narrowing conversion (i.e.subtype of declared type).
+ * Declared return type of the method is also considered acceptable.
+ *
+ * @param baseType Assumed type before considering annotations
+ *
+ * @return Class to use for deserialization instead of declared type
+ *
+ * @deprecated Since 2.7 call {@link #refineDeserializationType} instead
+ */
+ @Deprecated
+ public Class> findDeserializationType(Annotated am, JavaType baseType) {
+ return null;
+ }
+
+ /**
+ * Method for accessing additional narrowing type definition that a
+ * method can have, to define more specific key type to use.
+ * It should be only be used with {@link java.util.Map} types.
+ *
+ * @param baseKeyType Assumed key type before considering annotations
+ *
+ * @return Class specifying more specific type to use instead of
+ * declared type, if annotation found; null if not
+ *
+ * @deprecated Since 2.7 call {@link #refineDeserializationType} instead
+ */
+ @Deprecated
+ public Class> findDeserializationKeyType(Annotated am, JavaType baseKeyType) {
+ return null;
+ }
+
+ /**
+ * Method for accessing additional narrowing type definition that a
+ * method can have, to define more specific content type to use;
+ * content refers to Map values and Collection/array elements.
+ * It should be only be used with Map, Collection and array types.
+ *
+ * @param baseContentType Assumed content (value) type before considering annotations
+ *
+ * @return Class specifying more specific type to use instead of
+ * declared type, if annotation found; null if not
+ *
+ * @deprecated Since 2.7 call {@link #refineDeserializationType} instead
+ */
+ @Deprecated
+ public Class> findDeserializationContentType(Annotated am, JavaType baseContentType) {
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Deserialization: class annotations
+ /**********************************************************
+ */
+
+ /**
+ * Method getting {@link ValueInstantiator} to use for given
+ * type (class): return value can either be an instance of
+ * instantiator, or class of instantiator to create.
+ */
+ public Object findValueInstantiator(AnnotatedClass ac) {
+ return null;
+ }
+
+ /**
+ * Method for finding Builder object to use for constructing
+ * value instance and binding data (sort of combining value
+ * instantiators that can construct, and deserializers
+ * that can bind data).
+ *
+ * Note that unlike accessors for some helper Objects, this
+ * method does not allow returning instances: the reason is
+ * that builders have state, and a separate instance needs
+ * to be created for each deserialization call.
+ *
+ * @since 2.0
+ */
+ public Class> findPOJOBuilder(AnnotatedClass ac) {
+ return null;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac) {
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Deserialization: property annotations
+ /**********************************************************
+ */
+
+ /**
+ * Method for checking whether given property accessors (method,
+ * field) has an annotation that suggests property name to use
+ * for deserialization (reading JSON into POJOs).
+ * Should return null if no annotation
+ * is found; otherwise a non-null name (possibly
+ * {@link PropertyName#USE_DEFAULT}, which means "use default heuristics").
+ *
+ * @param a Property accessor to check
+ *
+ * @return Name to use if found; null if not.
+ *
+ * @since 2.1
+ */
+ public PropertyName findNameForDeserialization(Annotated a) {
+ /*
+ if (name != null) {
+ if (name.length() == 0) { // empty String means 'default'
+ return PropertyName.USE_DEFAULT;
+ }
+ return new PropertyName(name);
+ }
+ */
+ return null;
+ }
+
+ /**
+ * Method for checking whether given method has an annotation
+ * that suggests that the method is to serve as "any setter";
+ * method to be used for setting values of any properties for
+ * which no dedicated setter method is found.
+ *
+ * @return True if such annotation is found (and is not disabled),
+ * false otherwise
+ */
+ public boolean hasAnySetterAnnotation(AnnotatedMethod am) {
+ return false;
+ }
+
+ /**
+ * Method for checking whether given method has an annotation
+ * that suggests that the method is to serve as "any setter";
+ * method to be used for accessing set of miscellaneous "extra"
+ * properties, often bound with matching "any setter" method.
+ *
+ * @return True if such annotation is found (and is not disabled),
+ * false otherwise
+ */
+ public boolean hasAnyGetterAnnotation(AnnotatedMethod am) {
+ return false;
+ }
+
+ /**
+ * Method for checking whether given annotated item (method, constructor)
+ * has an annotation
+ * that suggests that the method is a "creator" (aka factory)
+ * method to be used for construct new instances of deserialized
+ * values.
+ *
+ * @return True if such annotation is found (and is not disabled),
+ * false otherwise
+ */
+ public boolean hasCreatorAnnotation(Annotated a) {
+ return false;
+ }
+
+ /**
+ * Method for finding indication of creator binding mode for
+ * a creator (something for which {@link #hasCreatorAnnotation} returns
+ * true), for cases where there may be ambiguity (currently: single-argument
+ * creator with implicit but no explicit name for the argument).
+ *
+ * @since 2.5
+ */
+ public JsonCreator.Mode findCreatorBinding(Annotated a) {
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Overridable methods: may be used as low-level extension
+ /* points.
+ /**********************************************************
+ */
+
+ /**
+ * Method that should be used by sub-classes for ALL
+ * annotation access;
+ * overridable so
+ * that sub-classes may, if they choose to, mangle actual access to
+ * block access ("hide" annotations) or perhaps change it.
+ *
+ * Default implementation is simply:
+ *
+ * Default implementation is simply:
+ *(1 << N)
+ */
+ public int getMask();
+
+ /**
+ * Convenience method for checking whether feature is enabled in given bitmask
+ */
+ public boolean enabledIn(int flags);
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/FormatSchema.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/FormatSchema.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/FormatSchema.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,32 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Simple tag interface used to mark schema objects that are used by some
+ * {@link JsonParser} and {@link JsonGenerator} implementations to further
+ * specify structure of expected format.
+ * Basic JSON-based parsers and generators do not use schemas, but some data
+ * formats (like many binary data formats like Thrift, protobuf) mandate
+ * use of schemas.
+ *intern()
ing) is disabled) as protective
+ * measure.
+ *ThreadLocal
contains a {@link java.lang.ref.SoftReference}
+ * to a {@link BufferRecycler} used to provide a low-cost
+ * buffer recycling between reader and writer instances.
+ */
+ final protected static ThreadLocalfalse
as JSON does NOT
+ * require stable ordering. Formats that require ordering include positional
+ * textual formats like CSV
, and schema-based binary formats
+ * like Avro
.
+ *
+ * @since 2.3
+ */
+ public boolean requiresPropertyOrdering() { return false; }
+
+ /**
+ * Introspection method that higher-level functionality may call
+ * to see whether underlying data format can read and write binary
+ * data natively; that is, embeded it as-is without using encodings
+ * such as Base64.
+ *false
as JSON does not
+ * support native access: all binary content must use Base64 encoding.
+ * Most binary formats (like Smile and Avro) support native binary content.
+ *
+ * @since 2.3
+ */
+ public boolean canHandleBinaryNatively() { return false; }
+
+ /**
+ * Introspection method that can be used by base factory to check
+ * whether access using char[]
is something that actual
+ * parser implementations can take advantage of, over having to
+ * use {@link java.io.Reader}. Sub-types are expected to override
+ * definition; default implementation (suitable for JSON) alleges
+ * that optimization are possible; and thereby is likely to try
+ * to access {@link java.lang.String} content by first copying it into
+ * recyclable intermediate buffer.
+ *
+ * @since 2.4
+ */
+ public boolean canUseCharArrays() { return true; }
+
+ /**
+ * Method for accessing kind of {@link FormatFeature} that a parser
+ * {@link JsonParser} produced by this factory would accept, if any;
+ * null
returned if none.
+ *
+ * @since 2.6
+ */
+ public Class extends FormatFeature> getFormatReadFeatureType() {
+ return null;
+ }
+
+ /**
+ * Method for accessing kind of {@link FormatFeature} that a parser
+ * {@link JsonGenerator} produced by this factory would accept, if any;
+ * null
returned if none.
+ *
+ * @since 2.6
+ */
+ public Class extends FormatFeature> getFormatWriteFeatureType() {
+ return null;
+ }
+ /*
+ /**********************************************************
+ /* Format detection functionality
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to quickly check whether given schema
+ * is something that parsers and/or generators constructed by this
+ * factory could use. Note that this means possible use, at the level
+ * of data format (i.e. schema is for same data format as parsers and
+ * generators this factory constructs); individual schema instances
+ * may have further usage restrictions.
+ *
+ * @since 2.1
+ */
+ public boolean canUseSchema(FormatSchema schema) {
+ String ourFormat = getFormatName();
+ return (ourFormat != null) && ourFormat.equals(schema.getSchemaType());
+ }
+
+ /**
+ * Method that returns short textual id identifying format
+ * this factory supports.
+ *com.fasterxml.jackson.databind.ObjectMapper
)
+ * with this factory (and more importantly, parsers and generators
+ * it constructs). This is needed to use data-binding methods
+ * of {@link JsonParser} and {@link JsonGenerator} instances.
+ */
+ public JsonFactory setCodec(ObjectCodec oc) {
+ _objectCodec = oc;
+ return this;
+ }
+
+ public ObjectCodec getCodec() { return _objectCodec; }
+
+ /*
+ /**********************************************************
+ /* Parser factories (new ones, as per [Issue-25])
+ /**********************************************************
+ */
+
+ /**
+ * Method for constructing JSON parser instance to parse
+ * contents of specified file.
+ *
+ *char[]
object for accessing content.
+ *
+ * @since 2.4
+ */
+ protected JsonParser _createParser(char[] data, int offset, int len, IOContext ctxt,
+ boolean recyclable) throws IOException {
+ return new ReaderBasedJsonParser(ctxt, _parserFeatures, null, _objectCodec,
+ _rootCharSymbols.makeChild(_factoryFeatures),
+ data, offset, offset+len, recyclable);
+ }
+
+ /**
+ * Overridable factory method that actually instantiates parser
+ * using given {@link Reader} object for reading content
+ * passed as raw byte array.
+ *ObjectMapper
+ */
+ public BufferRecycler _getBufferRecycler()
+ {
+ BufferRecycler br;
+
+ /* 23-Apr-2015, tatu: Let's allow disabling of buffer recycling
+ * scheme, for cases where it is considered harmful (possibly
+ * on Android, for example)
+ */
+ if (isEnabled(Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING)) {
+ SoftReferenceflush()
to underlying {@link OutputStream}
+ * or {@link Writer}; if disabled this will not be done.
+ * Main reason to disable this feature is to prevent flushing at
+ * generator level, if it is not possible to prevent method being
+ * called by other code (like ObjectMapper
or third
+ * party libraries).
+ *mask
.
+ * Functionally equivalent to
+ *
+ * int oldState = getFeatureMask();
+ * int newState = (oldState & ~mask) | (values & mask);
+ * setFeatureMask(newState);
+ *
+ * but preferred as this lets caller more efficiently specify actual changes made.
+ *
+ * @param values Bit mask of set/clear state for features to change
+ * @param mask Bit mask of features to change
+ *
+ * @since 2.6
+ */
+ public JsonGenerator overrideStdFeatures(int values, int mask) {
+ int oldState = getFeatureMask();
+ int newState = (oldState & ~mask) | (values & mask);
+ return setFeatureMask(newState);
+ }
+
+ /**
+ * Bulk access method for getting state of all {@link FormatFeature}s, format-specific
+ * on/off configuration settings.
+ *
+ * @return Bit mask that defines current states of all standard {@link FormatFeature}s.
+ *
+ * @since 2.6
+ */
+ public int getFormatFeatures() {
+ return 0;
+ }
+
+ /**
+ * Bulk set method for (re)setting states of {@link FormatFeature}s,
+ * by specifying values (set / clear) along with a mask, to determine
+ * which features to change, if any.
+ *
+ * getOutputContext().getCurrentValue();
+ *
+ *
+ * getOutputContext().setCurrentValue(v);
+ *
+ *
+ * @since 2.5
+ */
+ public void setCurrentValue(Object v) {
+ JsonStreamContext ctxt = getOutputContext();
+ if (ctxt != null) {
+ ctxt.setCurrentValue(v);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, capability introspection methods
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to verify that given schema can be used with
+ * this generator (using {@link #setSchema}).
+ *
+ * @param schema Schema to check
+ *
+ * @return True if this generator can use given schema; false if not
+ */
+ public boolean canUseSchema(FormatSchema schema) { return false; }
+
+ /**
+ * Introspection method that may be called to see if the underlying
+ * data format supports some kind of Object Ids natively (many do not;
+ * for example, JSON doesn't).
+ * This method must be called prior to calling
+ * {@link #writeObjectId} or {@link #writeObjectRef}.
+ *data
MUST provide at least
+ * that many bytes: if not, an exception will be thrown.
+ * Note that implementations
+ * need not support cases where length is not known in advance; this
+ * depends on underlying data format: JSON output does NOT require length,
+ * other formats may.
+ *
+ * @return Number of bytes read from data
and written as binary payload
+ *
+ * @since 2.1
+ */
+ public abstract int writeBinary(Base64Variant bv,
+ InputStream data, int dataLength) throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, other value types
+ /**********************************************************
+ */
+
+ /**
+ * Method for outputting given value as JSON number.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ *
+ * @since 2.2
+ */
+ public void writeNumber(short v) throws IOException { writeNumber((int) v); }
+
+ /**
+ * Method for outputting given value as JSON number.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ */
+ public abstract void writeNumber(int v) throws IOException;
+
+ /**
+ * Method for outputting given value as JSON number.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ */
+ public abstract void writeNumber(long v) throws IOException;
+
+ /**
+ * Method for outputting given value as JSON number.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ */
+ public abstract void writeNumber(BigInteger v) throws IOException;
+
+ /**
+ * Method for outputting indicate JSON numeric value.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ */
+ public abstract void writeNumber(double v) throws IOException;
+
+ /**
+ * Method for outputting indicate JSON numeric value.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ */
+ public abstract void writeNumber(float v) throws IOException;
+
+ /**
+ * Method for outputting indicate JSON numeric value.
+ * Can be called in any context where a value is expected
+ * (Array value, Object field value, root-level value).
+ * Additional white space may be added around the value
+ * if pretty-printing is enabled.
+ *
+ * @param v Number value to write
+ */
+ public abstract void writeNumber(BigDecimal v) throws IOException;
+
+ /**
+ * Write method that can be used for custom numeric types that can
+ * not be (easily?) converted to "standard" Java number types.
+ * Because numbers are not surrounded by double quotes, regular
+ * {@link #writeString} method can not be used; nor
+ * {@link #writeRaw} because that does not properly handle
+ * value separators needed in Array or Object contexts.
+ *
+ * writeFieldName(fieldName);
+ * writeString(value);
+ *
+ *
+ * writeFieldName(fieldName);
+ * writeBoolean(value);
+ *
+ */
+ public final void writeBooleanField(String fieldName, boolean value) throws IOException {
+ writeFieldName(fieldName);
+ writeBoolean(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has JSON literal value null. Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeNull();
+ *
+ */
+ public final void writeNullField(String fieldName) throws IOException {
+ writeFieldName(fieldName);
+ writeNull();
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has the specified numeric value. Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeNumber(value);
+ *
+ */
+ public final void writeNumberField(String fieldName, int value) throws IOException {
+ writeFieldName(fieldName);
+ writeNumber(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has the specified numeric value. Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeNumber(value);
+ *
+ */
+ public final void writeNumberField(String fieldName, long value) throws IOException {
+ writeFieldName(fieldName);
+ writeNumber(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has the specified numeric value. Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeNumber(value);
+ *
+ */
+ public final void writeNumberField(String fieldName, double value) throws IOException {
+ writeFieldName(fieldName);
+ writeNumber(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has the specified numeric value. Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeNumber(value);
+ *
+ */
+ public final void writeNumberField(String fieldName, float value) throws IOException {
+ writeFieldName(fieldName);
+ writeNumber(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that has the specified numeric value.
+ * Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeNumber(value);
+ *
+ */
+ public final void writeNumberField(String fieldName, BigDecimal value) throws IOException {
+ writeFieldName(fieldName);
+ writeNumber(value);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * that contains specified data in base64-encoded form.
+ * Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeBinary(value);
+ *
+ */
+ public final void writeBinaryField(String fieldName, byte[] data) throws IOException {
+ writeFieldName(fieldName);
+ writeBinary(data);
+ }
+
+ /**
+ * Convenience method for outputting a field entry ("member")
+ * (that will contain a JSON Array value), and the START_ARRAY marker.
+ * Equivalent to:
+ *
+ * writeFieldName(fieldName);
+ * writeStartArray();
+ *
+ *
+ * writeFieldName(fieldName);
+ * writeStartObject();
+ *
+ *
+ * writeFieldName(fieldName);
+ * writeObject(pojo);
+ *
+ */
+ public final void writeObjectField(String fieldName, Object pojo) throws IOException {
+ writeFieldName(fieldName);
+ writeObject(pojo);
+ }
+
+ /**
+ * Method called to indicate that a property in this position was
+ * skipped. It is usually only called for generators that return
+ * false
from {@link #canOmitFields()}.
+ *
+ *
+ *transient
since 2.2 so that Location itself is Serializable.
+ */
+ final transient Object _sourceRef;
+
+ public JsonLocation(Object srcRef, long totalChars, int lineNr, int colNr)
+ {
+ /* Unfortunately, none of legal encodings are straight single-byte
+ * encodings. Could determine offset for UTF-16/UTF-32, but the
+ * most important one is UTF-8...
+ * so for now, we'll just not report any real byte count
+ */
+ this(srcRef, -1L, totalChars, lineNr, colNr);
+ }
+
+ public JsonLocation(Object sourceRef, long totalBytes, long totalChars,
+ int lineNr, int columnNr)
+ {
+ _sourceRef = sourceRef;
+ _totalBytes = totalBytes;
+ _totalChars = totalChars;
+ _lineNr = lineNr;
+ _columnNr = columnNr;
+ }
+
+ /**
+ * Reference to the original resource being read, if one available.
+ * For example, when a parser has been constructed by passing
+ * a {@link java.io.File} instance, this method would return
+ * that File. Will return null if no such reference is available,
+ * for example when {@link java.io.InputStream} was used to
+ * construct the parser instance.
+ */
+ public Object getSourceRef() { return _sourceRef; }
+
+ /**
+ * @return Line number of the location (1-based)
+ */
+ public int getLineNr() { return _lineNr; }
+
+ /**
+ * @return Column number of the location (1-based)
+ */
+ public int getColumnNr() { return _columnNr; }
+
+ /**
+ * @return Character offset within underlying stream, reader or writer,
+ * if available; -1 if not.
+ */
+ public long getCharOffset() { return _totalChars; }
+
+ /**
+ * @return Byte offset within underlying stream, reader or writer,
+ * if available; -1 if not.
+ */
+ public long getByteOffset()
+ {
+ return _totalBytes;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder(80);
+ sb.append("[Source: ");
+ if (_sourceRef == null) {
+ sb.append("UNKNOWN");
+ } else {
+ sb.append(_sourceRef.toString());
+ }
+ sb.append("; line: ");
+ sb.append(_lineNr);
+ sb.append(", column: ");
+ sb.append(_columnNr);
+ sb.append(']');
+ return sb.toString();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = (_sourceRef == null) ? 1 : _sourceRef.hashCode();
+ hash ^= _lineNr;
+ hash += _columnNr;
+ hash ^= (int) _totalChars;
+ hash += (int) _totalBytes;
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object other)
+ {
+ if (other == this) return true;
+ if (other == null) return false;
+ if (!(other instanceof JsonLocation)) return false;
+ JsonLocation otherLoc = (JsonLocation) other;
+
+ if (_sourceRef == null) {
+ if (otherLoc._sourceRef != null) return false;
+ } else if (!_sourceRef.equals(otherLoc._sourceRef)) return false;
+
+ return (_lineNr == otherLoc._lineNr)
+ && (_columnNr == otherLoc._columnNr)
+ && (_totalChars == otherLoc._totalChars)
+ && (getByteOffset() == otherLoc.getByteOffset())
+ ;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonParseException.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonParseException.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonParseException.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,80 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+/**
+ * Exception type for parsing problems, used when non-well-formed content
+ * (content that does not conform to JSON syntax as per specification)
+ * is encountered.
+ */
+public class JsonParseException extends JsonProcessingException {
+ private static final long serialVersionUID = 2L; // 2.7
+
+ // since 2.7.4
+ protected transient JsonParser _processor;
+
+ @Deprecated // since 2.7
+ public JsonParseException(String msg, JsonLocation loc) {
+ super(msg, loc);
+ }
+
+ @Deprecated // since 2.7
+ public JsonParseException(String msg, JsonLocation loc, Throwable root) {
+ super(msg, loc, root);
+ }
+
+ /**
+ * Constructor that uses current parsing location as location, and
+ * sets processor (accessible via {@link #getProcessor()}) to
+ * specified parser.
+ *
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg) {
+ super(msg, (p == null) ? null : p.getCurrentLocation());
+ _processor = p;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg, Throwable root) {
+ super(msg, (p == null) ? null : p.getCurrentLocation(), root);
+ _processor = p;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg, JsonLocation loc) {
+ super(msg, loc);
+ _processor = p;
+ }
+
+ /**
+ * @since 2.7
+ */
+ public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable root) {
+ super(msg, loc, root);
+ _processor = p;
+ }
+
+ /**
+ * Fluent method that may be used to assign originating {@link JsonParser},
+ * to be accessed using {@link #getProcessor()}.
+ *
+ * @since 2.7
+ */
+ public JsonParseException withParser(JsonParser p) {
+ _processor = p;
+ return this;
+ }
+
+ @Override
+ public JsonParser getProcessor() {
+ return _processor;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonParser.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonParser.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonParser.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,1598 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+
+/**
+ * Base class that defines public API for reading JSON content.
+ * Instances are created using factory methods of
+ * a {@link JsonFactory} instance.
+ *
+ * @author Tatu Saloranta
+ */
+public abstract class JsonParser
+ implements Closeable, Versioned
+{
+ private final static int MIN_BYTE_I = (int) Byte.MIN_VALUE;
+ // as per [JACKSON-804], allow range up to and including 255
+ private final static int MAX_BYTE_I = (int) 255;
+
+ private final static int MIN_SHORT_I = (int) Short.MIN_VALUE;
+ private final static int MAX_SHORT_I = (int) Short.MAX_VALUE;
+
+ /**
+ * Enumeration of possible "native" (optimal) types that can be
+ * used for numbers.
+ */
+ public enum NumberType {
+ INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL
+ };
+
+ /**
+ * Enumeration that defines all on/off features for parsers.
+ */
+ public enum Feature {
+
+ // // // Low-level I/O handling features:
+
+ /**
+ * Feature that determines whether parser will automatically
+ * close underlying input source that is NOT owned by the
+ * parser. If disabled, calling application has to separately
+ * close the underlying {@link InputStream} and {@link Reader}
+ * instances used to create the parser. If enabled, parser
+ * will handle closing, as long as parser itself gets closed:
+ * this happens when end-of-input is encountered, or parser
+ * is closed by a call to {@link JsonParser#close}.
+ *
+ *
+ *
+ * getParsingContext().getCurrentValue();
+ *
+ *
+ * getParsingContext().setCurrentValue(v);
+ *
+ *
+ * @since 2.5
+ */
+ public void setCurrentValue(Object v) {
+ JsonStreamContext ctxt = getParsingContext();
+ if (ctxt != null) {
+ ctxt.setCurrentValue(v);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Format support
+ /**********************************************************
+ */
+
+ /**
+ * Method to call to make this parser use specified schema. Method must
+ * be called before trying to parse any content, right after parser instance
+ * has been created.
+ * Note that not all parsers support schemas; and those that do usually only
+ * accept specific types of schemas: ones defined for data format parser can read.
+ *mask
.
+ * Functionally equivalent to
+ *
+ * int oldState = getFeatureMask();
+ * int newState = (oldState & ~mask) | (values & mask);
+ * setFeatureMask(newState);
+ *
+ * but preferred as this lets caller more efficiently specify actual changes made.
+ *
+ * @param values Bit mask of set/clear state for features to change
+ * @param mask Bit mask of features to change
+ *
+ * @since 2.6
+ */
+ public JsonParser overrideStdFeatures(int values, int mask) {
+ int newState = (_features & ~mask) | (values & mask);
+ return setFeatureMask(newState);
+ }
+
+ /**
+ * Bulk access method for getting state of all {@link FormatFeature}s, format-specific
+ * on/off configuration settings.
+ *
+ * @return Bit mask that defines current states of all standard {@link FormatFeature}s.
+ *
+ * @since 2.6
+ */
+ public int getFormatFeatures() {
+ return 0;
+ }
+
+ /**
+ * Bulk set method for (re)setting states of {@link FormatFeature}s,
+ * by specifying values (set / clear) along with a mask, to determine
+ * which features to change, if any.
+ *
+ * return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
+ *
+ * but may be faster for parser to verify, and can therefore be used if caller
+ * expects to get such a property name from input next.
+ *
+ * @param str Property name to compare next token to (if next token is
+ * JsonToken.FIELD_NAME
)
+ */
+ public boolean nextFieldName(SerializableString str) throws IOException, JsonParseException {
+ return (nextToken() == JsonToken.FIELD_NAME) && str.getValue().equals(getCurrentName());
+ }
+
+ /**
+ * Method that fetches next token (as if calling {@link #nextToken}) and
+ * verifies whether it is {@link JsonToken#FIELD_NAME}; if it is,
+ * returns same as {@link #getCurrentName()}, otherwise null.
+ *
+ * @since 2.5
+ */
+ public String nextFieldName() throws IOException, JsonParseException {
+ return (nextToken() == JsonToken.FIELD_NAME) ? getCurrentName() : null;
+ }
+
+ /**
+ * Method that fetches next token (as if calling {@link #nextToken}) and
+ * if it is {@link JsonToken#VALUE_STRING} returns contained String value;
+ * otherwise returns null.
+ * It is functionally equivalent to:
+ *
+ * return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+ *
+ * but may be faster for parser to process, and can therefore be used if caller
+ * expects to get a String value next from input.
+ */
+ public String nextTextValue() throws IOException, JsonParseException {
+ return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
+ }
+
+ /**
+ * Method that fetches next token (as if calling {@link #nextToken}) and
+ * if it is {@link JsonToken#VALUE_NUMBER_INT} returns 32-bit int value;
+ * otherwise returns specified default value
+ * It is functionally equivalent to:
+ *
+ * return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+ *
+ * but may be faster for parser to process, and can therefore be used if caller
+ * expects to get a String value next from input.
+ */
+ public int nextIntValue(int defaultValue) throws IOException, JsonParseException {
+ return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
+ }
+
+ /**
+ * Method that fetches next token (as if calling {@link #nextToken}) and
+ * if it is {@link JsonToken#VALUE_NUMBER_INT} returns 64-bit long value;
+ * otherwise returns specified default value
+ * It is functionally equivalent to:
+ *
+ * return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+ *
+ * but may be faster for parser to process, and can therefore be used if caller
+ * expects to get a String value next from input.
+ */
+ public long nextLongValue(long defaultValue) throws IOException, JsonParseException {
+ return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getLongValue() : defaultValue;
+ }
+
+ /**
+ * Method that fetches next token (as if calling {@link #nextToken}) and
+ * if it is {@link JsonToken#VALUE_TRUE} or {@link JsonToken#VALUE_FALSE}
+ * returns matching Boolean value; otherwise return null.
+ * It is functionally equivalent to:
+ *
+ * JsonToken t = nextToken();
+ * if (t == JsonToken.VALUE_TRUE) return Boolean.TRUE;
+ * if (t == JsonToken.VALUE_FALSE) return Boolean.FALSE;
+ * return null;
+ *
+ * but may be faster for parser to process, and can therefore be used if caller
+ * expects to get a String value next from input.
+ */
+ public Boolean nextBooleanValue() throws IOException, JsonParseException {
+ JsonToken t = nextToken();
+ if (t == JsonToken.VALUE_TRUE) { return Boolean.TRUE; }
+ if (t == JsonToken.VALUE_FALSE) { return Boolean.FALSE; }
+ return null;
+ }
+
+ /**
+ * Method that will skip all child tokens of an array or
+ * object token that the parser currently points to,
+ * iff stream points to
+ * {@link JsonToken#START_OBJECT} or {@link JsonToken#START_ARRAY}.
+ * If not, it will do nothing.
+ * After skipping, stream will point to matching
+ * {@link JsonToken#END_OBJECT} or {@link JsonToken#END_ARRAY}
+ * (possibly skipping nested pairs of START/END OBJECT/ARRAY tokens
+ * as well as value tokens).
+ * The idea is that after calling this method, application
+ * will call {@link #nextToken} to point to the next
+ * available token, if any.
+ */
+ public abstract JsonParser skipChildren() throws IOException, JsonParseException;
+
+ /**
+ * Method that can be called to determine whether this parser
+ * is closed or not. If it is closed, no new tokens can be
+ * retrieved by calling {@link #nextToken} (and the underlying
+ * stream may be closed). Closing may be due to an explicit
+ * call to {@link #close} or because parser has encountered
+ * end of input.
+ */
+ public abstract boolean isClosed();
+
+ /*
+ /**********************************************************
+ /* Public API, token accessors
+ /**********************************************************
+ */
+
+ /**
+ * Accessor to find which token parser currently points to, if any;
+ * null will be returned if none.
+ * If return value is non-null, data associated with the token
+ * is available via other accessor methods.
+ *
+ * @return Type of the token this parser currently points to,
+ * if any: null before any tokens have been read, and
+ * after end-of-input has been encountered, as well as
+ * if the current token has been explicitly cleared.
+ */
+ public abstract JsonToken getCurrentToken();
+
+ /**
+ * Method similar to {@link #getCurrentToken()} but that returns an
+ * int
instead of {@link JsonToken} (enum value).
+ *int
matching one of constants from {@link JsonTokenId}.
+ */
+ public abstract int getCurrentTokenId();
+
+ /**
+ * Method for checking whether parser currently points to
+ * a token (and data for that token is available).
+ * Equivalent to check for parser.getCurrentToken() != null
.
+ *
+ * @return True if the parser just returned a valid
+ * token via {@link #nextToken}; false otherwise (parser
+ * was just constructed, encountered end-of-input
+ * and returned null from {@link #nextToken}, or the token
+ * has been consumed)
+ */
+ public abstract boolean hasCurrentToken();
+
+ /**
+ * Method that is functionally equivalent to:
+ *
+ * return getCurrentTokenId() == id
+ *
+ * but may be more efficiently implemented.
+ *
+ * return getCurrentTokenId() == id
+ *
+ * but may be more efficiently implemented.
+ *
+ * getCurrentToken() == JsonToken.START_ARRAY
+ *
+ * but may be overridden by custom parser implementations.
+ *
+ * @return True if the current token can be considered as a
+ * start-array marker (such {@link JsonToken#START_ARRAY});
+ * false if not.
+ */
+ public boolean isExpectedStartArrayToken() { return getCurrentToken() == JsonToken.START_ARRAY; }
+
+ /**
+ * Similar to {@link #isExpectedStartArrayToken()}, but checks whether stream
+ * currently points to {@link JsonToken#START_OBJECT}.
+ *
+ * @since 2.5
+ */
+ public boolean isExpectedStartObjectToken() { return getCurrentToken() == JsonToken.START_OBJECT; }
+
+ /*
+ /**********************************************************
+ /* Public API, token state overrides
+ /**********************************************************
+ */
+
+ /**
+ * Method called to "consume" the current token by effectively
+ * removing it so that {@link #hasCurrentToken} returns false, and
+ * {@link #getCurrentToken} null).
+ * Cleared token value can still be accessed by calling
+ * {@link #getLastClearedToken} (if absolutely needed), but
+ * usually isn't.
+ *
+ *
+ *MappingJsonFactory
(from "jackson-databind" jar)
+ * but not for {@link JsonFactory} (unless its setCodec
+ * method has been explicitly called).
+ *MappingJsonFactory
(defined in 'jackson-databind' bundle)
+ * but not for {@link JsonFactory} (unless its setCodec
+ * method has been explicitly called).
+ *FIELD_NAME
and value events that directly
+ * follow field names; null for root level and array values.
+ */
+ public abstract String getCurrentName();
+
+ /**
+ * Method for accessing currently active value being used by data-binding
+ * (as the source of streaming data to write, or destination of data being
+ * read), at this level in hierarchy.
+ *JsonNode
-based JSON trees, Maps, Lists and such).
+ */
+ VALUE_EMBEDDED_OBJECT(null, JsonTokenId.ID_EMBEDDED_OBJECT),
+
+ /**
+ * VALUE_STRING is returned when a String token is encountered
+ * in value context (array element, field value, or root-level
+ * stand-alone value)
+ */
+ VALUE_STRING(null, JsonTokenId.ID_STRING),
+
+ /**
+ * VALUE_NUMBER_INT is returned when an integer numeric token is
+ * encountered in value context: that is, a number that does
+ * not have floating point or exponent marker in it (consists
+ * only of an optional sign, followed by one or more digits)
+ */
+ VALUE_NUMBER_INT(null, JsonTokenId.ID_NUMBER_INT),
+
+ /**
+ * VALUE_NUMBER_INT is returned when a numeric token other
+ * that is not an integer is encountered: that is, a number that does
+ * have floating point or exponent marker in it, in addition
+ * to one or more digits.
+ */
+ VALUE_NUMBER_FLOAT(null, JsonTokenId.ID_NUMBER_FLOAT),
+
+ /**
+ * VALUE_TRUE is returned when encountering literal "true" in
+ * value context
+ */
+ VALUE_TRUE("true", JsonTokenId.ID_TRUE),
+
+ /**
+ * VALUE_FALSE is returned when encountering literal "false" in
+ * value context
+ */
+ VALUE_FALSE("false", JsonTokenId.ID_FALSE),
+
+ /**
+ * VALUE_NULL is returned when encountering literal "null" in
+ * value context
+ */
+ VALUE_NULL("null", JsonTokenId.ID_NULL),
+ ;
+
+ final String _serialized;
+
+ final char[] _serializedChars;
+
+ final byte[] _serializedBytes;
+
+ final int _id;
+
+ final boolean _isStructStart, _isStructEnd;
+
+ final boolean _isNumber;
+
+ final boolean _isBoolean;
+
+ final boolean _isScalar;
+
+ /**
+ * @param token representation for this token, if there is a
+ * single static representation; null otherwise
+ */
+ JsonToken(String token, int id)
+ {
+ if (token == null) {
+ _serialized = null;
+ _serializedChars = null;
+ _serializedBytes = null;
+ } else {
+ _serialized = token;
+ _serializedChars = token.toCharArray();
+ // It's all in ascii, can just case...
+ int len = _serializedChars.length;
+ _serializedBytes = new byte[len];
+ for (int i = 0; i < len; ++i) {
+ _serializedBytes[i] = (byte) _serializedChars[i];
+ }
+ }
+ _id = id;
+
+ _isBoolean = (id == JsonTokenId.ID_FALSE || id == JsonTokenId.ID_TRUE);
+ _isNumber = (id == JsonTokenId.ID_NUMBER_INT || id == JsonTokenId.ID_NUMBER_FLOAT);
+
+ _isStructStart = (id == JsonTokenId.ID_START_OBJECT || id == JsonTokenId.ID_START_ARRAY);
+ _isStructEnd = (id == JsonTokenId.ID_END_OBJECT || id == JsonTokenId.ID_END_ARRAY);
+
+ _isScalar = !_isStructStart && !_isStructEnd
+ && (id != JsonTokenId.ID_FIELD_NAME)
+ && (id != JsonTokenId.ID_NOT_AVAILABLE);
+ }
+
+ public final int id() { return _id; }
+
+ public final String asString() { return _serialized; }
+ public final char[] asCharArray() { return _serializedChars; }
+ public final byte[] asByteArray() { return _serializedBytes; }
+
+ public final boolean isNumeric() { return _isNumber; }
+
+ /**
+ * Accessor that is functionally equivalent to:
+ *
+ * this == JsonToken.START_OBJECT || this == JsonToken.START_ARRAY
+ *
+ *
+ * @since 2.3
+ */
+ public final boolean isStructStart() { return _isStructStart; }
+
+ /**
+ * Accessor that is functionally equivalent to:
+ *
+ * this == JsonToken.END_OBJECT || this == JsonToken.END_ARRAY
+ *
+ *
+ * @since 2.3
+ */
+ public final boolean isStructEnd() { return _isStructEnd; }
+
+ /**
+ * Method that can be used to check whether this token represents
+ * a valid non-structured value. This means all tokens other than
+ * Object/Array start/end markers all field names.
+ */
+ public final boolean isScalarValue() { return _isScalar; }
+ public final boolean isBoolean() { return _isBoolean; }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonTokenId.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonTokenId.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/JsonTokenId.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,87 @@
+package com.fasterxml.jackson.core;
+
+/**
+ * Interface defined to contain ids accessible with {@link JsonToken#id()}.
+ * Needed because it is impossible to define these constants in
+ * {@link JsonToken} itself, as static constants (oddity of how Enums
+ * are implemented by JVM).
+ *
+ * @since 2.3
+ */
+public interface JsonTokenId
+{
+ /**
+ * Id used to represent {@link JsonToken#NOT_AVAILABLE}, used in
+ * cases where a token may become available when more input
+ * is available: this occurs in non-blocking use cases.
+ */
+ public final static int ID_NOT_AVAILABLE = -1;
+
+ /**
+ * Id used to represent the case where no {@link JsonToken}
+ * is available: either because {@link JsonParser} has not been
+ * advanced to first token, or because no more tokens will be
+ * available (end-of-input or explicit closing of parser}.
+ */
+ public final static int ID_NO_TOKEN = 0;
+
+ /**
+ * Id used to represent {@link JsonToken#START_OBJECT}
+ */
+ public final static int ID_START_OBJECT = 1;
+
+ /**
+ * Id used to represent {@link JsonToken#END_OBJECT}
+ */
+ public final static int ID_END_OBJECT = 2;
+
+ /**
+ * Id used to represent {@link JsonToken#START_ARRAY}
+ */
+ public final static int ID_START_ARRAY = 3;
+
+ /**
+ * Id used to represent {@link JsonToken#END_ARRAY}
+ */
+ public final static int ID_END_ARRAY = 4;
+
+ /**
+ * Id used to represent {@link JsonToken#FIELD_NAME}
+ */
+ public final static int ID_FIELD_NAME = 5;
+
+ /**
+ * Id used to represent {@link JsonToken#VALUE_STRING}
+ */
+ public final static int ID_STRING = 6;
+
+ /**
+ * Id used to represent {@link JsonToken#VALUE_NUMBER_INT}
+ */
+ public final static int ID_NUMBER_INT = 7;
+
+ /**
+ * Id used to represent {@link JsonToken#VALUE_NUMBER_FLOAT}
+ */
+ public final static int ID_NUMBER_FLOAT = 8;
+
+ /**
+ * Id used to represent {@link JsonToken#VALUE_TRUE}
+ */
+ public final static int ID_TRUE = 9;
+
+ /**
+ * Id used to represent {@link JsonToken#VALUE_FALSE}
+ */
+ public final static int ID_FALSE = 10;
+ /**
+ * Id used to represent {@link JsonToken#VALUE_NULL}
+ */
+
+ public final static int ID_NULL = 11;
+
+ /**
+ * Id used to represent {@link JsonToken#VALUE_EMBEDDED_OBJECT}
+ */
+ public final static int ID_EMBEDDED_OBJECT = 12;
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/ObjectCodec.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/ObjectCodec.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/ObjectCodec.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,184 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import com.fasterxml.jackson.core.type.ResolvedType;
+import com.fasterxml.jackson.core.type.TypeReference;
+
+/**
+ * Abstract class that defines the interface that {@link JsonParser} and
+ * {@link JsonGenerator} use to serialize and deserialize regular
+ * Java objects (POJOs aka Beans).
+ *com.fasterxml.jackson.databind.ObjectMapper
,
+ * defined in the "jackson-databind".
+ */
+public abstract class ObjectCodec
+ extends TreeCodec // since 2.3
+ implements Versioned // since 2.3
+{
+ protected ObjectCodec() { }
+
+ // Since 2.3: need baseline implementation to avoid backwards compatibility
+ @Override
+ public Version version() { return Version.unknownVersion(); }
+
+ /*
+ /**********************************************************
+ /* API for de-serialization (JSON-to-Object)
+ /**********************************************************
+ */
+
+ /**
+ * Method to deserialize JSON content into a non-container
+ * type (it can be an array type, however): typically a bean, array
+ * or a wrapper type (like {@link java.lang.Boolean}).
+ *
+ * getValue().length();
+ *
+ */
+ int charLength();
+
+ /*
+ /**********************************************************
+ /* Accessors for byte sequences
+ /**********************************************************
+ */
+
+ /**
+ * Returns JSON quoted form of the String, as character array.
+ * Result can be embedded as-is in textual JSON as property name or JSON String.
+ */
+ char[] asQuotedChars();
+
+ /**
+ * Returns UTF-8 encoded version of unquoted String.
+ * Functionally equivalent to (but more efficient than):
+ *
+ * getValue().getBytes("UTF-8");
+ *
+ */
+ byte[] asUnquotedUTF8();
+
+ /**
+ * Returns UTF-8 encoded version of JSON-quoted String.
+ * Functionally equivalent to (but more efficient than):
+ *
+ * new String(asQuotedChars()).getBytes("UTF-8");
+ *
+ */
+ byte[] asQuotedUTF8();
+
+ /*
+ /**********************************************************
+ /* Helper methods for appending byte/char sequences
+ /**********************************************************
+ */
+
+ /**
+ * Method that will append quoted UTF-8 bytes of this String into given
+ * buffer, if there is enough room; if not, returns -1.
+ * Functionally equivalent to:
+ *
+ * byte[] bytes = str.asQuotedUTF8();
+ * System.arraycopy(bytes, 0, buffer, offset, bytes.length);
+ * return bytes.length;
+ *
+ *
+ * @return Number of bytes appended, if successful, otherwise -1
+ */
+ int appendQuotedUTF8(byte[] buffer, int offset);
+
+ /**
+ * Method that will append quoted characters of this String into given
+ * buffer. Functionally equivalent to:
+ *
+ * char[] ch = str.asQuotedChars();
+ * System.arraycopy(ch, 0, buffer, offset, ch.length);
+ * return ch.length;
+ *
+ *
+ * @return Number of characters appended, if successful, otherwise -1
+ */
+ int appendQuoted(char[] buffer, int offset);
+
+ /**
+ * Method that will append unquoted ('raw') UTF-8 bytes of this String into given
+ * buffer. Functionally equivalent to:
+ *
+ * byte[] bytes = str.asUnquotedUTF8();
+ * System.arraycopy(bytes, 0, buffer, offset, bytes.length);
+ * return bytes.length;
+ *
+ *
+ * @return Number of bytes appended, if successful, otherwise -1
+ */
+ int appendUnquotedUTF8(byte[] buffer, int offset);
+
+
+ /**
+ * Method that will append unquoted characters of this String into given
+ * buffer. Functionally equivalent to:
+ *
+ * char[] ch = str.getValue().toCharArray();
+ * System.arraycopy(bytes, 0, buffer, offset, ch.length);
+ * return ch.length;
+ *
+ *
+ * @return Number of characters appended, if successful, otherwise -1
+ */
+ int appendUnquoted(char[] buffer, int offset);
+
+ /*
+ /**********************************************************
+ /* Helper methods for writing out byte sequences
+ /**********************************************************
+ */
+
+ /**
+ * @return Number of bytes written
+ */
+ int writeQuotedUTF8(OutputStream out) throws IOException;
+
+ /**
+ * @return Number of bytes written
+ */
+ int writeUnquotedUTF8(OutputStream out) throws IOException;
+
+ /**
+ * @return Number of bytes put, if successful, otherwise -1
+ */
+ int putQuotedUTF8(ByteBuffer buffer) throws IOException;
+
+ /**
+ * @return Number of bytes put, if successful, otherwise -1
+ */
+ int putUnquotedUTF8(ByteBuffer out) throws IOException;
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/TreeCodec.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/TreeCodec.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/TreeCodec.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,18 @@
+package com.fasterxml.jackson.core;
+
+import java.io.IOException;
+
+/**
+ * Interface that defines objects that can read and write
+ * {@link TreeNode} instances using Streaming API.
+ *
+ * @since 2.3
+ */
+public abstract class TreeCodec
+{
+ public abstract JsonNode
+ * base class in mapper
package.
+ *JsonNode
itself
+ * was part of core package: Jackson 2.x refactored this
+ * since conceptually Tree Model is part of mapper package,
+ * and so part visible to core
package should
+ * be minimized.
+ *node.size()
, null is returned; no exception is
+ * thrown for any index.
+ *
+ * @return Node that represent value of the specified element,
+ * if this node is an array and has specified element.
+ * Null otherwise.
+ *
+ * @since 2.2
+ */
+ TreeNode get(int index);
+
+ /**
+ * Method for accessing value of the specified field of
+ * an object node.
+ * For other nodes, a "missing node" (virtual node
+ * for which {@link #isMissingNode} returns true) is returned.
+ *
+ * @return Node that represent value of the specified field,
+ * if this node is an object and has value for the specified field;
+ * otherwise "missing node" is returned.
+ *
+ * @since 2.2
+ */
+ TreeNode path(String fieldName);
+
+ /**
+ * Method for accessing value of the specified element of
+ * an array node.
+ * For other nodes, a "missing node" (virtual node
+ * for which {@link #isMissingNode} returns true) is returned.
+ *node.size()
, "missing node" is returned; no exception is
+ * thrown for any index.
+ *
+ * @return Node that represent value of the specified element,
+ * if this node is an array and has specified element;
+ * otherwise "missing node" is returned.
+ *
+ * @since 2.2
+ */
+ TreeNode path(int index);
+
+ /**
+ * Method for accessing names of all fields for this node, iff
+ * this node is an Object node. Number of field names accessible
+ * will be {@link #size}.
+ *
+ * @since 2.2
+ */
+ Iterator
+ * return at(JsonPointer.valueOf(jsonPointerExpression));
+ *
+ *nextToken()
,
+ * as well as if token has been explicitly cleared
+ */
+ protected JsonToken _currToken;
+
+ /**
+ * Last cleared token, if any: that is, value that was in
+ * effect when {@link #clearCurrentToken} was called.
+ */
+ protected JsonToken _lastClearedToken;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ protected ParserMinimalBase() { }
+ protected ParserMinimalBase(int features) { super(features); }
+
+ // NOTE: had base impl in 2.3 and before; but shouldn't
+ // public abstract Version version();
+
+ /*
+ /**********************************************************
+ /* Configuration overrides if any
+ /**********************************************************
+ */
+
+ // from base class:
+
+ //public void enableFeature(Feature f)
+ //public void disableFeature(Feature f)
+ //public void setFeature(Feature f, boolean state)
+ //public boolean isFeatureEnabled(Feature f)
+
+ /*
+ /**********************************************************
+ /* JsonParser impl
+ /**********************************************************
+ */
+
+ @Override public abstract JsonToken nextToken() throws IOException;
+ @Override public JsonToken getCurrentToken() { return _currToken; }
+
+ @Override public int getCurrentTokenId() {
+ final JsonToken t = _currToken;
+ return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
+ }
+
+ @Override public boolean hasCurrentToken() { return _currToken != null; }
+ @Override public boolean hasTokenId(int id) {
+ final JsonToken t = _currToken;
+ if (t == null) {
+ return (JsonTokenId.ID_NO_TOKEN == id);
+ }
+ return t.id() == id;
+ }
+
+ @Override public boolean hasToken(JsonToken t) {
+ return (_currToken == t);
+ }
+
+ @Override public boolean isExpectedStartArrayToken() { return _currToken == JsonToken.START_ARRAY; }
+ @Override public boolean isExpectedStartObjectToken() { return _currToken == JsonToken.START_OBJECT; }
+
+ @Override
+ public JsonToken nextValue() throws IOException {
+ /* Implementation should be as trivial as follows; only
+ * needs to change if we are to skip other tokens (for
+ * example, if comments were exposed as tokens)
+ */
+ JsonToken t = nextToken();
+ if (t == JsonToken.FIELD_NAME) {
+ t = nextToken();
+ }
+ return t;
+ }
+
+ @Override
+ public JsonParser skipChildren() throws IOException
+ {
+ if (_currToken != JsonToken.START_OBJECT
+ && _currToken != JsonToken.START_ARRAY) {
+ return this;
+ }
+ int open = 1;
+
+ /* Since proper matching of start/end markers is handled
+ * by nextToken(), we'll just count nesting levels here
+ */
+ while (true) {
+ JsonToken t = nextToken();
+ if (t == null) {
+ _handleEOF();
+ /* given constraints, above should never return;
+ * however, FindBugs doesn't know about it and
+ * complains... so let's add dummy break here
+ */
+ return this;
+ }
+ if (t.isStructStart()) {
+ ++open;
+ } else if (t.isStructEnd()) {
+ if (--open == 0) {
+ return this;
+ }
+ }
+ }
+ }
+
+ /**
+ * Method sub-classes need to implement
+ */
+ protected abstract void _handleEOF() throws JsonParseException;
+
+ //public JsonToken getCurrentToken()
+ //public boolean hasCurrentToken()
+
+ @Override public abstract String getCurrentName() throws IOException;
+ @Override public abstract void close() throws IOException;
+ @Override public abstract boolean isClosed();
+
+ @Override public abstract JsonStreamContext getParsingContext();
+
+// public abstract JsonLocation getTokenLocation();
+
+// public abstract JsonLocation getCurrentLocation();
+
+ /*
+ /**********************************************************
+ /* Public API, token state overrides
+ /**********************************************************
+ */
+
+ @Override public void clearCurrentToken() {
+ if (_currToken != null) {
+ _lastClearedToken = _currToken;
+ _currToken = null;
+ }
+ }
+
+ @Override public JsonToken getLastClearedToken() { return _lastClearedToken; }
+
+ @Override public abstract void overrideCurrentName(String name);
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, text
+ /**********************************************************
+ */
+
+ @Override public abstract String getText() throws IOException;
+ @Override public abstract char[] getTextCharacters() throws IOException;
+ @Override public abstract boolean hasTextCharacters();
+ @Override public abstract int getTextLength() throws IOException;
+ @Override public abstract int getTextOffset() throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, binary
+ /**********************************************************
+ */
+
+ @Override public abstract byte[] getBinaryValue(Base64Variant b64variant) throws IOException;
+
+ /*
+ /**********************************************************
+ /* Public API, access with conversion/coercion
+ /**********************************************************
+ */
+
+ @Override
+ public boolean getValueAsBoolean(boolean defaultValue) throws IOException
+ {
+ JsonToken t = _currToken;
+ if (t != null) {
+ switch (t.id()) {
+ case ID_STRING:
+ String str = getText().trim();
+ if ("true".equals(str)) {
+ return true;
+ }
+ if ("false".equals(str)) {
+ return false;
+ }
+ if (_hasTextualNull(str)) {
+ return false;
+ }
+ break;
+ case ID_NUMBER_INT:
+ return getIntValue() != 0;
+ case ID_TRUE:
+ return true;
+ case ID_FALSE:
+ case ID_NULL:
+ return false;
+ case ID_EMBEDDED_OBJECT:
+ Object value = this.getEmbeddedObject();
+ if (value instanceof Boolean) {
+ return (Boolean) value;
+ }
+ break;
+ default:
+ }
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public int getValueAsInt() throws IOException
+ {
+ JsonToken t = _currToken;
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+ return getIntValue();
+ }
+ return getValueAsInt(0);
+ }
+
+ @Override
+ public int getValueAsInt(int defaultValue) throws IOException
+ {
+ JsonToken t = _currToken;
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+ return getIntValue();
+ }
+ if (t != null) {
+ switch (t.id()) {
+ case ID_STRING:
+ String str = getText();
+ if (_hasTextualNull(str)) {
+ return 0;
+ }
+ return NumberInput.parseAsInt(str, defaultValue);
+ case ID_TRUE:
+ return 1;
+ case ID_FALSE:
+ return 0;
+ case ID_NULL:
+ return 0;
+ case ID_EMBEDDED_OBJECT:
+ Object value = this.getEmbeddedObject();
+ if (value instanceof Number) {
+ return ((Number) value).intValue();
+ }
+ }
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public long getValueAsLong() throws IOException
+ {
+ JsonToken t = _currToken;
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+ return getLongValue();
+ }
+ return getValueAsLong(0L);
+ }
+
+ @Override
+ public long getValueAsLong(long defaultValue) throws IOException
+ {
+ JsonToken t = _currToken;
+ if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
+ return getLongValue();
+ }
+ if (t != null) {
+ switch (t.id()) {
+ case ID_STRING:
+ String str = getText();
+ if (_hasTextualNull(str)) {
+ return 0L;
+ }
+ return NumberInput.parseAsLong(str, defaultValue);
+ case ID_TRUE:
+ return 1L;
+ case ID_FALSE:
+ case ID_NULL:
+ return 0L;
+ case ID_EMBEDDED_OBJECT:
+ Object value = this.getEmbeddedObject();
+ if (value instanceof Number) {
+ return ((Number) value).longValue();
+ }
+ }
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public double getValueAsDouble(double defaultValue) throws IOException
+ {
+ JsonToken t = _currToken;
+ if (t != null) {
+ switch (t.id()) {
+ case ID_STRING:
+ String str = getText();
+ if (_hasTextualNull(str)) {
+ return 0L;
+ }
+ return NumberInput.parseAsDouble(str, defaultValue);
+ case ID_NUMBER_INT:
+ case ID_NUMBER_FLOAT:
+ return getDoubleValue();
+ case ID_TRUE:
+ return 1.0;
+ case ID_FALSE:
+ case ID_NULL:
+ return 0.0;
+ case ID_EMBEDDED_OBJECT:
+ Object value = this.getEmbeddedObject();
+ if (value instanceof Number) {
+ return ((Number) value).doubleValue();
+ }
+ }
+ }
+ return defaultValue;
+ }
+
+ @Override
+ public String getValueAsString() throws IOException {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ return getText();
+ }
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return getCurrentName();
+ }
+ return getValueAsString(null);
+ }
+
+ @Override
+ public String getValueAsString(String defaultValue) throws IOException {
+ if (_currToken == JsonToken.VALUE_STRING) {
+ return getText();
+ }
+ if (_currToken == JsonToken.FIELD_NAME) {
+ return getCurrentName();
+ }
+ if (_currToken == null || _currToken == JsonToken.VALUE_NULL || !_currToken.isScalarValue()) {
+ return defaultValue;
+ }
+ return getText();
+ }
+
+ /*
+ /**********************************************************
+ /* Base64 decoding
+ /**********************************************************
+ */
+
+ /**
+ * Helper method that can be used for base64 decoding in cases where
+ * encoded content has already been read as a String.
+ */
+ protected void _decodeBase64(String str, ByteArrayBuilder builder, Base64Variant b64variant) throws IOException
+ {
+ // just call helper method introduced in 2.2.3
+ try {
+ b64variant.decode(str, builder);
+ } catch (IllegalArgumentException e) {
+ _reportError(e.getMessage());
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Coercion helper methods (overridable)
+ /**********************************************************
+ */
+
+ /**
+ * Helper method used to determine whether we are currently pointing to
+ * a String value of "null" (NOT a null token); and, if so, that parser
+ * is to recognize and return it similar to if it was real null token.
+ *
+ * @since 2.3
+ */
+ protected boolean _hasTextualNull(String value) { return "null".equals(value); }
+
+ /*
+ /**********************************************************
+ /* Error reporting
+ /**********************************************************
+ */
+
+ protected void _reportUnexpectedChar(int ch, String comment) throws JsonParseException
+ {
+ if (ch < 0) { // sanity check
+ _reportInvalidEOF();
+ }
+ String msg = "Unexpected character ("+_getCharDesc(ch)+")";
+ if (comment != null) {
+ msg += ": "+comment;
+ }
+ _reportError(msg);
+ }
+
+ protected void _reportInvalidEOF() throws JsonParseException {
+ _reportInvalidEOF(" in "+_currToken);
+ }
+
+ protected void _reportInvalidEOF(String msg) throws JsonParseException {
+ _reportError("Unexpected end-of-input"+msg);
+ }
+
+ protected void _reportInvalidEOFInValue() throws JsonParseException {
+ _reportInvalidEOF(" in a value");
+ }
+
+ protected void _reportMissingRootWS(int ch) throws JsonParseException {
+ _reportUnexpectedChar(ch, "Expected space separating root-level values");
+ }
+
+ protected void _throwInvalidSpace(int i) throws JsonParseException {
+ char c = (char) i;
+ String msg = "Illegal character ("+_getCharDesc(c)+"): only regular white space (\\r, \\n, \\t) is allowed between tokens";
+ _reportError(msg);
+ }
+
+ /**
+ * Method called to report a problem with unquoted control character.
+ * Note: starting with version 1.4, it is possible to suppress
+ * exception by enabling {@link Feature#ALLOW_UNQUOTED_CONTROL_CHARS}.
+ */
+ protected void _throwUnquotedSpace(int i, String ctxtDesc) throws JsonParseException {
+ // JACKSON-208; possible to allow unquoted control chars:
+ if (!isEnabled(Feature.ALLOW_UNQUOTED_CONTROL_CHARS) || i > INT_SPACE) {
+ char c = (char) i;
+ String msg = "Illegal unquoted character ("+_getCharDesc(c)+"): has to be escaped using backslash to be included in "+ctxtDesc;
+ _reportError(msg);
+ }
+ }
+
+ protected char _handleUnrecognizedCharacterEscape(char ch) throws JsonProcessingException {
+ // as per [JACKSON-300]
+ if (isEnabled(Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER)) {
+ return ch;
+ }
+ // and [JACKSON-548]
+ if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
+ return ch;
+ }
+ _reportError("Unrecognized character escape "+_getCharDesc(ch));
+ return ch;
+ }
+
+ /*
+ /**********************************************************
+ /* Error reporting, generic
+ /**********************************************************
+ */
+
+ protected final static String _getCharDesc(int ch)
+ {
+ char c = (char) ch;
+ if (Character.isISOControl(c)) {
+ return "(CTRL-CHAR, code "+ch+")";
+ }
+ if (ch > 255) {
+ return "'"+c+"' (code "+ch+" / 0x"+Integer.toHexString(ch)+")";
+ }
+ return "'"+c+"' (code "+ch+")";
+ }
+
+ protected final void _reportError(String msg) throws JsonParseException {
+ throw _constructError(msg);
+ }
+
+ protected final void _wrapError(String msg, Throwable t) throws JsonParseException {
+ throw _constructError(msg, t);
+ }
+
+ protected final void _throwInternal() {
+ VersionUtil.throwInternal();
+ }
+
+ protected final JsonParseException _constructError(String msg, Throwable t) {
+ return new JsonParseException(this, msg, t);
+ }
+
+ protected static byte[] _asciiBytes(String str) {
+ byte[] b = new byte[str.length()];
+ for (int i = 0, len = str.length(); i < len; ++i) {
+ b[i] = (byte) str.charAt(i);
+ }
+ return b;
+ }
+
+ protected static String _ascii(byte[] b) {
+ try {
+ return new String(b, "US-ASCII");
+ } catch (IOException e) { // never occurs
+ throw new RuntimeException(e);
+ }
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/base/package-info.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/base/package-info.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/base/package-info.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,9 @@
+/**
+ * Base classes used by concrete Parser and Generator implementations;
+ * contain functionality that is not specific to JSON or input
+ * abstraction (byte vs char).
+ * Most formats extend these types, although it is also possible to
+ * directly extend {@link com.fasterxml.jackson.core.JsonParser} or
+ * {@link com.fasterxml.jackson.core.JsonGenerator}.
+ */
+package com.fasterxml.jackson.core.base;
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/FilteringGeneratorDelegate.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,868 @@
+package com.fasterxml.jackson.core.filter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.util.JsonGeneratorDelegate;
+
+/**
+ * Specialized {@link JsonGeneratorDelegate} that allows use of
+ * {@link TokenFilter} for outputting a subset of content that
+ * caller tries to generate.
+ *
+ * @since 2.6
+ */
+public class FilteringGeneratorDelegate extends JsonGeneratorDelegate
+{
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Object consulted to determine whether to write parts of content generator
+ * is asked to write or not.
+ */
+ protected TokenFilter rootFilter;
+
+ /**
+ * Flag that determines whether filtering will continue after the first
+ * match is indicated or not: if `false`, output is based on just the first
+ * full match (returning {@link TokenFilter#INCLUDE_ALL}) and no more
+ * checks are made; if `true` then filtering will be applied as necessary
+ * until end of content.
+ */
+ protected boolean _allowMultipleMatches;
+
+ /**
+ * Flag that determines whether path leading up to included content should
+ * also be automatically included or not. If `false`, no path inclusion is
+ * done and only explicitly included entries are output; if `true` then
+ * path from main level down to match is also included as necessary.
+ */
+ protected boolean _includePath;
+
+ /* NOTE: this feature is included in the first version (2.6), but
+ * there is no public API to enable it, yet, since there isn't an
+ * actual use case. But it seemed possible need could arise, which
+ * is feature has not yet been removed. If no use is found within
+ * first version or two, just remove.
+ *
+ * Marked as deprecated since its status is uncertain.
+ */
+ @Deprecated
+ protected boolean _includeImmediateParent;
+
+ /*
+ /**********************************************************
+ /* Additional state
+ /**********************************************************
+ */
+
+ /**
+ * Although delegate has its own output context it is not sufficient since we actually
+ * have to keep track of excluded (filtered out) structures as well as ones delegate
+ * actually outputs.
+ */
+ protected TokenFilterContext _filterContext;
+
+ /**
+ * State that applies to the item within container, used where applicable.
+ * Specifically used to pass inclusion state between property name and
+ * property, and also used for array elements.
+ */
+ protected TokenFilter _itemFilter;
+
+ /**
+ * Number of tokens for which {@link TokenFilter#INCLUDE_ALL}
+ * has been returned
+ */
+ protected int _matchCount;
+
+ /*
+ /**********************************************************
+ /* Construction, initialization
+ /**********************************************************
+ */
+
+ public FilteringGeneratorDelegate(JsonGenerator d, TokenFilter f,
+ boolean includePath, boolean allowMultipleMatches)
+ {
+ // By default, do NOT delegate copy methods
+ super(d, false);
+ rootFilter = f;
+ // and this is the currently active filter for root values
+ _itemFilter = f;
+ _filterContext = TokenFilterContext.createRootContext(f);
+ _includePath = includePath;
+ _allowMultipleMatches = allowMultipleMatches;
+ }
+
+ /*
+ /**********************************************************
+ /* Extended API
+ /**********************************************************
+ */
+
+ public TokenFilter getFilter() { return rootFilter; }
+
+ public JsonStreamContext getFilterContext() {
+ return _filterContext;
+ }
+
+ /**
+ * Accessor for finding number of matches, where specific token and sub-tree
+ * starting (if structured type) are passed.
+ */
+ public int getMatchCount() {
+ return _matchCount;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, accessors
+ /**********************************************************
+ */
+
+ @Override
+ public JsonStreamContext getOutputContext() {
+ /* 11-Apr-2015, tatu: Choice is between pre- and post-filter context;
+ * let's expose post-filter context that correlates with the view
+ * of caller.
+ */
+ return _filterContext;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, structural
+ /**********************************************************
+ */
+
+ @Override
+ public void writeStartArray() throws IOException
+ {
+ // First things first: whole-sale skipping easy
+ if (_itemFilter == null) {
+ _filterContext = _filterContext.createChildArrayContext(null, false);
+ return;
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) { // include the whole sub-tree?
+ _filterContext = _filterContext.createChildArrayContext(_itemFilter, true);
+ delegate.writeStartArray();
+ return;
+ }
+ // Ok; regular checking state then
+ _itemFilter = _filterContext.checkValue(_itemFilter);
+ if (_itemFilter == null) {
+ _filterContext = _filterContext.createChildArrayContext(null, false);
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ _itemFilter = _itemFilter.filterStartArray();
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+ _checkParentPath();
+ _filterContext = _filterContext.createChildArrayContext(_itemFilter, true);
+ delegate.writeStartArray();
+ } else {
+ _filterContext = _filterContext.createChildArrayContext(_itemFilter, false);
+ }
+ }
+
+ @Override
+ public void writeStartArray(int size) throws IOException
+ {
+ if (_itemFilter == null) {
+ _filterContext = _filterContext.createChildArrayContext(null, false);
+ return;
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+ _filterContext = _filterContext.createChildArrayContext(_itemFilter, true);
+ delegate.writeStartArray(size);
+ return;
+ }
+ _itemFilter = _filterContext.checkValue(_itemFilter);
+ if (_itemFilter == null) {
+ _filterContext = _filterContext.createChildArrayContext(null, false);
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ _itemFilter = _itemFilter.filterStartArray();
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+ _checkParentPath();
+ _filterContext = _filterContext.createChildArrayContext(_itemFilter, true);
+ delegate.writeStartArray(size);
+ } else {
+ _filterContext = _filterContext.createChildArrayContext(_itemFilter, false);
+ }
+ }
+
+ @Override
+ public void writeEndArray() throws IOException
+ {
+ _filterContext = _filterContext.closeArray(delegate);
+
+ if (_filterContext != null) {
+ _itemFilter = _filterContext.getFilter();
+ }
+ }
+
+ @Override
+ public void writeStartObject() throws IOException
+ {
+ if (_itemFilter == null) {
+ _filterContext = _filterContext.createChildObjectContext(_itemFilter, false);
+ return;
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+ _filterContext = _filterContext.createChildObjectContext(_itemFilter, true);
+ delegate.writeStartObject();
+ return;
+ }
+
+ TokenFilter f = _filterContext.checkValue(_itemFilter);
+ if (f == null) {
+ return;
+ }
+
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartObject();
+ }
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _checkParentPath();
+ _filterContext = _filterContext.createChildObjectContext(f, true);
+ delegate.writeStartObject();
+ } else { // filter out
+ _filterContext = _filterContext.createChildObjectContext(f, false);
+ }
+ }
+
+ @Override
+ public void writeEndObject() throws IOException
+ {
+ _filterContext = _filterContext.closeObject(delegate);
+ if (_filterContext != null) {
+ _itemFilter = _filterContext.getFilter();
+ }
+ }
+
+ @Override
+ public void writeFieldName(String name) throws IOException
+ {
+ TokenFilter state = _filterContext.setFieldName(name);
+ if (state == null) {
+ _itemFilter = null;
+ return;
+ }
+ if (state == TokenFilter.INCLUDE_ALL) {
+ _itemFilter = state;
+ delegate.writeFieldName(name);
+ return;
+ }
+ state = state.includeProperty(name);
+ _itemFilter = state;
+ if (state == TokenFilter.INCLUDE_ALL) {
+ _checkPropertyParentPath();
+ }
+ }
+
+ @Override
+ public void writeFieldName(SerializableString name) throws IOException
+ {
+ TokenFilter state = _filterContext.setFieldName(name.getValue());
+ if (state == null) {
+ _itemFilter = null;
+ return;
+ }
+ if (state == TokenFilter.INCLUDE_ALL) {
+ _itemFilter = state;
+ delegate.writeFieldName(name);
+ return;
+ }
+ state = state.includeProperty(name.getValue());
+ _itemFilter = state;
+ if (state == TokenFilter.INCLUDE_ALL) {
+ _checkPropertyParentPath();
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, text/String values
+ /**********************************************************
+ */
+
+ @Override
+ public void writeString(String value) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeString(value)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeString(value);
+ }
+
+ @Override
+ public void writeString(char[] text, int offset, int len) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ String value = new String(text, offset, len);
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeString(value)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeString(text, offset, len);
+ }
+
+ @Override
+ public void writeString(SerializableString value) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeString(value.getValue())) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeString(value);
+ }
+
+ @Override
+ public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRawUTF8String(text, offset, length);
+ }
+ }
+
+ @Override
+ public void writeUTF8String(byte[] text, int offset, int length) throws IOException
+ {
+ // not exact match, but best we can do
+ if (_checkRawValueWrite()) {
+ delegate.writeRawUTF8String(text, offset, length);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, binary/raw content
+ /**********************************************************
+ */
+
+ @Override
+ public void writeRaw(String text) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text);
+ }
+ }
+
+ @Override
+ public void writeRaw(String text, int offset, int len) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text);
+ }
+ }
+
+ @Override
+ public void writeRaw(SerializableString text) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text);
+ }
+ }
+
+ @Override
+ public void writeRaw(char[] text, int offset, int len) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text, offset, len);
+ }
+ }
+
+ @Override
+ public void writeRaw(char c) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(c);
+ }
+ }
+
+ @Override
+ public void writeRawValue(String text) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text);
+ }
+ }
+
+ @Override
+ public void writeRawValue(String text, int offset, int len) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text, offset, len);
+ }
+ }
+
+ @Override
+ public void writeRawValue(char[] text, int offset, int len) throws IOException
+ {
+ if (_checkRawValueWrite()) {
+ delegate.writeRaw(text, offset, len);
+ }
+ }
+
+ @Override
+ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException
+ {
+ if (_checkBinaryWrite()) {
+ delegate.writeBinary(b64variant, data, offset, len);
+ }
+ }
+
+ @Override
+ public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException
+ {
+ if (_checkBinaryWrite()) {
+ return delegate.writeBinary(b64variant, data, dataLength);
+ }
+ return -1;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, other value types
+ /**********************************************************
+ */
+
+ @Override
+ public void writeNumber(short v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(int v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(long v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(BigInteger v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(double v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(float v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(BigDecimal v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNumber(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(v);
+ }
+
+ @Override
+ public void writeNumber(String encodedValue) throws IOException, UnsupportedOperationException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeRawValue()) { // close enough?
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNumber(encodedValue);
+ }
+
+ @Override
+ public void writeBoolean(boolean v) throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeBoolean(v)) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeBoolean(v);
+ }
+
+ @Override
+ public void writeNull() throws IOException
+ {
+ if (_itemFilter == null) {
+ return;
+ }
+ if (_itemFilter != TokenFilter.INCLUDE_ALL) {
+ TokenFilter state = _filterContext.checkValue(_itemFilter);
+ if (state == null) {
+ return;
+ }
+ if (state != TokenFilter.INCLUDE_ALL) {
+ if (!state.includeNull()) {
+ return;
+ }
+ }
+ _checkParentPath();
+ }
+ delegate.writeNull();
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden field methods
+ /**********************************************************
+ */
+
+ @Override
+ public void writeOmittedField(String fieldName) throws IOException {
+ // Hmmh. Not sure how this would work but...
+ if (_itemFilter != null) {
+ delegate.writeOmittedField(fieldName);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, Native Ids
+ /**********************************************************
+ */
+
+ // 25-Mar-2015, tatu: These are tricky as they sort of predate actual filtering calls.
+ // Let's try to use current state as a clue at least...
+
+ @Override
+ public void writeObjectId(Object id) throws IOException {
+ if (_itemFilter != null) {
+ delegate.writeObjectId(id);
+ }
+ }
+
+ @Override
+ public void writeObjectRef(Object id) throws IOException {
+ if (_itemFilter != null) {
+ delegate.writeObjectRef(id);
+ }
+ }
+
+ @Override
+ public void writeTypeId(Object id) throws IOException {
+ if (_itemFilter != null) {
+ delegate.writeTypeId(id);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, serializing Java objects
+ /**********************************************************
+ */
+
+ // Base class definitions for these seems correct to me, iff not directly delegating:
+
+ /*
+ @Override
+ public void writeObject(Object pojo) throws IOException,JsonProcessingException {
+ if (delegateCopyMethods) {
+ delegate.writeObject(pojo);
+ return;
+ }
+ // NOTE: copied from
+ if (pojo == null) {
+ writeNull();
+ } else {
+ if (getCodec() != null) {
+ getCodec().writeValue(this, pojo);
+ return;
+ }
+ _writeSimpleObject(pojo);
+ }
+ }
+
+ @Override
+ public void writeTree(TreeNode rootNode) throws IOException {
+ if (delegateCopyMethods) {
+ delegate.writeTree(rootNode);
+ return;
+ }
+ // As with 'writeObject()', we are not check if write would work
+ if (rootNode == null) {
+ writeNull();
+ } else {
+ if (getCodec() == null) {
+ throw new IllegalStateException("No ObjectCodec defined");
+ }
+ getCodec().writeValue(this, rootNode);
+ }
+ }
+ */
+
+ /*
+ /**********************************************************
+ /* Public API, copy-through methods
+ /**********************************************************
+ */
+
+ // Base class definitions for these seems correct to me, iff not directly delegating:
+
+ /*
+ @Override
+ public void copyCurrentEvent(JsonParser jp) throws IOException {
+ if (delegateCopyMethods) delegate.copyCurrentEvent(jp);
+ else super.copyCurrentEvent(jp);
+ }
+
+ @Override
+ public void copyCurrentStructure(JsonParser jp) throws IOException {
+ if (delegateCopyMethods) delegate.copyCurrentStructure(jp);
+ else super.copyCurrentStructure(jp);
+ }
+ */
+
+ /*
+ /**********************************************************
+ /* Helper methods
+ /**********************************************************
+ */
+
+ protected void _checkParentPath() throws IOException
+ {
+ ++_matchCount;
+ // only need to construct path if parent wasn't written
+ if (_includePath) {
+ _filterContext.writePath(delegate);
+ }
+ // also: if no multiple matches desired, short-cut checks
+ if (!_allowMultipleMatches) {
+ // Mark parents as "skip" so that further check calls are not made
+ _filterContext.skipParentChecks();
+ }
+ }
+
+ /**
+ * Specialized variant of {@link #_checkParentPath} used when checking
+ * parent for a property name to be included with value: rules are slightly
+ * different.
+ */
+ protected void _checkPropertyParentPath() throws IOException
+ {
+ ++_matchCount;
+ if (_includePath) {
+ _filterContext.writePath(delegate);
+ } else if (_includeImmediateParent) {
+ // 21-Apr-2015, tatu: Note that there is no API to enable this currently...
+ // retained for speculative future use
+ _filterContext.writeImmediatePath(delegate);
+ }
+
+ // also: if no multiple matches desired, short-cut checks
+ if (!_allowMultipleMatches) {
+ // Mark parents as "skip" so that further check calls are not made
+ _filterContext.skipParentChecks();
+ }
+ }
+
+ protected boolean _checkBinaryWrite() throws IOException
+ {
+ if (_itemFilter == null) {
+ return false;
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+ return true;
+ }
+ if (_itemFilter.includeBinary()) { // close enough?
+ _checkParentPath();
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean _checkRawValueWrite() throws IOException
+ {
+ if (_itemFilter == null) {
+ return false;
+ }
+ if (_itemFilter == TokenFilter.INCLUDE_ALL) {
+ return true;
+ }
+ if (_itemFilter.includeRawValue()) { // close enough?
+ _checkParentPath();
+ return true;
+ }
+ return false;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/FilteringParserDelegate.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,896 @@
+package com.fasterxml.jackson.core.filter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.util.JsonParserDelegate;
+
+import static com.fasterxml.jackson.core.JsonTokenId.*;
+
+/**
+ * Specialized {@link JsonParserDelegate} that allows use of
+ * {@link TokenFilter} for outputting a subset of content that
+ * is visible to caller
+ *
+ * @since 2.6
+ */
+public class FilteringParserDelegate extends JsonParserDelegate
+{
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Object consulted to determine whether to write parts of content generator
+ * is asked to write or not.
+ */
+ protected TokenFilter rootFilter;
+
+ /**
+ * Flag that determines whether filtering will continue after the first
+ * match is indicated or not: if `false`, output is based on just the first
+ * full match (returning {@link TokenFilter#INCLUDE_ALL}) and no more
+ * checks are made; if `true` then filtering will be applied as necessary
+ * until end of content.
+ */
+ protected boolean _allowMultipleMatches;
+
+ /**
+ * Flag that determines whether path leading up to included content should
+ * also be automatically included or not. If `false`, no path inclusion is
+ * done and only explicitly included entries are output; if `true` then
+ * path from main level down to match is also included as necessary.
+ */
+ protected boolean _includePath;
+
+ /* NOTE: this feature is included in the first version (2.6), but
+ * there is no public API to enable it, yet, since there isn't an
+ * actual use case. But it seemed possible need could arise, which
+ * is feature has not yet been removed. If no use is found within
+ * first version or two, just remove.
+ *
+ * Marked as deprecated since its status is uncertain.
+ */
+ @Deprecated
+ protected boolean _includeImmediateParent;
+
+ /*
+ /**********************************************************
+ /* State
+ /**********************************************************
+ */
+
+ /**
+ * Last token retrieved via {@link #nextToken}, if any.
+ * Null before the first call to nextToken()
,
+ * as well as if token has been explicitly cleared
+ */
+ protected JsonToken _currToken;
+
+ /**
+ * Last cleared token, if any: that is, value that was in
+ * effect when {@link #clearCurrentToken} was called.
+ */
+ protected JsonToken _lastClearedToken;
+
+ /**
+ * During traversal this is the actual "open" parse tree, which sometimes
+ * is the same as {@link #_exposedContext}, and at other times is ahead
+ * of it. Note that this context is never null.
+ */
+ protected TokenFilterContext _headContext;
+
+ /**
+ * In cases where {@link #_headContext} is "ahead" of context exposed to
+ * caller, this context points to what is currently exposed to caller.
+ * When the two are in sync, this context reference will be null
.
+ */
+ protected TokenFilterContext _exposedContext;
+
+ /**
+ * State that applies to the item within container, used where applicable.
+ * Specifically used to pass inclusion state between property name and
+ * property, and also used for array elements.
+ */
+ protected TokenFilter _itemFilter;
+
+ /**
+ * Number of tokens for which {@link TokenFilter#INCLUDE_ALL}
+ * has been returned.
+ */
+ protected int _matchCount;
+
+ /*
+ /**********************************************************
+ /* Construction, initialization
+ /**********************************************************
+ */
+
+ public FilteringParserDelegate(JsonParser p, TokenFilter f,
+ boolean includePath, boolean allowMultipleMatches)
+ {
+ super(p);
+ rootFilter = f;
+ // and this is the currently active filter for root values
+ _itemFilter = f;
+ _headContext = TokenFilterContext.createRootContext(f);
+ _includePath = includePath;
+ _allowMultipleMatches = allowMultipleMatches;
+ }
+
+ /*
+ /**********************************************************
+ /* Extended API
+ /**********************************************************
+ */
+
+ public TokenFilter getFilter() { return rootFilter; }
+
+ /**
+ * Accessor for finding number of matches, where specific token and sub-tree
+ * starting (if structured type) are passed.
+ */
+ public int getMatchCount() {
+ return _matchCount;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, token accessors
+ /**********************************************************
+ */
+
+ @Override public JsonToken getCurrentToken() { return _currToken; }
+
+ @Override public final int getCurrentTokenId() {
+ final JsonToken t = _currToken;
+ return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
+ }
+
+ @Override public boolean hasCurrentToken() { return _currToken != null; }
+ @Override public boolean hasTokenId(int id) {
+ final JsonToken t = _currToken;
+ if (t == null) {
+ return (JsonTokenId.ID_NO_TOKEN == id);
+ }
+ return t.id() == id;
+ }
+
+ @Override public final boolean hasToken(JsonToken t) {
+ return (_currToken == t);
+ }
+
+ @Override public boolean isExpectedStartArrayToken() { return _currToken == JsonToken.START_ARRAY; }
+ @Override public boolean isExpectedStartObjectToken() { return _currToken == JsonToken.START_OBJECT; }
+
+ @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
+
+ @Override
+ public JsonStreamContext getParsingContext() {
+ return _filterContext();
+ }
+
+ // !!! TODO: Verify it works as expected: copied from standard JSON parser impl
+ @Override
+ public String getCurrentName() throws IOException {
+ JsonStreamContext ctxt = _filterContext();
+ if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
+ JsonStreamContext parent = ctxt.getParent();
+ return (parent == null) ? null : parent.getCurrentName();
+ }
+ return ctxt.getCurrentName();
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, token state overrides
+ /**********************************************************
+ */
+
+ @Override
+ public void clearCurrentToken() {
+ if (_currToken != null) {
+ _lastClearedToken = _currToken;
+ _currToken = null;
+ }
+ }
+
+ @Override
+ public JsonToken getLastClearedToken() { return _lastClearedToken; }
+
+ @Override
+ public void overrideCurrentName(String name) {
+ /* 14-Apr-2015, tatu: Not sure whether this can be supported, and if so,
+ * what to do with it... Delegation won't work for sure, so let's for
+ * now throw an exception
+ */
+ throw new UnsupportedOperationException("Can not currently override name during filtering read");
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, traversal
+ /**********************************************************
+ */
+
+ @Override
+ public JsonToken nextToken() throws IOException
+ {
+ //Check for _allowMultipleMatches - false and atleast there is one token - which is _currToken
+ // check for no buffered context _exposedContext - null
+ //If all the conditions matches then check for scalar / non-scalar property
+ if(!_allowMultipleMatches && _currToken != null && _exposedContext == null){
+ //if not scalar and ended successfully, then return null
+ if((_currToken.isStructEnd() && _headContext.isStartHandled()) ){
+ return (_currToken = null);
+ }
+ //else if scalar, and scalar not present in obj/array and !includePath and INCLUDE_ALL matched once
+ // then return null
+ else if(_currToken.isScalarValue() && !_headContext.isStartHandled() && !_includePath
+ && _itemFilter == TokenFilter.INCLUDE_ALL) {
+ return (_currToken = null);
+ }
+ }
+ // Anything buffered?
+ TokenFilterContext ctxt = _exposedContext;
+
+ if (ctxt != null) {
+ while (true) {
+ JsonToken t = ctxt.nextTokenToRead();
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ // all done with buffered stuff?
+ if (ctxt == _headContext) {
+ _exposedContext = null;
+ if (ctxt.inArray()) {
+ t = delegate.getCurrentToken();
+// Is this guaranteed to work without further checks?
+// if (t != JsonToken.START_ARRAY) {
+ _currToken = t;
+ return t;
+ }
+
+ // Almost! Most likely still have the current token;
+ // with the sole exception of
+ /*
+ t = delegate.getCurrentToken();
+ if (t != JsonToken.FIELD_NAME) {
+ _currToken = t;
+ return t;
+ }
+ */
+ break;
+ }
+ // If not, traverse down the context chain
+ ctxt = _headContext.findChildOf(ctxt);
+ _exposedContext = ctxt;
+ if (ctxt == null) { // should never occur
+ throw _constructError("Unexpected problem: chain of filtered context broken");
+ }
+ }
+ }
+
+ // If not, need to read more. If we got any:
+ JsonToken t = delegate.nextToken();
+ if (t == null) {
+ // no strict need to close, since we have no state here
+ return (_currToken = t);
+ }
+
+ // otherwise... to include or not?
+ TokenFilter f;
+
+ switch (t.id()) {
+ case ID_START_ARRAY:
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildArrayContext(f, true);
+ return (_currToken = t);
+ }
+ if (f == null) { // does this occur?
+ delegate.skipChildren();
+ break;
+ }
+ // Otherwise still iffy, need to check
+ f = _headContext.checkValue(f);
+ if (f == null) {
+ delegate.skipChildren();
+ break;
+ }
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartArray();
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildArrayContext(f, true);
+ return (_currToken = t);
+ }
+ _headContext = _headContext.createChildArrayContext(f, false);
+
+ // Also: only need buffering if parent path to be included
+ if (_includePath) {
+ t = _nextTokenWithBuffering(_headContext);
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ }
+ break;
+
+ case ID_START_OBJECT:
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildObjectContext(f, true);
+ return (_currToken = t);
+ }
+ if (f == null) { // does this occur?
+ delegate.skipChildren();
+ break;
+ }
+ // Otherwise still iffy, need to check
+ f = _headContext.checkValue(f);
+ if (f == null) {
+ delegate.skipChildren();
+ break;
+ }
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartObject();
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildObjectContext(f, true);
+ return (_currToken = t);
+ }
+ _headContext = _headContext.createChildObjectContext(f, false);
+ // Also: only need buffering if parent path to be included
+ if (_includePath) {
+ t = _nextTokenWithBuffering(_headContext);
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ }
+ // note: inclusion of surrounding Object handled separately via
+ // FIELD_NAME
+ break;
+
+ case ID_END_ARRAY:
+ case ID_END_OBJECT:
+ {
+ boolean returnEnd = _headContext.isStartHandled();
+ f = _headContext.getFilter();
+ if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
+ f.filterFinishArray();
+ }
+ _headContext = _headContext.getParent();
+ _itemFilter = _headContext.getFilter();
+ if (returnEnd) {
+ return (_currToken = t);
+ }
+ }
+ break;
+
+ case ID_FIELD_NAME:
+ {
+ final String name = delegate.getCurrentName();
+ // note: this will also set 'needToHandleName'
+ f = _headContext.setFieldName(name);
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _itemFilter = f;
+ if (!_includePath) {
+ // Minor twist here: if parent NOT included, may need to induce output of
+ // surrounding START_OBJECT/END_OBJECT
+ if (_includeImmediateParent && !_headContext.isStartHandled()) {
+ t = _headContext.nextTokenToRead(); // returns START_OBJECT but also marks it handled
+ _exposedContext = _headContext;
+ }
+ }
+ return (_currToken = t);
+ }
+ if (f == null) {
+ delegate.nextToken();
+ delegate.skipChildren();
+ break;
+ }
+ f = f.includeProperty(name);
+ if (f == null) {
+ delegate.nextToken();
+ delegate.skipChildren();
+ break;
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ if (_includePath) {
+ return (_currToken = t);
+ }
+ }
+ if (_includePath) {
+ t = _nextTokenWithBuffering(_headContext);
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ }
+ break;
+ }
+
+ default: // scalar value
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ return (_currToken = t);
+ }
+ if (f != null) {
+ f = _headContext.checkValue(f);
+ if ((f == TokenFilter.INCLUDE_ALL)
+ || ((f != null) && f.includeValue(delegate))) {
+ return (_currToken = t);
+ }
+ }
+ // Otherwise not included (leaves must be explicitly included)
+ break;
+ }
+
+ // We get here if token was not yet found; offlined handling
+ return _nextToken2();
+ }
+
+ /**
+ * Offlined handling for cases where there was no buffered token to
+ * return, and the token read next could not be returned as-is,
+ * at least not yet, but where we have not yet established that
+ * buffering is needed.
+ */
+ protected final JsonToken _nextToken2() throws IOException
+ {
+ main_loop:
+ while (true) {
+ JsonToken t = delegate.nextToken();
+ if (t == null) { // is this even legal?
+ return (_currToken = t);
+ }
+ TokenFilter f;
+
+ switch (t.id()) {
+ case ID_START_ARRAY:
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildArrayContext(f, true);
+ return (_currToken = t);
+ }
+ if (f == null) { // does this occur?
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ // Otherwise still iffy, need to check
+ f = _headContext.checkValue(f);
+ if (f == null) {
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartArray();
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildArrayContext(f, true);
+ return (_currToken = t);
+ }
+ _headContext = _headContext.createChildArrayContext(f, false);
+ // but if we didn't figure it out yet, need to buffer possible events
+ if (_includePath) {
+ t = _nextTokenWithBuffering(_headContext);
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ }
+ continue main_loop;
+
+ case ID_START_OBJECT:
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildObjectContext(f, true);
+ return (_currToken = t);
+ }
+ if (f == null) { // does this occur?
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ // Otherwise still iffy, need to check
+ f = _headContext.checkValue(f);
+ if (f == null) {
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartObject();
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildObjectContext(f, true);
+ return (_currToken = t);
+ }
+ _headContext = _headContext.createChildObjectContext(f, false);
+ if (_includePath) {
+ t = _nextTokenWithBuffering(_headContext);
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ }
+ continue main_loop;
+
+ case ID_END_ARRAY:
+ case ID_END_OBJECT:
+ {
+ boolean returnEnd = _headContext.isStartHandled();
+ f = _headContext.getFilter();
+ if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
+ f.filterFinishArray();
+ }
+ _headContext = _headContext.getParent();
+ _itemFilter = _headContext.getFilter();
+ if (returnEnd) {
+ return (_currToken = t);
+ }
+ }
+ continue main_loop;
+
+ case ID_FIELD_NAME:
+ {
+ final String name = delegate.getCurrentName();
+ f = _headContext.setFieldName(name);
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _itemFilter = f;
+ return (_currToken = t);
+ }
+ if (f == null) { // filter out the value
+ delegate.nextToken();
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ f = f.includeProperty(name);
+ if (f == null) { // filter out the value
+ delegate.nextToken();
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ if (_includePath) {
+ return (_currToken = t);
+ }
+// if (_includeImmediateParent) { ...
+ continue main_loop;
+ }
+ if (_includePath) {
+ t = _nextTokenWithBuffering(_headContext);
+ if (t != null) {
+ _currToken = t;
+ return t;
+ }
+ }
+ }
+ continue main_loop;
+
+ default: // scalar value
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ return (_currToken = t);
+ }
+ if (f != null) {
+ f = _headContext.checkValue(f);
+ if ((f == TokenFilter.INCLUDE_ALL)
+ || ((f != null) && f.includeValue(delegate))) {
+ return (_currToken = t);
+ }
+ }
+ // Otherwise not included (leaves must be explicitly included)
+ break;
+ }
+ }
+ }
+
+ /**
+ * Method called when a new potentially included context is found.
+ */
+ protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffRoot)
+ throws IOException
+ {
+ main_loop:
+ while (true) {
+ JsonToken t = delegate.nextToken();
+ if (t == null) { // is this even legal?
+ return t;
+ }
+ TokenFilter f;
+
+ // One simplification here: we know for a fact that the item filter is
+ // neither null nor 'include all', for most cases; the only exception
+ // being FIELD_NAME handling
+
+ switch (t.id()) {
+ case ID_START_ARRAY:
+ f = _headContext.checkValue(_itemFilter);
+ if (f == null) {
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartArray();
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildArrayContext(f, true);
+ return _nextBuffered(buffRoot);
+ }
+ _headContext = _headContext.createChildArrayContext(f, false);
+ continue main_loop;
+
+ case ID_START_OBJECT:
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildObjectContext(f, true);
+ return t;
+ }
+ if (f == null) { // does this occur?
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ // Otherwise still iffy, need to check
+ f = _headContext.checkValue(f);
+ if (f == null) {
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ if (f != TokenFilter.INCLUDE_ALL) {
+ f = f.filterStartObject();
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _headContext = _headContext.createChildObjectContext(f, true);
+ return _nextBuffered(buffRoot);
+ }
+ _headContext = _headContext.createChildObjectContext(f, false);
+ continue main_loop;
+
+ case ID_END_ARRAY:
+ case ID_END_OBJECT:
+ {
+ // Unlike with other loops, here we know that content was NOT
+ // included (won't get this far otherwise)
+ f = _headContext.getFilter();
+ if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
+ f.filterFinishArray();
+ }
+ boolean gotEnd = (_headContext == buffRoot);
+ boolean returnEnd = gotEnd && _headContext.isStartHandled();
+
+ _headContext = _headContext.getParent();
+ _itemFilter = _headContext.getFilter();
+
+ if (returnEnd) {
+ return t;
+ }
+ // Hmmh. Do we need both checks, or should above suffice?
+ if (gotEnd || (_headContext == buffRoot)) {
+ return null;
+ }
+ }
+ continue main_loop;
+
+ case ID_FIELD_NAME:
+ {
+ final String name = delegate.getCurrentName();
+ f = _headContext.setFieldName(name);
+ if (f == TokenFilter.INCLUDE_ALL) {
+ _itemFilter = f;
+ return _nextBuffered(buffRoot);
+ }
+ if (f == null) { // filter out the value
+ delegate.nextToken();
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ f = f.includeProperty(name);
+ if (f == null) { // filter out the value
+ delegate.nextToken();
+ delegate.skipChildren();
+ continue main_loop;
+ }
+ _itemFilter = f;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ return _nextBuffered(buffRoot);
+ }
+ }
+ continue main_loop;
+
+ default: // scalar value
+ f = _itemFilter;
+ if (f == TokenFilter.INCLUDE_ALL) {
+ return _nextBuffered(buffRoot);
+ }
+ if (f != null) {
+ f = _headContext.checkValue(f);
+ if ((f == TokenFilter.INCLUDE_ALL)
+ || ((f != null) && f.includeValue(delegate))) {
+ return _nextBuffered(buffRoot);
+ }
+ }
+ // Otherwise not included (leaves must be explicitly included)
+ continue main_loop;
+ }
+ }
+ }
+
+ private JsonToken _nextBuffered(TokenFilterContext buffRoot) throws IOException
+ {
+ _exposedContext = buffRoot;
+ TokenFilterContext ctxt = buffRoot;
+ JsonToken t = ctxt.nextTokenToRead();
+ if (t != null) {
+ return t;
+ }
+ while (true) {
+ // all done with buffered stuff?
+ if (ctxt == _headContext) {
+ throw _constructError("Internal error: failed to locate expected buffered tokens");
+ /*
+ _exposedContext = null;
+ break;
+ */
+ }
+ // If not, traverse down the context chain
+ ctxt = _exposedContext.findChildOf(ctxt);
+ _exposedContext = ctxt;
+ if (ctxt == null) { // should never occur
+ throw _constructError("Unexpected problem: chain of filtered context broken");
+ }
+ t = _exposedContext.nextTokenToRead();
+ if (t != null) {
+ return t;
+ }
+ }
+ }
+
+ @Override
+ public JsonToken nextValue() throws IOException {
+ // Re-implemented same as ParserMinimalBase:
+ JsonToken t = nextToken();
+ if (t == JsonToken.FIELD_NAME) {
+ t = nextToken();
+ }
+ return t;
+ }
+
+ /**
+ * Need to override, re-implement similar to how method defined in
+ * {@link com.fasterxml.jackson.core.base.ParserMinimalBase}, to keep
+ * state correct here.
+ */
+ @Override
+ public JsonParser skipChildren() throws IOException
+ {
+ if ((_currToken != JsonToken.START_OBJECT)
+ && (_currToken != JsonToken.START_ARRAY)) {
+ return this;
+ }
+ int open = 1;
+
+ // Since proper matching of start/end markers is handled
+ // by nextToken(), we'll just count nesting levels here
+ while (true) {
+ JsonToken t = nextToken();
+ if (t == null) { // not ideal but for now, just return
+ return this;
+ }
+ if (t.isStructStart()) {
+ ++open;
+ } else if (t.isStructEnd()) {
+ if (--open == 0) {
+ return this;
+ }
+ }
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, text
+ /**********************************************************
+ */
+
+ @Override public String getText() throws IOException { return delegate.getText(); }
+ @Override public boolean hasTextCharacters() { return delegate.hasTextCharacters(); }
+ @Override public char[] getTextCharacters() throws IOException { return delegate.getTextCharacters(); }
+ @Override public int getTextLength() throws IOException { return delegate.getTextLength(); }
+ @Override public int getTextOffset() throws IOException { return delegate.getTextOffset(); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, numeric
+ /**********************************************************
+ */
+
+ @Override
+ public BigInteger getBigIntegerValue() throws IOException { return delegate.getBigIntegerValue(); }
+
+ @Override
+ public boolean getBooleanValue() throws IOException { return delegate.getBooleanValue(); }
+
+ @Override
+ public byte getByteValue() throws IOException { return delegate.getByteValue(); }
+
+ @Override
+ public short getShortValue() throws IOException { return delegate.getShortValue(); }
+
+ @Override
+ public BigDecimal getDecimalValue() throws IOException { return delegate.getDecimalValue(); }
+
+ @Override
+ public double getDoubleValue() throws IOException { return delegate.getDoubleValue(); }
+
+ @Override
+ public float getFloatValue() throws IOException { return delegate.getFloatValue(); }
+
+ @Override
+ public int getIntValue() throws IOException { return delegate.getIntValue(); }
+
+ @Override
+ public long getLongValue() throws IOException { return delegate.getLongValue(); }
+
+ @Override
+ public NumberType getNumberType() throws IOException { return delegate.getNumberType(); }
+
+ @Override
+ public Number getNumberValue() throws IOException { return delegate.getNumberValue(); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, coercion/conversion
+ /**********************************************************
+ */
+
+ @Override public int getValueAsInt() throws IOException { return delegate.getValueAsInt(); }
+ @Override public int getValueAsInt(int defaultValue) throws IOException { return delegate.getValueAsInt(defaultValue); }
+ @Override public long getValueAsLong() throws IOException { return delegate.getValueAsLong(); }
+ @Override public long getValueAsLong(long defaultValue) throws IOException { return delegate.getValueAsLong(defaultValue); }
+ @Override public double getValueAsDouble() throws IOException { return delegate.getValueAsDouble(); }
+ @Override public double getValueAsDouble(double defaultValue) throws IOException { return delegate.getValueAsDouble(defaultValue); }
+ @Override public boolean getValueAsBoolean() throws IOException { return delegate.getValueAsBoolean(); }
+ @Override public boolean getValueAsBoolean(boolean defaultValue) throws IOException { return delegate.getValueAsBoolean(defaultValue); }
+ @Override public String getValueAsString() throws IOException { return delegate.getValueAsString(); }
+ @Override public String getValueAsString(String defaultValue) throws IOException { return delegate.getValueAsString(defaultValue); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token values, other
+ /**********************************************************
+ */
+
+ @Override public Object getEmbeddedObject() throws IOException { return delegate.getEmbeddedObject(); }
+ @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { return delegate.getBinaryValue(b64variant); }
+ @Override public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException { return delegate.readBinaryValue(b64variant, out); }
+ @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
+
+ /*
+ /**********************************************************
+ /* Internal helper methods
+ /**********************************************************
+ */
+
+ protected JsonStreamContext _filterContext() {
+ if (_exposedContext != null) {
+ return _exposedContext;
+ }
+ return _headContext;
+ }
+
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/JsonPointerBasedFilter.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,69 @@
+package com.fasterxml.jackson.core.filter;
+
+import com.fasterxml.jackson.core.JsonPointer;
+
+/**
+ * Simple {@link TokenFilter} implementation that takes a single
+ * {@link JsonPointer} and matches a single value accordingly.
+ * Instances are immutable and fully thread-safe, shareable,
+ * and efficient to use.
+ *
+ * @since 2.6
+ */
+public class JsonPointerBasedFilter extends TokenFilter
+{
+ protected final JsonPointer _pathToMatch;
+
+ public JsonPointerBasedFilter(String ptrExpr) {
+ this(JsonPointer.compile(ptrExpr));
+ }
+
+ public JsonPointerBasedFilter(JsonPointer match) {
+ _pathToMatch = match;
+ }
+
+ @Override
+ public TokenFilter includeElement(int index) {
+ JsonPointer next = _pathToMatch.matchElement(index);
+ if (next == null) {
+ return null;
+ }
+ if (next.matches()) {
+ return TokenFilter.INCLUDE_ALL;
+ }
+ return new JsonPointerBasedFilter(next);
+ }
+
+ @Override
+ public TokenFilter includeProperty(String name) {
+ JsonPointer next = _pathToMatch.matchProperty(name);
+ if (next == null) {
+ return null;
+ }
+ if (next.matches()) {
+ return TokenFilter.INCLUDE_ALL;
+ }
+ return new JsonPointerBasedFilter(next);
+ }
+
+ @Override
+ public TokenFilter filterStartArray() {
+ return this;
+ }
+
+ @Override
+ public TokenFilter filterStartObject() {
+ return this;
+ }
+
+ @Override
+ protected boolean _includeScalar() {
+ // should only occur for root-level scalars, path "/"
+ return _pathToMatch.matches();
+ }
+
+ @Override
+ public String toString() {
+ return "[JsonPointerFilter at: "+_pathToMatch+"]";
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/TokenFilter.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/TokenFilter.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/filter/TokenFilter.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,363 @@
+package com.fasterxml.jackson.core.filter;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonParser;
+
+/**
+ * Strategy class that can be implemented to specify actual inclusion/exclusion
+ * criteria for filtering, used by {@link FilteringGeneratorDelegate}.
+ *
+ * @since 2.6
+ */
+public class TokenFilter
+{
+
+ // // Marker values
+
+ /**
+ * Marker value that should be used to indicate inclusion of a structured
+ * value (sub-tree representing Object or Array), or value of a named
+ * property (regardless of type).
+ * Note that if this instance is returned, it will used as a marker, and
+ * no actual callbacks need to be made. For this reason, it is more efficient
+ * to return this instance if the whole sub-tree is to be included, instead
+ * of implementing similar filter functionality explicitly.
+ */
+ public final static TokenFilter INCLUDE_ALL = new TokenFilter();
+
+ // Life-cycle
+
+ protected TokenFilter() { }
+
+ /*
+ /**********************************************************
+ /* API, structured values
+ /**********************************************************
+ */
+
+ /**
+ * Method called to check whether Object value at current output
+ * location should be included in output.
+ * Three kinds of return values may be used as follows:
+ *
+ *
+ *null
to indicate that the Object should be skipped
+ * this
, which means that checks
+ * are made recursively for properties of the Object to determine possible inclusion.
+ *
+ * @return TokenFilter to use for further calls within Array, unless return value
+ * is null
or {@link #INCLUDE_ALL} (which have simpler semantics)
+ */
+ public TokenFilter filterStartObject() {
+ return this;
+ }
+
+ /**
+ * Method called to check whether Array value at current output
+ * location should be included in output.
+ * Three kinds of return values may be used as follows:
+ *
+ *
+ *null
to indicate that the Array should be skipped
+ * this
, which means that checks
+ * are made recursively for elements of the array to determine possible inclusion.
+ *
+ * @return TokenFilter to use for further calls within Array, unless return value
+ * is null
or {@link #INCLUDE_ALL} (which have simpler semantics)
+ */
+ public TokenFilter filterStartArray() {
+ return this;
+ }
+
+ /**
+ * Method called to indicate that output of non-filtered Object (one that may
+ * have been included either completely, or in part) is completed,
+ * in cases where filter other that {@link #INCLUDE_ALL} was returned.
+ * This occurs when {@link JsonGenerator#writeEndObject()} is called.
+ */
+ public void filterFinishObject() { }
+
+ /**
+ * Method called to indicate that output of non-filtered Array (one that may
+ * have been included either completely, or in part) is completed,
+ * in cases where filter other that {@link #INCLUDE_ALL} was returned.
+ * This occurs when {@link JsonGenerator#writeEndArray()} is called.
+ */
+ public void filterFinishArray() { }
+
+ /*
+ /**********************************************************
+ /* API, properties/elements
+ /**********************************************************
+ */
+
+ /**
+ * Method called to check whether property value with specified name,
+ * at current output location, should be included in output.
+ * Three kinds of return values may be used as follows:
+ *
+ *
+ *null
to indicate that the property and its value should be skipped
+ * this
to continue calling
+ * methods on this filter object, without full inclusion or exclusion.
+ *
+ * @return TokenFilter to use for further calls within property value, unless return value
+ * is null
or {@link #INCLUDE_ALL} (which have simpler semantics)
+ */
+ public TokenFilter includeProperty(String name) {
+ return this;
+ }
+
+ /**
+ * Method called to check whether array element with specified index (zero-based),
+ * at current output location, should be included in output.
+ * Three kinds of return values may be used as follows:
+ *
+ *
+ *null
to indicate that the Array element should be skipped
+ * this
to continue calling
+ * methods on this filter object, without full inclusion or exclusion.
+ *
+ * @return TokenFilter to use for further calls within element value, unless return value
+ * is null
or {@link #INCLUDE_ALL} (which have simpler semantics)
+ */
+ public TokenFilter includeElement(int index) {
+ return this;
+ }
+
+ /**
+ * Method called to check whether root-level value,
+ * at current output location, should be included in output.
+ * Three kinds of return values may be used as follows:
+ *
+ *
+ *null
to indicate that the root value should be skipped
+ * this
to continue calling
+ * methods on this filter object, without full inclusion or exclusion.
+ *
+ * @return TokenFilter to use for further calls within root value, unless return value
+ * is null
or {@link #INCLUDE_ALL} (which have simpler semantics)
+ */
+ public TokenFilter includeRootValue(int index) {
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* API, scalar values (being read)
+ /**********************************************************
+ */
+
+ /**
+ * Call made when verifying whether a scaler value is being
+ * read from a parser.
+ *_includeScalar()
and return
+ * whatever it indicates.
+ */
+ public boolean includeValue(JsonParser p) throws IOException {
+ return _includeScalar();
+ }
+
+ /*
+ /**********************************************************
+ /* API, scalar values (being written)
+ /**********************************************************
+ */
+
+ /**
+ * Call made to verify whether leaf-level
+ * boolean value
+ * should be included in output or not.
+ */
+ public boolean includeBoolean(boolean value) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * null value
+ * should be included in output or not.
+ */
+ public boolean includeNull() {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * String value
+ * should be included in output or not.
+ */
+ public boolean includeString(String value) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * int
value
+ * should be included in output or not.
+ *
+ * NOTE: also called for `short`, `byte`
+ */
+ public boolean includeNumber(int v) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * long
value
+ * should be included in output or not.
+ */
+ public boolean includeNumber(long v) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * float
value
+ * should be included in output or not.
+ */
+ public boolean includeNumber(float v) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * double
value
+ * should be included in output or not.
+ */
+ public boolean includeNumber(double v) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * {@link BigDecimal} value
+ * should be included in output or not.
+ */
+ public boolean includeNumber(BigDecimal v) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * {@link BigInteger} value
+ * should be included in output or not.
+ */
+ public boolean includeNumber(BigInteger v) {
+ return _includeScalar();
+ }
+
+ /**
+ * Call made to verify whether leaf-level
+ * Binary value
+ * should be included in output or not.
+ *
+ * return hasMatch() ? getMatch().getFormatName() : null;
+ *
+ */
+ public String getMatchedFormatName() {
+ return _match.getFormatName();
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, factory methods
+ /**********************************************************
+ */
+
+ /**
+ * Convenience method for trying to construct a {@link JsonParser} for
+ * parsing content which is assumed to be in detected data format.
+ * If no match was found, returns null.
+ */
+ public JsonParser createParserWithMatch() throws IOException {
+ if (_match == null) {
+ return null;
+ }
+ if (_originalStream == null) {
+ return _match.createParser(_bufferedData, _bufferedStart, _bufferedLength);
+ }
+ return _match.createParser(getDataStream());
+ }
+
+ /**
+ * Method to use for accessing input for which format detection has been done.
+ * This must be used instead of using stream passed to detector
+ * unless given stream itself can do buffering.
+ * Stream will return all content that was read during matching process, as well
+ * as remaining contents of the underlying stream.
+ */
+ public InputStream getDataStream() {
+ if (_originalStream == null) {
+ return new ByteArrayInputStream(_bufferedData, _bufferedStart, _bufferedLength);
+ }
+ return new MergedStream(null, _originalStream, _bufferedData, _bufferedStart, _bufferedLength);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/InputAccessor.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/InputAccessor.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/InputAccessor.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,151 @@
+package com.fasterxml.jackson.core.format;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.JsonFactory;
+
+/**
+ * Interface used to expose beginning of a data file to data format
+ * detection code.
+ */
+public interface InputAccessor
+{
+ /**
+ * Method to call to check if more input is available.
+ * Since this may result in more content to be read (at least
+ * one more byte), a {@link IOException} may get thrown.
+ */
+ boolean hasMoreBytes() throws IOException;
+
+ /**
+ * Returns next byte available, if any; if no more bytes are
+ * available, will throw {@link java.io.EOFException}.
+ */
+ byte nextByte() throws IOException;
+
+ /**
+ * Method that can be called to reset accessor to read from beginning
+ * of input.
+ */
+ void reset();
+
+ /*
+ /**********************************************************
+ /* Standard implementation
+ /**********************************************************
+ */
+
+ /**
+ * Basic implementation that reads data from given
+ * {@link InputStream} and buffers it as necessary.
+ */
+ class Std implements InputAccessor
+ {
+ protected final InputStream _in;
+
+ protected final byte[] _buffer;
+
+ protected final int _bufferedStart;
+
+ /**
+ * End of valid bytes in the buffer (points to one past last valid)
+ */
+ protected int _bufferedEnd;
+
+ /**
+ * Pointer to next available buffered byte in {@link #_buffer}.
+ */
+ protected int _ptr;
+
+ /**
+ * Constructor used when content to check is available via
+ * input stream and must be read.
+ */
+ public Std(InputStream in, byte[] buffer)
+ {
+ _in = in;
+ _buffer = buffer;
+ _bufferedStart = 0;
+ _ptr = 0;
+ _bufferedEnd = 0;
+ }
+
+ /**
+ * Constructor used when the full input (or at least enough leading bytes
+ * of full input) is available.
+ */
+ public Std(byte[] inputDocument)
+ {
+ _in = null;
+ _buffer = inputDocument;
+ // we have it all:
+ _bufferedStart = 0;
+ _bufferedEnd = inputDocument.length;
+ }
+
+ /**
+ * Constructor used when the full input (or at least enough leading bytes
+ * of full input) is available.
+ *
+ * @since 2.1
+ */
+ public Std(byte[] inputDocument, int start, int len)
+ {
+ _in = null;
+ _buffer = inputDocument;
+ _ptr = start;
+ _bufferedStart = start;
+ _bufferedEnd = start+len;
+ }
+
+ @Override
+ public boolean hasMoreBytes() throws IOException
+ {
+ if (_ptr < _bufferedEnd) { // already got more
+ return true;
+ }
+ if (_in == null) { // nowhere to read from
+ return false;
+ }
+ int amount = _buffer.length - _ptr;
+ if (amount < 1) { // can not load any more
+ return false;
+ }
+ int count = _in.read(_buffer, _ptr, amount);
+ if (count <= 0) { // EOF
+ return false;
+ }
+ _bufferedEnd += count;
+ return true;
+ }
+
+ @Override
+ public byte nextByte() throws IOException
+ {
+ // should we just try loading more automatically?
+ if (_ptr >= _bufferedEnd) {
+ if (!hasMoreBytes()) {
+ throw new EOFException("Failed auto-detect: could not read more than "+_ptr+" bytes (max buffer size: "+_buffer.length+")");
+ }
+ }
+ return _buffer[_ptr++];
+ }
+
+ @Override
+ public void reset() {
+ _ptr = _bufferedStart;
+ }
+
+ /*
+ /**********************************************************
+ /* Extended API for DataFormatDetector/Matcher
+ /**********************************************************
+ */
+
+ public DataFormatMatcher createMatcher(JsonFactory match, MatchStrength matchStrength)
+ {
+ return new DataFormatMatcher(_in, _buffer, _bufferedStart, (_bufferedEnd - _bufferedStart),
+ match, matchStrength);
+ }
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/MatchStrength.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/MatchStrength.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/format/MatchStrength.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,62 @@
+package com.fasterxml.jackson.core.format;
+
+/**
+ * Enumeration used to indicate strength of match between data format
+ * and piece of data (typically beginning of a data file).
+ * Values are in increasing match strength; and detectors should return
+ * "strongest" value: that is, it should start with strongest match
+ * criteria, and downgrading if criteria is not fulfilled.
+ */
+public enum MatchStrength
+{
+ /**
+ * Value that indicates that given data can not be in given format.
+ */
+ NO_MATCH,
+
+ /**
+ * Value that indicates that detector can not find out whether could
+ * be a match or not.
+ * This can occur for example for textual data formats t
+ * when there are so many leading spaces that detector can not
+ * find the first data byte (because detectors typically limit lookahead
+ * to some smallish value).
+ */
+ INCONCLUSIVE,
+
+ /**
+ * Value that indicates that given data could be of specified format (i.e.
+ * it can not be ruled out). This can occur for example when seen data
+ * is both not in canonical formats (for example: JSON data should be a JSON Array or Object
+ * not a scalar value, as per JSON specification) and there are known use case
+ * where a format detected is actually used (plain JSON Strings are actually used, even
+ * though specification does not indicate that as valid usage: as such, seeing a leading
+ * double-quote could indicate a JSON String, which plausibly could indicate
+ * non-standard JSON usage).
+ */
+ WEAK_MATCH,
+
+ /**
+ * Value that indicates that given data conforms to (one of) canonical form(s) of
+ * the data format.
+ *ESCAPE_xxx
constants, or non-zero positive
+ * integer (meaning of which is data format specific; for JSON it means
+ * that combination of backslash and character with that value is to be used)
+ * to indicate that specific escape sequence is to be used.
+ */
+ public abstract int[] getEscapeCodesForAscii();
+
+ /**
+ * Method generators can call to get lookup table for determining
+ * exact escape sequence to use for given character.
+ * It can be called for any character, but typically is called for
+ * either for ASCII characters for which custom escape
+ * sequence is needed; or for any non-ASCII character.
+ */
+ public abstract SerializableString getEscapeSequence(int ch);
+
+ /**
+ * Helper method that can be used to get a copy of standard JSON
+ * escape definitions; this is useful when just wanting to slightly
+ * customize definitions. Caller can modify this array as it sees
+ * fit and usually returns modified instance via {@link #getEscapeCodesForAscii}
+ */
+ public static int[] standardAsciiEscapesForJSON()
+ {
+ int[] esc = CharTypes.get7BitOutputEscapes();
+ return Arrays.copyOf(esc, esc.length);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/IOContext.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/IOContext.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/IOContext.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,281 @@
+package com.fasterxml.jackson.core.io;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.util.BufferRecycler;
+import com.fasterxml.jackson.core.util.TextBuffer;
+
+/**
+ * To limit number of configuration and state objects to pass, all
+ * contextual objects that need to be passed by the factory to
+ * readers and writers are combined under this object. One instance
+ * is created for each reader and writer.
+ *ThreadLocal
contains a {@link java.lang.ref.SoftReference}
+ * to a {@link BufferRecycler} used to provide a low-cost
+ * buffer recycling between reader and writer instances.
+ */
+ final protected static ThreadLocalc
is positive, and larger than
+ * Integer.MAX_VALUE (about 2 billions).
+ */
+ private static int calcLongStrLength(long v)
+ {
+ int len = 10;
+ long cmp = TEN_BILLION_L;
+
+ // 19 is longest, need to worry about overflow
+ while (v >= cmp) {
+ if (len == 19) {
+ break;
+ }
+ ++len;
+ cmp = (cmp << 3) + (cmp << 1); // 10x
+ }
+ return len;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/OutputDecorator.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/OutputDecorator.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/OutputDecorator.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,38 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+
+/**
+ * Handler class that can be used to decorate output destinations.
+ * Typical use is to use a filter abstraction (filtered output stream,
+ * writer) around original output destination, and apply additional
+ * processing during write operations.
+ */
+@SuppressWarnings("serial")
+public abstract class OutputDecorator implements java.io.Serializable // since 2.1
+{
+ /**
+ * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
+ * creating generator for given {@link OutputStream}, when this decorator
+ * has been registered.
+ *
+ * @param ctxt IO context in use (provides access to declared encoding)
+ * @param out Original output destination
+ *
+ * @return OutputStream to use; either passed in argument, or something that
+ * calls it
+ */
+ public abstract OutputStream decorate(IOContext ctxt, OutputStream out) throws IOException;
+
+ /**
+ * Method called by {@link com.fasterxml.jackson.core.JsonFactory} instance when
+ * creating generator for given {@link Writer}, when this decorator
+ * has been registered.
+ *
+ * @param ctxt IO context in use (provides access to declared encoding)
+ * @param w Original output writer
+ *
+ * @return Writer to use; either passed in argument, or something that calls it
+ */
+ public abstract Writer decorate(IOContext ctxt, Writer w) throws IOException;
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/SegmentedStringWriter.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/SegmentedStringWriter.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/SegmentedStringWriter.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,87 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+
+import com.fasterxml.jackson.core.util.BufferRecycler;
+import com.fasterxml.jackson.core.util.TextBuffer;
+
+/**
+ * Efficient alternative to {@link StringWriter}, based on using segmented
+ * internal buffer. Initial input buffer is also recyclable.
+ *JsonGenerator
.
+ */
+public final class SegmentedStringWriter extends Writer
+{
+ final protected TextBuffer _buffer;
+
+ public SegmentedStringWriter(BufferRecycler br) {
+ super();
+ _buffer = new TextBuffer(br);
+ }
+
+ /*
+ /**********************************************************
+ /* java.io.Writer implementation
+ /**********************************************************
+ */
+
+ @Override
+ public Writer append(char c) {
+ write(c);
+ return this;
+ }
+
+ @Override
+ public Writer append(CharSequence csq) {
+ String str = csq.toString();
+ _buffer.append(str, 0, str.length());
+ return this;
+ }
+
+ @Override
+ public Writer append(CharSequence csq, int start, int end) {
+ String str = csq.subSequence(start, end).toString();
+ _buffer.append(str, 0, str.length());
+ return this;
+ }
+
+ @Override public void close() { } // NOP
+ @Override public void flush() { } // NOP
+
+ @Override
+ public void write(char[] cbuf) { _buffer.append(cbuf, 0, cbuf.length); }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) { _buffer.append(cbuf, off, len); }
+
+ @Override
+ public void write(int c) { _buffer.append((char) c); }
+
+ @Override
+ public void write(String str) { _buffer.append(str, 0, str.length()); }
+
+ @Override
+ public void write(String str, int off, int len) { _buffer.append(str, off, len); }
+
+ /*
+ /**********************************************************
+ /* Extended API
+ /**********************************************************
+ */
+
+ /**
+ * Main access method that will construct a String that contains
+ * all the contents, release all internal buffers we may have,
+ * and return result String.
+ * Note that the method is not idempotent -- if called second time,
+ * will just return an empty String.
+ */
+ public String getAndClear() {
+ String result = _buffer.contentsAsString();
+ _buffer.releaseBuffers();
+ return result;
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/SerializedString.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/SerializedString.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/io/SerializedString.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,269 @@
+package com.fasterxml.jackson.core.io;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+
+import com.fasterxml.jackson.core.SerializableString;
+
+/**
+ * String token that can lazily serialize String contained and then reuse that
+ * serialization later on. This is similar to JDBC prepared statements, for example,
+ * in that instances should only be created when they are used more than use;
+ * prime candidates are various serializers.
+ *char
s that we know will always fit
+ * in the output buffer after escaping
+ */
+ protected final int _outputMaxContiguous;
+
+ /**
+ * Intermediate buffer in which characters of a String are copied
+ * before being encoded.
+ */
+ protected char[] _charBuffer;
+
+ /**
+ * Length of _charBuffer
+ */
+ protected final int _charBufferLength;
+
+ /**
+ * 6 character temporary buffer allocated if needed, for constructing
+ * escape sequences
+ */
+ protected byte[] _entityBuffer;
+
+ /**
+ * Flag that indicates whether the output buffer is recycable (and
+ * needs to be returned to recycler once we are done) or not.
+ */
+ protected boolean _bufferRecyclable;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
+ OutputStream out)
+ {
+ super(ctxt, features, codec);
+ _outputStream = out;
+ _bufferRecyclable = true;
+ _outputBuffer = ctxt.allocWriteEncodingBuffer();
+ _outputEnd = _outputBuffer.length;
+
+ /* To be exact, each char can take up to 6 bytes when escaped (Unicode
+ * escape with backslash, 'u' and 4 hex digits); but to avoid fluctuation,
+ * we will actually round down to only do up to 1/8 number of chars
+ */
+ _outputMaxContiguous = _outputEnd >> 3;
+ _charBuffer = ctxt.allocConcatBuffer();
+ _charBufferLength = _charBuffer.length;
+
+ // By default we use this feature to determine additional quoting
+ if (isEnabled(Feature.ESCAPE_NON_ASCII)) {
+ setHighestNonEscapedChar(127);
+ }
+ }
+
+ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
+ OutputStream out,
+ byte[] outputBuffer, int outputOffset, boolean bufferRecyclable)
+ {
+
+ super(ctxt, features, codec);
+ _outputStream = out;
+ _bufferRecyclable = bufferRecyclable;
+ _outputTail = outputOffset;
+ _outputBuffer = outputBuffer;
+ _outputEnd = _outputBuffer.length;
+ // up to 6 bytes per char (see above), rounded up to 1/8
+ _outputMaxContiguous = (_outputEnd >> 3);
+ _charBuffer = ctxt.allocConcatBuffer();
+ _charBufferLength = _charBuffer.length;
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden configuration methods
+ /**********************************************************
+ */
+
+ @Override
+ public Object getOutputTarget() {
+ return _outputStream;
+ }
+
+ @Override
+ public int getOutputBuffered() {
+ // Assuming tail is always valid, set to 0 on close
+ return _outputTail;
+ }
+
+ /*
+ /**********************************************************
+ /* Overridden methods
+ /**********************************************************
+ */
+
+ @Override
+ public void writeFieldName(String name) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ _writePPFieldName(name);
+ return;
+ }
+ final int status = _writeContext.writeFieldName(name);
+ if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
+ _reportError("Can not write a field name, expecting a value");
+ }
+ if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) { // need comma
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_COMMA;
+ }
+ /* To support [JACKSON-46], we'll do this:
+ * (Question: should quoting of spaces (etc) still be enabled?)
+ */
+ if (_cfgUnqNames) {
+ _writeStringSegments(name, false);
+ return;
+ }
+ final int len = name.length();
+ // Does it fit in buffer?
+ if (len > _charBufferLength) { // no, offline
+ _writeStringSegments(name, true);
+ return;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ // But as one segment, or multiple?
+ if (len <= _outputMaxContiguous) {
+ if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
+ _flushBuffer();
+ }
+ _writeStringSegment(name, 0, len);
+ } else {
+ _writeStringSegments(name, 0, len);
+ }
+ // and closing quotes; need room for one more char:
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeFieldName(SerializableString name) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ _writePPFieldName(name);
+ return;
+ }
+ final int status = _writeContext.writeFieldName(name.getValue());
+ if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
+ _reportError("Can not write a field name, expecting a value");
+ }
+ if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_COMMA;
+ }
+ if (_cfgUnqNames) {
+ _writeUnq(name);
+ return;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
+ if (len < 0) { // couldn't append, bit longer processing
+ _writeBytes(name.asQuotedUTF8());
+ } else {
+ _outputTail += len;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ private final void _writeUnq(SerializableString name) throws IOException {
+ int len = name.appendQuotedUTF8(_outputBuffer, _outputTail);
+ if (len < 0) {
+ _writeBytes(name.asQuotedUTF8());
+ } else {
+ _outputTail += len;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, structural
+ /**********************************************************
+ */
+
+ @Override
+ public final void writeStartArray() throws IOException
+ {
+ _verifyValueWrite("start an array");
+ _writeContext = _writeContext.createChildArrayContext();
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeStartArray(this);
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_LBRACKET;
+ }
+ }
+
+ @Override
+ public final void writeEndArray() throws IOException
+ {
+ if (!_writeContext.inArray()) {
+ _reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc());
+ }
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_RBRACKET;
+ }
+ _writeContext = _writeContext.clearAndGetParent();
+ }
+
+ @Override
+ public final void writeStartObject() throws IOException
+ {
+ _verifyValueWrite("start an object");
+ _writeContext = _writeContext.createChildObjectContext();
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeStartObject(this);
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_LCURLY;
+ }
+ }
+
+ @Override
+ public final void writeEndObject() throws IOException
+ {
+ if (!_writeContext.inObject()) {
+ _reportError("Current context not an object but "+_writeContext.getTypeDesc());
+ }
+ if (_cfgPrettyPrinter != null) {
+ _cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_RCURLY;
+ }
+ _writeContext = _writeContext.clearAndGetParent();
+ }
+
+ /**
+ * Specialized version of _writeFieldName
, off-lined
+ * to keep the "fast path" as simple (and hopefully fast) as possible.
+ */
+ protected final void _writePPFieldName(String name) throws IOException
+ {
+ int status = _writeContext.writeFieldName(name);
+ if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
+ _reportError("Can not write a field name, expecting a value");
+ }
+ if ((status == JsonWriteContext.STATUS_OK_AFTER_COMMA)) {
+ _cfgPrettyPrinter.writeObjectEntrySeparator(this);
+ } else {
+ _cfgPrettyPrinter.beforeObjectEntries(this);
+ }
+ if (_cfgUnqNames) {
+ _writeStringSegments(name, false);
+ return;
+ }
+ final int len = name.length();
+ if (len > _charBufferLength) {
+ _writeStringSegments(name, true);
+ return;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ name.getChars(0, len, _charBuffer, 0);
+ // But as one segment, or multiple?
+ if (len <= _outputMaxContiguous) {
+ if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
+ _flushBuffer();
+ }
+ _writeStringSegment(_charBuffer, 0, len);
+ } else {
+ _writeStringSegments(_charBuffer, 0, len);
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ protected final void _writePPFieldName(SerializableString name) throws IOException
+ {
+ final int status = _writeContext.writeFieldName(name.getValue());
+ if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
+ _reportError("Can not write a field name, expecting a value");
+ }
+ if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
+ _cfgPrettyPrinter.writeObjectEntrySeparator(this);
+ } else {
+ _cfgPrettyPrinter.beforeObjectEntries(this);
+ }
+
+ final boolean addQuotes = !_cfgUnqNames; // standard
+ if (addQuotes) {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+ _writeBytes(name.asQuotedUTF8());
+ if (addQuotes) {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, textual
+ /**********************************************************
+ */
+
+ @Override
+ public void writeString(String text) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (text == null) {
+ _writeNull();
+ return;
+ }
+ // First: if we can't guarantee it all fits, quoted, within output, offline
+ final int len = text.length();
+ if (len > _outputMaxContiguous) { // nope: off-line handling
+ _writeStringSegments(text, true);
+ return;
+ }
+ if ((_outputTail + len) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ _writeStringSegment(text, 0, len); // we checked space already above
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeString(char[] text, int offset, int len) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ // One or multiple segments?
+ if (len <= _outputMaxContiguous) {
+ if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
+ _flushBuffer();
+ }
+ _writeStringSegment(text, offset, len);
+ } else {
+ _writeStringSegments(text, offset, len);
+ }
+ // And finally, closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public final void writeString(SerializableString text) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ int len = text.appendQuotedUTF8(_outputBuffer, _outputTail);
+ if (len < 0) {
+ _writeBytes(text.asQuotedUTF8());
+ } else {
+ _outputTail += len;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ _writeBytes(text, offset, length);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeUTF8String(byte[] text, int offset, int len) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ // One or multiple segments?
+ if (len <= _outputMaxContiguous) {
+ _writeUTF8Segment(text, offset, len);
+ } else {
+ _writeUTF8Segments(text, offset, len);
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, unprocessed ("raw")
+ /**********************************************************
+ */
+
+ @Override
+ public void writeRaw(String text)
+ throws IOException, JsonGenerationException
+ {
+ int start = 0;
+ int len = text.length();
+ while (len > 0) {
+ char[] buf = _charBuffer;
+ final int blen = buf.length;
+ final int len2 = (len < blen) ? len : blen;
+ text.getChars(start, start+len2, buf, 0);
+ writeRaw(buf, 0, len2);
+ start += len2;
+ len -= len2;
+ }
+ }
+
+ @Override
+ public void writeRaw(String text, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ while (len > 0) {
+ char[] buf = _charBuffer;
+ final int blen = buf.length;
+ final int len2 = (len < blen) ? len : blen;
+ text.getChars(offset, offset+len2, buf, 0);
+ writeRaw(buf, 0, len2);
+ offset += len2;
+ len -= len2;
+ }
+ }
+
+ @Override
+ public void writeRaw(SerializableString text) throws IOException, JsonGenerationException
+ {
+ byte[] raw = text.asUnquotedUTF8();
+ if (raw.length > 0) {
+ _writeBytes(raw);
+ }
+ }
+
+ // since 2.5
+ @Override
+ public void writeRawValue(SerializableString text) throws IOException {
+ _verifyValueWrite(WRITE_RAW);
+ byte[] raw = text.asUnquotedUTF8();
+ if (raw.length > 0) {
+ _writeBytes(raw);
+ }
+ }
+
+ // @TODO: rewrite for speed...
+ @Override
+ public final void writeRaw(char[] cbuf, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ // First: if we have 3 x charCount spaces, we know it'll fit just fine
+ {
+ int len3 = len+len+len;
+ if ((_outputTail + len3) > _outputEnd) {
+ // maybe we could flush?
+ if (_outputEnd < len3) { // wouldn't be enough...
+ _writeSegmentedRaw(cbuf, offset, len);
+ return;
+ }
+ // yes, flushing brings enough space
+ _flushBuffer();
+ }
+ }
+ len += offset; // now marks the end
+
+ // Note: here we know there is enough room, hence no output boundary checks
+ main_loop:
+ while (offset < len) {
+ inner_loop:
+ while (true) {
+ int ch = (int) cbuf[offset];
+ if (ch > 0x7F) {
+ break inner_loop;
+ }
+ _outputBuffer[_outputTail++] = (byte) ch;
+ if (++offset >= len) {
+ break main_loop;
+ }
+ }
+ char ch = cbuf[offset++];
+ if (ch < 0x800) { // 2-byte?
+ _outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
+ _outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ offset = _outputRawMultiByteChar(ch, cbuf, offset, len);
+ }
+ }
+ }
+
+ @Override
+ public void writeRaw(char ch)
+ throws IOException, JsonGenerationException
+ {
+ if ((_outputTail + 3) >= _outputEnd) {
+ _flushBuffer();
+ }
+ final byte[] bbuf = _outputBuffer;
+ if (ch <= 0x7F) {
+ bbuf[_outputTail++] = (byte) ch;
+ } else if (ch < 0x800) { // 2-byte?
+ bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
+ bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ /*offset =*/ _outputRawMultiByteChar(ch, null, 0, 0);
+ }
+ }
+
+ /**
+ * Helper method called when it is possible that output of raw section
+ * to output may cross buffer boundary
+ */
+ private final void _writeSegmentedRaw(char[] cbuf, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ final int end = _outputEnd;
+ final byte[] bbuf = _outputBuffer;
+
+ main_loop:
+ while (offset < len) {
+ inner_loop:
+ while (true) {
+ int ch = (int) cbuf[offset];
+ if (ch >= 0x80) {
+ break inner_loop;
+ }
+ // !!! TODO: fast(er) writes (roll input, output checks in one)
+ if (_outputTail >= end) {
+ _flushBuffer();
+ }
+ bbuf[_outputTail++] = (byte) ch;
+ if (++offset >= len) {
+ break main_loop;
+ }
+ }
+ if ((_outputTail + 3) >= _outputEnd) {
+ _flushBuffer();
+ }
+ char ch = cbuf[offset++];
+ if (ch < 0x800) { // 2-byte?
+ bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
+ bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ offset = _outputRawMultiByteChar(ch, cbuf, offset, len);
+ }
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, base64-encoded binary
+ /**********************************************************
+ */
+
+ @Override
+ public void writeBinary(Base64Variant b64variant,
+ byte[] data, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ _verifyValueWrite(WRITE_BINARY);
+ // Starting quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ _writeBinary(b64variant, data, offset, offset+len);
+ // and closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public int writeBinary(Base64Variant b64variant,
+ InputStream data, int dataLength)
+ throws IOException, JsonGenerationException
+ {
+ _verifyValueWrite(WRITE_BINARY);
+ // Starting quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ byte[] encodingBuffer = _ioContext.allocBase64Buffer();
+ int bytes;
+ try {
+ if (dataLength < 0) { // length unknown
+ bytes = _writeBinary(b64variant, data, encodingBuffer);
+ } else {
+ int missing = _writeBinary(b64variant, data, encodingBuffer, dataLength);
+ if (missing > 0) {
+ _reportError("Too few bytes available: missing "+missing+" bytes (out of "+dataLength+")");
+ }
+ bytes = dataLength;
+ }
+ } finally {
+ _ioContext.releaseBase64Buffer(encodingBuffer);
+ }
+ // and closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ return bytes;
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, primitive
+ /**********************************************************
+ */
+
+ @Override
+ public void writeNumber(short s) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ // up to 5 digits and possible minus sign
+ if ((_outputTail + 6) >= _outputEnd) {
+ _flushBuffer();
+ }
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedShort(s);
+ return;
+ }
+ _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
+ }
+
+ private final void _writeQuotedShort(short s) throws IOException {
+ if ((_outputTail + 8) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeNumber(int i) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ // up to 10 digits and possible minus sign
+ if ((_outputTail + 11) >= _outputEnd) {
+ _flushBuffer();
+ }
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedInt(i);
+ return;
+ }
+ _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
+ }
+
+ private final void _writeQuotedInt(int i) throws IOException
+ {
+ if ((_outputTail + 13) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeNumber(long l) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedLong(l);
+ return;
+ }
+ if ((_outputTail + 21) >= _outputEnd) {
+ // up to 20 digits, minus sign
+ _flushBuffer();
+ }
+ _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
+ }
+
+ private final void _writeQuotedLong(long l) throws IOException
+ {
+ if ((_outputTail + 23) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeNumber(BigInteger value) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (value == null) {
+ _writeNull();
+ } else if (_cfgNumbersAsStrings) {
+ _writeQuotedRaw(value.toString());
+ } else {
+ writeRaw(value.toString());
+ }
+ }
+
+
+ @Override
+ public void writeNumber(double d) throws IOException
+ {
+ if (_cfgNumbersAsStrings ||
+ (((Double.isNaN(d) || Double.isInfinite(d))
+ && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
+ writeString(String.valueOf(d));
+ return;
+ }
+ // What is the max length for doubles? 40 chars?
+ _verifyValueWrite(WRITE_NUMBER);
+ writeRaw(String.valueOf(d));
+ }
+
+ @Override
+ public void writeNumber(float f) throws IOException
+ {
+ if (_cfgNumbersAsStrings ||
+ // [JACKSON-139]
+ (((Float.isNaN(f) || Float.isInfinite(f))
+ && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)))) {
+ writeString(String.valueOf(f));
+ return;
+ }
+ // What is the max length for floats?
+ _verifyValueWrite(WRITE_NUMBER);
+ writeRaw(String.valueOf(f));
+ }
+
+ @Override
+ public void writeNumber(BigDecimal value) throws IOException
+ {
+ // Don't really know max length for big decimal, no point checking
+ _verifyValueWrite(WRITE_NUMBER);
+ if (value == null) {
+ _writeNull();
+ } else if (_cfgNumbersAsStrings) {
+ String raw = Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)
+ ? value.toPlainString() : value.toString();
+ _writeQuotedRaw(raw);
+ } else if (Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)) {
+ writeRaw(value.toPlainString());
+ } else {
+ writeRaw(value.toString());
+ }
+ }
+
+ @Override
+ public void writeNumber(String encodedValue) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedRaw(encodedValue);
+ } else {
+ writeRaw(encodedValue);
+ }
+ }
+
+ private final void _writeQuotedRaw(String value) throws IOException
+ {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ writeRaw(value);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ @Override
+ public void writeBoolean(boolean state) throws IOException
+ {
+ _verifyValueWrite(WRITE_BOOLEAN);
+ if ((_outputTail + 5) >= _outputEnd) {
+ _flushBuffer();
+ }
+ byte[] keyword = state ? TRUE_BYTES : FALSE_BYTES;
+ int len = keyword.length;
+ System.arraycopy(keyword, 0, _outputBuffer, _outputTail, len);
+ _outputTail += len;
+ }
+
+ @Override
+ public void writeNull() throws IOException
+ {
+ _verifyValueWrite(WRITE_NULL);
+ _writeNull();
+ }
+
+ /*
+ /**********************************************************
+ /* Implementations for other methods
+ /**********************************************************
+ */
+
+ @Override
+ protected final void _verifyValueWrite(String typeMsg) throws IOException
+ {
+ int status = _writeContext.writeValue();
+ if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
+ _reportError("Can not "+typeMsg+", expecting field name");
+ }
+ if (_cfgPrettyPrinter == null) {
+ byte b;
+ switch (status) {
+ case JsonWriteContext.STATUS_OK_AFTER_COMMA:
+ b = BYTE_COMMA;
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_COLON:
+ b = BYTE_COLON;
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator
+ if (_rootValueSeparator != null) {
+ byte[] raw = _rootValueSeparator.asUnquotedUTF8();
+ if (raw.length > 0) {
+ _writeBytes(raw);
+ }
+ }
+ return;
+ case JsonWriteContext.STATUS_OK_AS_IS:
+ default:
+ return;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail] = b;
+ ++_outputTail;
+ return;
+ }
+ // Otherwise, pretty printer knows what to do...
+ _verifyPrettyValueWrite(typeMsg, status);
+ }
+
+ protected final void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException
+ {
+ // If we have a pretty printer, it knows what to do:
+ switch (status) {
+ case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
+ _cfgPrettyPrinter.writeArrayValueSeparator(this);
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_COLON:
+ _cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_SPACE:
+ _cfgPrettyPrinter.writeRootValueSeparator(this);
+ break;
+ case JsonWriteContext.STATUS_OK_AS_IS:
+ // First entry, but of which context?
+ if (_writeContext.inArray()) {
+ _cfgPrettyPrinter.beforeArrayValues(this);
+ } else if (_writeContext.inObject()) {
+ _cfgPrettyPrinter.beforeObjectEntries(this);
+ }
+ break;
+ default:
+ _throwInternal();
+ break;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Low-level output handling
+ /**********************************************************
+ */
+
+ @Override
+ public void flush() throws IOException
+ {
+ _flushBuffer();
+ if (_outputStream != null) {
+ if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
+ _outputStream.flush();
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ super.close();
+
+ /* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open
+ * scopes.
+ */
+ // First: let's see that we still have buffers...
+ if ((_outputBuffer != null)
+ && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
+ while (true) {
+ JsonStreamContext ctxt = getOutputContext();
+ if (ctxt.inArray()) {
+ writeEndArray();
+ } else if (ctxt.inObject()) {
+ writeEndObject();
+ } else {
+ break;
+ }
+ }
+ }
+ _flushBuffer();
+ _outputTail = 0; // just to ensure we don't think there's anything buffered
+
+ /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
+ * on the underlying Reader, unless we "own" it, or auto-closing
+ * feature is enabled.
+ * One downside: when using UTF8Writer, underlying buffer(s)
+ * may not be properly recycled if we don't close the writer.
+ */
+ if (_outputStream != null) {
+ if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
+ _outputStream.close();
+ } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
+ // If we can't close it, we should at least flush
+ _outputStream.flush();
+ }
+ }
+ // Internal buffer(s) generator has can now be released as well
+ _releaseBuffers();
+ }
+
+ @Override
+ protected void _releaseBuffers()
+ {
+ byte[] buf = _outputBuffer;
+ if (buf != null && _bufferRecyclable) {
+ _outputBuffer = null;
+ _ioContext.releaseWriteEncodingBuffer(buf);
+ }
+ char[] cbuf = _charBuffer;
+ if (cbuf != null) {
+ _charBuffer = null;
+ _ioContext.releaseConcatBuffer(cbuf);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, raw bytes
+ /**********************************************************
+ */
+
+ private final void _writeBytes(byte[] bytes) throws IOException
+ {
+ final int len = bytes.length;
+ if ((_outputTail + len) > _outputEnd) {
+ _flushBuffer();
+ // still not enough?
+ if (len > MAX_BYTES_TO_BUFFER) {
+ _outputStream.write(bytes, 0, len);
+ return;
+ }
+ }
+ System.arraycopy(bytes, 0, _outputBuffer, _outputTail, len);
+ _outputTail += len;
+ }
+
+ private final void _writeBytes(byte[] bytes, int offset, int len) throws IOException
+ {
+ if ((_outputTail + len) > _outputEnd) {
+ _flushBuffer();
+ // still not enough?
+ if (len > MAX_BYTES_TO_BUFFER) {
+ _outputStream.write(bytes, offset, len);
+ return;
+ }
+ }
+ System.arraycopy(bytes, offset, _outputBuffer, _outputTail, len);
+ _outputTail += len;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, mid-level writing, String segments
+ /**********************************************************
+ */
+
+ /**
+ * Method called when String to write is long enough not to fit
+ * completely in temporary copy buffer. If so, we will actually
+ * copy it in small enough chunks so it can be directly fed
+ * to single-segment writes (instead of maximum slices that
+ * would fit in copy buffer)
+ */
+ private final void _writeStringSegments(String text, boolean addQuotes) throws IOException
+ {
+ if (addQuotes) {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+
+ int left = text.length();
+ int offset = 0;
+
+ while (left > 0) {
+ int len = Math.min(_outputMaxContiguous, left);
+ if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
+ _flushBuffer();
+ }
+ _writeStringSegment(text, offset, len);
+ offset += len;
+ left -= len;
+ }
+
+ if (addQuotes) {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = BYTE_QUOTE;
+ }
+ }
+
+ /**
+ * Method called when character sequence to write is long enough that
+ * its maximum encoded and escaped form is not guaranteed to fit in
+ * the output buffer. If so, we will need to choose smaller output
+ * chunks to write at a time.
+ */
+ private final void _writeStringSegments(char[] cbuf, int offset, int totalLen) throws IOException
+ {
+ do {
+ int len = Math.min(_outputMaxContiguous, totalLen);
+ if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
+ _flushBuffer();
+ }
+ _writeStringSegment(cbuf, offset, len);
+ offset += len;
+ totalLen -= len;
+ } while (totalLen > 0);
+ }
+
+ private final void _writeStringSegments(String text, int offset, int totalLen) throws IOException
+ {
+ do {
+ int len = Math.min(_outputMaxContiguous, totalLen);
+ if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
+ _flushBuffer();
+ }
+ _writeStringSegment(text, offset, len);
+ offset += len;
+ totalLen -= len;
+ } while (totalLen > 0);
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, text segments
+ /**********************************************************
+ */
+
+ /**
+ * This method called when the string content is already in
+ * a char buffer, and its maximum total encoded and escaped length
+ * can not exceed size of the output buffer.
+ * Caller must ensure that there is enough space in output buffer,
+ * assuming case of all non-escaped ASCII characters, as well as
+ * potentially enough space for other cases (but not necessarily flushed)
+ */
+ private final void _writeStringSegment(char[] cbuf, int offset, int len)
+ throws IOException
+ {
+ // note: caller MUST ensure (via flushing) there's room for ASCII only
+
+ // Fast+tight loop for ASCII-only, no-escaping-needed output
+ len += offset; // becomes end marker, then
+
+ int outputPtr = _outputTail;
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+
+ while (offset < len) {
+ int ch = cbuf[offset];
+ // note: here we know that (ch > 0x7F) will cover case of escaping non-ASCII too:
+ if (ch > 0x7F || escCodes[ch] != 0) {
+ break;
+ }
+ outputBuffer[outputPtr++] = (byte) ch;
+ ++offset;
+ }
+ _outputTail = outputPtr;
+ if (offset < len) {
+ // [JACKSON-106]
+ if (_characterEscapes != null) {
+ _writeCustomStringSegment2(cbuf, offset, len);
+ // [JACKSON-102]
+ } else if (_maximumNonEscapedChar == 0) {
+ _writeStringSegment2(cbuf, offset, len);
+ } else {
+ _writeStringSegmentASCII2(cbuf, offset, len);
+ }
+
+ }
+ }
+
+ private final void _writeStringSegment(String text, int offset, int len) throws IOException
+ {
+ // note: caller MUST ensure (via flushing) there's room for ASCII only
+ // Fast+tight loop for ASCII-only, no-escaping-needed output
+ len += offset; // becomes end marker, then
+
+ int outputPtr = _outputTail;
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+
+ while (offset < len) {
+ int ch = text.charAt(offset);
+ // note: here we know that (ch > 0x7F) will cover case of escaping non-ASCII too:
+ if (ch > 0x7F || escCodes[ch] != 0) {
+ break;
+ }
+ outputBuffer[outputPtr++] = (byte) ch;
+ ++offset;
+ }
+ _outputTail = outputPtr;
+ if (offset < len) {
+ if (_characterEscapes != null) {
+ _writeCustomStringSegment2(text, offset, len);
+ } else if (_maximumNonEscapedChar == 0) {
+ _writeStringSegment2(text, offset, len);
+ } else {
+ _writeStringSegmentASCII2(text, offset, len);
+ }
+ }
+ }
+
+ /**
+ * Secondary method called when content contains characters to escape,
+ * and/or multi-byte UTF-8 characters.
+ */
+ private final void _writeStringSegment2(final char[] cbuf, int offset, final int end) throws IOException
+ {
+ // Ok: caller guarantees buffer can have room; but that may require flushing:
+ if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
+ _flushBuffer();
+ }
+
+ int outputPtr = _outputTail;
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+
+ while (offset < end) {
+ int ch = cbuf[offset++];
+ if (ch <= 0x7F) {
+ if (escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = (byte) ch;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ continue;
+ }
+ if (ch <= 0x7FF) { // fine, just needs 2 byte output
+ outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
+ outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ outputPtr = _outputMultiByteChar(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ private final void _writeStringSegment2(final String text, int offset, final int end) throws IOException
+ {
+ if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
+ _flushBuffer();
+ }
+
+ int outputPtr = _outputTail;
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+
+ while (offset < end) {
+ int ch = text.charAt(offset++);
+ if (ch <= 0x7F) {
+ if (escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = (byte) ch;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ continue;
+ }
+ if (ch <= 0x7FF) { // fine, just needs 2 byte output
+ outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
+ outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ outputPtr = _outputMultiByteChar(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, text segment
+ /* with additional escaping (ASCII or such)
+ /**********************************************************
+ */
+
+ /**
+ * Same as _writeStringSegment2(char[], ...) _outputEnd) {
+ _flushBuffer();
+ }
+
+ int outputPtr = _outputTail;
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+ final int maxUnescaped = _maximumNonEscapedChar;
+
+ while (offset < end) {
+ int ch = cbuf[offset++];
+ if (ch <= 0x7F) {
+ if (escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = (byte) ch;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ continue;
+ }
+ if (ch > maxUnescaped) { // [JACKSON-102] Allow forced escaping if non-ASCII (etc) chars:
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ continue;
+ }
+ if (ch <= 0x7FF) { // fine, just needs 2 byte output
+ outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
+ outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ outputPtr = _outputMultiByteChar(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ private final void _writeStringSegmentASCII2(final String text, int offset, final int end) throws IOException
+ {
+ // Ok: caller guarantees buffer can have room; but that may require flushing:
+ if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
+ _flushBuffer();
+ }
+
+ int outputPtr = _outputTail;
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+ final int maxUnescaped = _maximumNonEscapedChar;
+
+ while (offset < end) {
+ int ch = text.charAt(offset++);
+ if (ch <= 0x7F) {
+ if (escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = (byte) ch;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ continue;
+ }
+ if (ch > maxUnescaped) { // [JACKSON-102] Allow forced escaping if non-ASCII (etc) chars:
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ continue;
+ }
+ if (ch <= 0x7FF) { // fine, just needs 2 byte output
+ outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
+ outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ outputPtr = _outputMultiByteChar(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, text segment
+ /* with fully custom escaping (and possibly escaping of non-ASCII
+ /**********************************************************
+ */
+
+ /**
+ * Same as
_writeStringSegmentASCII2(char[], ...) _outputEnd) {
+ _flushBuffer();
+ }
+ int outputPtr = _outputTail;
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+ // may or may not have this limit
+ final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar;
+ final CharacterEscapes customEscapes = _characterEscapes; // non-null
+
+ while (offset < end) {
+ int ch = cbuf[offset++];
+ if (ch <= 0x7F) {
+ if (escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = (byte) ch;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else if (escape == CharacterEscapes.ESCAPE_CUSTOM) {
+ SerializableString esc = customEscapes.getEscapeSequence(ch);
+ if (esc == null) {
+ _reportError("Invalid custom escape definitions; custom escape not found for character code 0x"
+ +Integer.toHexString(ch)+", although was supposed to have one");
+ }
+ outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ continue;
+ }
+ if (ch > maxUnescaped) { // [JACKSON-102] Allow forced escaping if non-ASCII (etc) chars:
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ continue;
+ }
+ SerializableString esc = customEscapes.getEscapeSequence(ch);
+ if (esc != null) {
+ outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
+ continue;
+ }
+ if (ch <= 0x7FF) { // fine, just needs 2 byte output
+ outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
+ outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ outputPtr = _outputMultiByteChar(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ private final void _writeCustomStringSegment2(final String text, int offset, final int end) throws IOException
+ {
+ // Ok: caller guarantees buffer can have room; but that may require flushing:
+ if ((_outputTail + 6 * (end - offset)) > _outputEnd) {
+ _flushBuffer();
+ }
+ int outputPtr = _outputTail;
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+ // may or may not have this limit
+ final int maxUnescaped = (_maximumNonEscapedChar <= 0) ? 0xFFFF : _maximumNonEscapedChar;
+ final CharacterEscapes customEscapes = _characterEscapes; // non-null
+
+ while (offset < end) {
+ int ch = text.charAt(offset++);
+ if (ch <= 0x7F) {
+ if (escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = (byte) ch;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else if (escape == CharacterEscapes.ESCAPE_CUSTOM) {
+ SerializableString esc = customEscapes.getEscapeSequence(ch);
+ if (esc == null) {
+ _reportError("Invalid custom escape definitions; custom escape not found for character code 0x"
+ +Integer.toHexString(ch)+", although was supposed to have one");
+ }
+ outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ continue;
+ }
+ if (ch > maxUnescaped) { // [JACKSON-102] Allow forced escaping if non-ASCII (etc) chars:
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ continue;
+ }
+ SerializableString esc = customEscapes.getEscapeSequence(ch);
+ if (esc != null) {
+ outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
+ continue;
+ }
+ if (ch <= 0x7FF) { // fine, just needs 2 byte output
+ outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
+ outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ outputPtr = _outputMultiByteChar(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ private final int _writeCustomEscape(byte[] outputBuffer, int outputPtr, SerializableString esc, int remainingChars)
+ throws IOException, JsonGenerationException
+ {
+ byte[] raw = esc.asUnquotedUTF8(); // must be escaped at this point, shouldn't double-quote
+ int len = raw.length;
+ if (len > 6) { // may violate constraints we have, do offline
+ return _handleLongCustomEscape(outputBuffer, outputPtr, _outputEnd, raw, remainingChars);
+ }
+ // otherwise will fit without issues, so:
+ System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
+ return (outputPtr + len);
+ }
+
+ private final int _handleLongCustomEscape(byte[] outputBuffer, int outputPtr, int outputEnd, byte[] raw,
+ int remainingChars)
+ throws IOException, JsonGenerationException
+ {
+ int len = raw.length;
+ if ((outputPtr + len) > outputEnd) {
+ _outputTail = outputPtr;
+ _flushBuffer();
+ outputPtr = _outputTail;
+ if (len > outputBuffer.length) { // very unlikely, but possible...
+ _outputStream.write(raw, 0, len);
+ return outputPtr;
+ }
+ System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
+ outputPtr += len;
+ }
+ // but is the invariant still obeyed? If not, flush once more
+ if ((outputPtr + 6 * remainingChars) > outputEnd) {
+ _flushBuffer();
+ return _outputTail;
+ }
+ return outputPtr;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, "raw UTF-8" segments
+ /**********************************************************
+ */
+
+ /**
+ * Method called when UTF-8 encoded (but NOT yet escaped!) content is not guaranteed
+ * to fit in the output buffer after escaping; as such, we just need to
+ * chunk writes.
+ */
+ private final void _writeUTF8Segments(byte[] utf8, int offset, int totalLen)
+ throws IOException, JsonGenerationException
+ {
+ do {
+ int len = Math.min(_outputMaxContiguous, totalLen);
+ _writeUTF8Segment(utf8, offset, len);
+ offset += len;
+ totalLen -= len;
+ } while (totalLen > 0);
+ }
+
+ private final void _writeUTF8Segment(byte[] utf8, final int offset, final int len)
+ throws IOException, JsonGenerationException
+ {
+ // fast loop to see if escaping is needed; don't copy, just look
+ final int[] escCodes = _outputEscapes;
+
+ for (int ptr = offset, end = offset + len; ptr < end; ) {
+ // 28-Feb-2011, tatu: escape codes just cover 7-bit range, so:
+ int ch = utf8[ptr++];
+ if ((ch >= 0) && escCodes[ch] != 0) {
+ _writeUTF8Segment2(utf8, offset, len);
+ return;
+ }
+ }
+
+ // yes, fine, just copy the sucker
+ if ((_outputTail + len) > _outputEnd) { // enough room or need to flush?
+ _flushBuffer(); // but yes once we flush (caller guarantees length restriction)
+ }
+ System.arraycopy(utf8, offset, _outputBuffer, _outputTail, len);
+ _outputTail += len;
+ }
+
+ private final void _writeUTF8Segment2(final byte[] utf8, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ int outputPtr = _outputTail;
+
+ // Ok: caller guarantees buffer can have room; but that may require flushing:
+ if ((outputPtr + (len * 6)) > _outputEnd) {
+ _flushBuffer();
+ outputPtr = _outputTail;
+ }
+
+ final byte[] outputBuffer = _outputBuffer;
+ final int[] escCodes = _outputEscapes;
+ len += offset; // so 'len' becomes 'end'
+
+ while (offset < len) {
+ byte b = utf8[offset++];
+ int ch = b;
+ if (ch < 0 || escCodes[ch] == 0) {
+ outputBuffer[outputPtr++] = b;
+ continue;
+ }
+ int escape = escCodes[ch];
+ if (escape > 0) { // 2-char escape, fine
+ outputBuffer[outputPtr++] = BYTE_BACKSLASH;
+ outputBuffer[outputPtr++] = (byte) escape;
+ } else {
+ // ctrl-char, 6-byte escape...
+ outputPtr = _writeGenericEscape(ch, outputPtr);
+ }
+ }
+ _outputTail = outputPtr;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing, base64 encoded
+ /**********************************************************
+ */
+
+ protected final void _writeBinary(Base64Variant b64variant,
+ byte[] input, int inputPtr, final int inputEnd)
+ throws IOException, JsonGenerationException
+ {
+ // Encoding is by chunks of 3 input, 4 output chars, so:
+ int safeInputEnd = inputEnd - 3;
+ // Let's also reserve room for possible (and quoted) lf char each round
+ int safeOutputEnd = _outputEnd - 6;
+ int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+
+ // Ok, first we loop through all full triplets of data:
+ while (inputPtr <= safeInputEnd) {
+ if (_outputTail > safeOutputEnd) { // need to flush
+ _flushBuffer();
+ }
+ // First, mash 3 bytes into lsb of 32-bit int
+ int b24 = ((int) input[inputPtr++]) << 8;
+ b24 |= ((int) input[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | (((int) input[inputPtr++]) & 0xFF);
+ _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
+ if (--chunksBeforeLF <= 0) {
+ // note: must quote in JSON value
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = 'n';
+ chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+ }
+ }
+
+ // And then we may have 1 or 2 leftover bytes to encode
+ int inputLeft = inputEnd - inputPtr; // 0, 1 or 2
+ if (inputLeft > 0) { // yes, but do we have room for output?
+ if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
+ _flushBuffer();
+ }
+ int b24 = ((int) input[inputPtr++]) << 16;
+ if (inputLeft == 2) {
+ b24 |= (((int) input[inputPtr++]) & 0xFF) << 8;
+ }
+ _outputTail = b64variant.encodeBase64Partial(b24, inputLeft, _outputBuffer, _outputTail);
+ }
+ }
+
+ // write-method called when length is definitely known
+ protected final int _writeBinary(Base64Variant b64variant,
+ InputStream data, byte[] readBuffer, int bytesLeft)
+ throws IOException, JsonGenerationException
+ {
+ int inputPtr = 0;
+ int inputEnd = 0;
+ int lastFullOffset = -3;
+
+ // Let's also reserve room for possible (and quoted) LF char each round
+ int safeOutputEnd = _outputEnd - 6;
+ int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+
+ while (bytesLeft > 2) { // main loop for full triplets
+ if (inputPtr > lastFullOffset) {
+ inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
+ inputPtr = 0;
+ if (inputEnd < 3) { // required to try to read to have at least 3 bytes
+ break;
+ }
+ lastFullOffset = inputEnd-3;
+ }
+ if (_outputTail > safeOutputEnd) { // need to flush
+ _flushBuffer();
+ }
+ int b24 = ((int) readBuffer[inputPtr++]) << 8;
+ b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ bytesLeft -= 3;
+ _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
+ if (--chunksBeforeLF <= 0) {
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = 'n';
+ chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+ }
+ }
+
+ // And then we may have 1 or 2 leftover bytes to encode
+ if (bytesLeft > 0) {
+ inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
+ inputPtr = 0;
+ if (inputEnd > 0) { // yes, but do we have room for output?
+ if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
+ _flushBuffer();
+ }
+ int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int amount;
+ if (inputPtr < inputEnd) {
+ b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ amount = 2;
+ } else {
+ amount = 1;
+ }
+ _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
+ bytesLeft -= amount;
+ }
+ }
+ return bytesLeft;
+ }
+
+ // write method when length is unknown
+ protected final int _writeBinary(Base64Variant b64variant,
+ InputStream data, byte[] readBuffer)
+ throws IOException, JsonGenerationException
+ {
+ int inputPtr = 0;
+ int inputEnd = 0;
+ int lastFullOffset = -3;
+ int bytesDone = 0;
+
+ // Let's also reserve room for possible (and quoted) LF char each round
+ int safeOutputEnd = _outputEnd - 6;
+ int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+
+ // Ok, first we loop through all full triplets of data:
+ while (true) {
+ if (inputPtr > lastFullOffset) { // need to load more
+ inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
+ inputPtr = 0;
+ if (inputEnd < 3) { // required to try to read to have at least 3 bytes
+ break;
+ }
+ lastFullOffset = inputEnd-3;
+ }
+ if (_outputTail > safeOutputEnd) { // need to flush
+ _flushBuffer();
+ }
+ // First, mash 3 bytes into lsb of 32-bit int
+ int b24 = ((int) readBuffer[inputPtr++]) << 8;
+ b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
+ b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
+ bytesDone += 3;
+ _outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
+ if (--chunksBeforeLF <= 0) {
+ _outputBuffer[_outputTail++] = '\\';
+ _outputBuffer[_outputTail++] = 'n';
+ chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
+ }
+ }
+
+ // And then we may have 1 or 2 leftover bytes to encode
+ if (inputPtr < inputEnd) { // yes, but do we have room for output?
+ if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
+ _flushBuffer();
+ }
+ int b24 = ((int) readBuffer[inputPtr++]) << 16;
+ int amount = 1;
+ if (inputPtr < inputEnd) {
+ b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
+ amount = 2;
+ }
+ bytesDone += amount;
+ _outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
+ }
+ return bytesDone;
+ }
+
+ private final int _readMore(InputStream in,
+ byte[] readBuffer, int inputPtr, int inputEnd,
+ int maxRead) throws IOException
+ {
+ // anything to shift to front?
+ int i = 0;
+ while (inputPtr < inputEnd) {
+ readBuffer[i++] = readBuffer[inputPtr++];
+ }
+ inputPtr = 0;
+ inputEnd = i;
+ maxRead = Math.min(maxRead, readBuffer.length);
+
+ do {
+ int length = maxRead - inputEnd;
+ if (length == 0) {
+ break;
+ }
+ int count = in.read(readBuffer, inputEnd, length);
+ if (count < 0) {
+ return inputEnd;
+ }
+ inputEnd += count;
+ } while (inputEnd < 3);
+ return inputEnd;
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, character escapes/encoding
+ /**********************************************************
+ */
+
+ /**
+ * Method called to output a character that is beyond range of
+ * 1- and 2-byte UTF-8 encodings, when outputting "raw"
+ * text (meaning it is not to be escaped or quoted)
+ */
+ private final int _outputRawMultiByteChar(int ch, char[] cbuf, int inputOffset, int inputLen)
+ throws IOException
+ {
+ // Let's handle surrogates gracefully (as 4 byte output):
+ if (ch >= SURR1_FIRST) {
+ if (ch <= SURR2_LAST) { // yes, outside of BMP
+ // Do we have second part?
+ if (inputOffset >= inputLen || cbuf == null) { // nope... have to note down
+ _reportError("Split surrogate on writeRaw() input (last character)");
+ }
+ _outputSurrogates(ch, cbuf[inputOffset]);
+ return (inputOffset+1);
+ }
+ }
+ final byte[] bbuf = _outputBuffer;
+ bbuf[_outputTail++] = (byte) (0xe0 | (ch >> 12));
+ bbuf[_outputTail++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
+ bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
+ return inputOffset;
+ }
+
+ protected final void _outputSurrogates(int surr1, int surr2) throws IOException
+ {
+ int c = _decodeSurrogate(surr1, surr2);
+ if ((_outputTail + 4) > _outputEnd) {
+ _flushBuffer();
+ }
+ final byte[] bbuf = _outputBuffer;
+ bbuf[_outputTail++] = (byte) (0xf0 | (c >> 18));
+ bbuf[_outputTail++] = (byte) (0x80 | ((c >> 12) & 0x3f));
+ bbuf[_outputTail++] = (byte) (0x80 | ((c >> 6) & 0x3f));
+ bbuf[_outputTail++] = (byte) (0x80 | (c & 0x3f));
+ }
+
+ /**
+ *
+ * @param ch
+ * @param outputPtr Position within output buffer to append multi-byte in
+ *
+ * @return New output position after appending
+ *
+ * @throws IOException
+ */
+ private final int _outputMultiByteChar(int ch, int outputPtr) throws IOException
+ {
+ byte[] bbuf = _outputBuffer;
+ if (ch >= SURR1_FIRST && ch <= SURR2_LAST) { // yes, outside of BMP; add an escape
+ // 23-Nov-2015, tatu: As per [core#223], may or may not want escapes;
+ // it would be added here... but as things are, we do not have proper
+ // access yet...
+// if (Feature.ESCAPE_UTF8_SURROGATES.enabledIn(_features)) {
+ bbuf[outputPtr++] = BYTE_BACKSLASH;
+ bbuf[outputPtr++] = BYTE_u;
+
+ bbuf[outputPtr++] = HEX_CHARS[(ch >> 12) & 0xF];
+ bbuf[outputPtr++] = HEX_CHARS[(ch >> 8) & 0xF];
+ bbuf[outputPtr++] = HEX_CHARS[(ch >> 4) & 0xF];
+ bbuf[outputPtr++] = HEX_CHARS[ch & 0xF];
+// } else { ... }
+ } else {
+ bbuf[outputPtr++] = (byte) (0xe0 | (ch >> 12));
+ bbuf[outputPtr++] = (byte) (0x80 | ((ch >> 6) & 0x3f));
+ bbuf[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
+ }
+ return outputPtr;
+ }
+
+ private final void _writeNull() throws IOException
+ {
+ if ((_outputTail + 4) >= _outputEnd) {
+ _flushBuffer();
+ }
+ System.arraycopy(NULL_BYTES, 0, _outputBuffer, _outputTail, 4);
+ _outputTail += 4;
+ }
+
+ /**
+ * Method called to write a generic Unicode escape for given character.
+ *
+ * @param charToEscape Character to escape using escape sequence (\\uXXXX)
+ */
+ private int _writeGenericEscape(int charToEscape, int outputPtr) throws IOException
+ {
+ final byte[] bbuf = _outputBuffer;
+ bbuf[outputPtr++] = BYTE_BACKSLASH;
+ bbuf[outputPtr++] = BYTE_u;
+ if (charToEscape > 0xFF) {
+ int hi = (charToEscape >> 8) & 0xFF;
+ bbuf[outputPtr++] = HEX_CHARS[hi >> 4];
+ bbuf[outputPtr++] = HEX_CHARS[hi & 0xF];
+ charToEscape &= 0xFF;
+ } else {
+ bbuf[outputPtr++] = BYTE_0;
+ bbuf[outputPtr++] = BYTE_0;
+ }
+ // We know it's a control char, so only the last 2 chars are non-0
+ bbuf[outputPtr++] = HEX_CHARS[charToEscape >> 4];
+ bbuf[outputPtr++] = HEX_CHARS[charToEscape & 0xF];
+ return outputPtr;
+ }
+
+ protected final void _flushBuffer() throws IOException
+ {
+ int len = _outputTail;
+ if (len > 0) {
+ _outputTail = 0;
+ _outputStream.write(_outputBuffer, 0, len);
+ }
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,3684 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.*;
+import java.util.Arrays;
+
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.core.base.ParserBase;
+import com.fasterxml.jackson.core.io.CharTypes;
+import com.fasterxml.jackson.core.io.IOContext;
+import com.fasterxml.jackson.core.sym.ByteQuadsCanonicalizer;
+import com.fasterxml.jackson.core.util.*;
+
+import static com.fasterxml.jackson.core.JsonTokenId.*;
+
+/**
+ * This is a concrete implementation of {@link JsonParser}, which is
+ * based on a {@link java.io.InputStream} as the input source.
+ *
ObjectMapper
, but that abstract is not part of core
+ * package.
+ */
+ protected ObjectCodec _objectCodec;
+
+ /**
+ * Symbol table that contains field names encountered so far
+ */
+ final protected ByteQuadsCanonicalizer _symbols;
+
+ /*
+ /**********************************************************
+ /* Parsing state
+ /**********************************************************
+ */
+
+ /**
+ * Temporary buffer used for name parsing.
+ */
+ protected int[] _quadBuffer = new int[16];
+
+ /**
+ * Flag that indicates that the current token has not yet
+ * been fully processed, and needs to be finished for
+ * some access (or skipped to obtain the next token)
+ */
+ protected boolean _tokenIncomplete;
+
+ /**
+ * Temporary storage for partially parsed name bytes.
+ */
+ private int _quad1;
+
+ /**
+ * Value of {@link #_inputPtr} at the time when the first character of
+ * name token was read. Used for calculating token location when requested;
+ * combined with {@link #_currInputProcessed}, may be updated appropriately
+ * as needed.
+ *
+ * @since 2.7
+ */
+ protected int _nameStartOffset;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartRow;
+
+ /**
+ * @since 2.7
+ */
+ protected int _nameStartCol;
+
+ /*
+ /**********************************************************
+ /* Input buffering (from former 'StreamBasedParserBase')
+ /**********************************************************
+ */
+
+ protected InputStream _inputStream;
+
+ /*
+ /**********************************************************
+ /* Current input data
+ /**********************************************************
+ */
+
+ /**
+ * Current buffer from which data is read; generally data is read into
+ * buffer from input source, but in some cases pre-loaded buffer
+ * is handed to the parser.
+ */
+ protected byte[] _inputBuffer;
+
+ /**
+ * Flag that indicates whether the input buffer is recycable (and
+ * needs to be returned to recycler once we are done) or not.
+ *_writeFieldName
, off-lined
+ * to keep the "fast path" as simple (and hopefully fast) as possible.
+ */
+ protected void _writePPFieldName(String name, boolean commaBefore) throws IOException
+ {
+ if (commaBefore) {
+ _cfgPrettyPrinter.writeObjectEntrySeparator(this);
+ } else {
+ _cfgPrettyPrinter.beforeObjectEntries(this);
+ }
+
+ if (_cfgUnqNames) {// non-standard, omit quotes
+ _writeString(name);
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _writeString(name);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+ }
+
+ protected void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
+ {
+ if (commaBefore) {
+ _cfgPrettyPrinter.writeObjectEntrySeparator(this);
+ } else {
+ _cfgPrettyPrinter.beforeObjectEntries(this);
+ }
+
+ final char[] quoted = name.asQuotedChars();
+ if (_cfgUnqNames) {// non-standard, omit quotes
+ writeRaw(quoted, 0, quoted.length);
+ } else {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ writeRaw(quoted, 0, quoted.length);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, textual
+ /**********************************************************
+ */
+
+ @Override
+ public void writeString(String text) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (text == null) {
+ _writeNull();
+ return;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _writeString(text);
+ // And finally, closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public void writeString(char[] text, int offset, int len) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _writeString(text, offset, len);
+ // And finally, closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public void writeString(SerializableString sstr) throws IOException
+ {
+ _verifyValueWrite(WRITE_STRING);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ // Note: copied from writeRaw:
+ char[] text = sstr.asQuotedChars();
+ final int len = text.length;
+ // Only worth buffering if it's a short write?
+ if (len < SHORT_WRITE) {
+ int room = _outputEnd - _outputTail;
+ if (len > room) {
+ _flushBuffer();
+ }
+ System.arraycopy(text, 0, _outputBuffer, _outputTail, len);
+ _outputTail += len;
+ } else {
+ // Otherwise, better just pass through:
+ _flushBuffer();
+ _writer.write(text, 0, len);
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException {
+ // could add support for buffering if we really want it...
+ _reportUnsupportedOperation();
+ }
+
+ @Override
+ public void writeUTF8String(byte[] text, int offset, int length) throws IOException {
+ // could add support for buffering if we really want it...
+ _reportUnsupportedOperation();
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, unprocessed ("raw")
+ /**********************************************************
+ */
+
+ @Override
+ public void writeRaw(String text) throws IOException
+ {
+ // Nothing to check, can just output as is
+ int len = text.length();
+ int room = _outputEnd - _outputTail;
+
+ if (room == 0) {
+ _flushBuffer();
+ room = _outputEnd - _outputTail;
+ }
+ // But would it nicely fit in? If yes, it's easy
+ if (room >= len) {
+ text.getChars(0, len, _outputBuffer, _outputTail);
+ _outputTail += len;
+ } else {
+ writeRawLong(text);
+ }
+ }
+
+ @Override
+ public void writeRaw(String text, int start, int len) throws IOException
+ {
+ // Nothing to check, can just output as is
+ int room = _outputEnd - _outputTail;
+
+ if (room < len) {
+ _flushBuffer();
+ room = _outputEnd - _outputTail;
+ }
+ // But would it nicely fit in? If yes, it's easy
+ if (room >= len) {
+ text.getChars(start, start+len, _outputBuffer, _outputTail);
+ _outputTail += len;
+ } else {
+ writeRawLong(text.substring(start, start+len));
+ }
+ }
+
+ // @since 2.1
+ @Override
+ public void writeRaw(SerializableString text) throws IOException {
+ writeRaw(text.getValue());
+ }
+
+ @Override
+ public void writeRaw(char[] text, int offset, int len) throws IOException
+ {
+ // Only worth buffering if it's a short write?
+ if (len < SHORT_WRITE) {
+ int room = _outputEnd - _outputTail;
+ if (len > room) {
+ _flushBuffer();
+ }
+ System.arraycopy(text, offset, _outputBuffer, _outputTail, len);
+ _outputTail += len;
+ return;
+ }
+ // Otherwise, better just pass through:
+ _flushBuffer();
+ _writer.write(text, offset, len);
+ }
+
+ @Override
+ public void writeRaw(char c) throws IOException
+ {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = c;
+ }
+
+ private void writeRawLong(String text) throws IOException
+ {
+ int room = _outputEnd - _outputTail;
+ // If not, need to do it by looping
+ text.getChars(0, room, _outputBuffer, _outputTail);
+ _outputTail += room;
+ _flushBuffer();
+ int offset = room;
+ int len = text.length() - room;
+
+ while (len > _outputEnd) {
+ int amount = _outputEnd;
+ text.getChars(offset, offset+amount, _outputBuffer, 0);
+ _outputHead = 0;
+ _outputTail = amount;
+ _flushBuffer();
+ offset += amount;
+ len -= amount;
+ }
+ // And last piece (at most length of buffer)
+ text.getChars(offset, offset+len, _outputBuffer, 0);
+ _outputHead = 0;
+ _outputTail = len;
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, base64-encoded binary
+ /**********************************************************
+ */
+
+ @Override
+ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len)
+ throws IOException, JsonGenerationException
+ {
+ _verifyValueWrite(WRITE_BINARY);
+ // Starting quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _writeBinary(b64variant, data, offset, offset+len);
+ // and closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public int writeBinary(Base64Variant b64variant,
+ InputStream data, int dataLength)
+ throws IOException, JsonGenerationException
+ {
+ _verifyValueWrite(WRITE_BINARY);
+ // Starting quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ byte[] encodingBuffer = _ioContext.allocBase64Buffer();
+ int bytes;
+ try {
+ if (dataLength < 0) { // length unknown
+ bytes = _writeBinary(b64variant, data, encodingBuffer);
+ } else {
+ int missing = _writeBinary(b64variant, data, encodingBuffer, dataLength);
+ if (missing > 0) {
+ _reportError("Too few bytes available: missing "+missing+" bytes (out of "+dataLength+")");
+ }
+ bytes = dataLength;
+ }
+ } finally {
+ _ioContext.releaseBase64Buffer(encodingBuffer);
+ }
+ // and closing quotes
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ return bytes;
+ }
+
+ /*
+ /**********************************************************
+ /* Output method implementations, primitive
+ /**********************************************************
+ */
+
+ @Override
+ public void writeNumber(short s) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedShort(s);
+ return;
+ }
+ // up to 5 digits and possible minus sign
+ if ((_outputTail + 6) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
+ }
+
+ private void _writeQuotedShort(short s) throws IOException {
+ if ((_outputTail + 8) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail);
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public void writeNumber(int i) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedInt(i);
+ return;
+ }
+ // up to 10 digits and possible minus sign
+ if ((_outputTail + 11) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
+ }
+
+ private void _writeQuotedInt(int i) throws IOException {
+ if ((_outputTail + 13) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail);
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public void writeNumber(long l) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedLong(l);
+ return;
+ }
+ if ((_outputTail + 21) >= _outputEnd) {
+ // up to 20 digits, minus sign
+ _flushBuffer();
+ }
+ _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
+ }
+
+ private void _writeQuotedLong(long l) throws IOException {
+ if ((_outputTail + 23) >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail);
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ // !!! 05-Aug-2008, tatus: Any ways to optimize these?
+
+ @Override
+ public void writeNumber(BigInteger value) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (value == null) {
+ _writeNull();
+ } else if (_cfgNumbersAsStrings) {
+ _writeQuotedRaw(value.toString());
+ } else {
+ writeRaw(value.toString());
+ }
+ }
+
+
+ @Override
+ public void writeNumber(double d) throws IOException
+ {
+ if (_cfgNumbersAsStrings ||
+ // [JACKSON-139]
+ (isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS) && ((Double.isNaN(d) || Double.isInfinite(d))))) {
+ writeString(String.valueOf(d));
+ return;
+ }
+ // What is the max length for doubles? 40 chars?
+ _verifyValueWrite(WRITE_NUMBER);
+ writeRaw(String.valueOf(d));
+ }
+
+ @Override
+ public void writeNumber(float f) throws IOException
+ {
+ if (_cfgNumbersAsStrings ||
+ // [JACKSON-139]
+ (isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS) && ((Float.isNaN(f) || Float.isInfinite(f))))) {
+ writeString(String.valueOf(f));
+ return;
+ }
+ // What is the max length for floats?
+ _verifyValueWrite(WRITE_NUMBER);
+ writeRaw(String.valueOf(f));
+ }
+
+ @Override
+ public void writeNumber(BigDecimal value) throws IOException
+ {
+ // Don't really know max length for big decimal, no point checking
+ _verifyValueWrite(WRITE_NUMBER);
+ if (value == null) {
+ _writeNull();
+ } else if (_cfgNumbersAsStrings) {
+ String raw = isEnabled(Feature.WRITE_BIGDECIMAL_AS_PLAIN) ? value.toPlainString() : value.toString();
+ _writeQuotedRaw(raw);
+ } else if (isEnabled(Feature.WRITE_BIGDECIMAL_AS_PLAIN)) {
+ writeRaw(value.toPlainString());
+ } else {
+ writeRaw(value.toString());
+ }
+ }
+
+ @Override
+ public void writeNumber(String encodedValue) throws IOException
+ {
+ _verifyValueWrite(WRITE_NUMBER);
+ if (_cfgNumbersAsStrings) {
+ _writeQuotedRaw(encodedValue);
+ } else {
+ writeRaw(encodedValue);
+ }
+ }
+
+ private void _writeQuotedRaw(String value) throws IOException
+ {
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ writeRaw(value);
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail++] = '"';
+ }
+
+ @Override
+ public void writeBoolean(boolean state) throws IOException
+ {
+ _verifyValueWrite(WRITE_BOOLEAN);
+ if ((_outputTail + 5) >= _outputEnd) {
+ _flushBuffer();
+ }
+ int ptr = _outputTail;
+ char[] buf = _outputBuffer;
+ if (state) {
+ buf[ptr] = 't';
+ buf[++ptr] = 'r';
+ buf[++ptr] = 'u';
+ buf[++ptr] = 'e';
+ } else {
+ buf[ptr] = 'f';
+ buf[++ptr] = 'a';
+ buf[++ptr] = 'l';
+ buf[++ptr] = 's';
+ buf[++ptr] = 'e';
+ }
+ _outputTail = ptr+1;
+ }
+
+ @Override
+ public void writeNull() throws IOException {
+ _verifyValueWrite(WRITE_NULL);
+ _writeNull();
+ }
+
+ /*
+ /**********************************************************
+ /* Implementations for other methods
+ /**********************************************************
+ */
+
+ @Override
+ protected void _verifyValueWrite(String typeMsg) throws IOException
+ {
+ if (_cfgPrettyPrinter != null) {
+ // Otherwise, pretty printer knows what to do...
+ _verifyPrettyValueWrite(typeMsg);
+ return;
+ }
+ char c;
+ final int status = _writeContext.writeValue();
+ if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
+ _reportError("Can not "+typeMsg+", expecting field name");
+ }
+ switch (status) {
+ case JsonWriteContext.STATUS_OK_AFTER_COMMA:
+ c = ',';
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_COLON:
+ c = ':';
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator
+ if (_rootValueSeparator != null) {
+ writeRaw(_rootValueSeparator.getValue());
+ }
+ return;
+ case JsonWriteContext.STATUS_OK_AS_IS:
+ default:
+ return;
+ }
+ if (_outputTail >= _outputEnd) {
+ _flushBuffer();
+ }
+ _outputBuffer[_outputTail] = c;
+ ++_outputTail;
+ }
+
+ protected void _verifyPrettyValueWrite(String typeMsg) throws IOException
+ {
+ final int status = _writeContext.writeValue();
+ if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
+ _reportError("Can not "+typeMsg+", expecting field name");
+ }
+
+ // If we have a pretty printer, it knows what to do:
+ switch (status) {
+ case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
+ _cfgPrettyPrinter.writeArrayValueSeparator(this);
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_COLON:
+ _cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
+ break;
+ case JsonWriteContext.STATUS_OK_AFTER_SPACE:
+ _cfgPrettyPrinter.writeRootValueSeparator(this);
+ break;
+ case JsonWriteContext.STATUS_OK_AS_IS:
+ // First entry, but of which context?
+ if (_writeContext.inArray()) {
+ _cfgPrettyPrinter.beforeArrayValues(this);
+ } else if (_writeContext.inObject()) {
+ _cfgPrettyPrinter.beforeObjectEntries(this);
+ }
+ break;
+ default:
+ _throwInternal();
+ break;
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Low-level output handling
+ /**********************************************************
+ */
+
+ @Override
+ public void flush() throws IOException
+ {
+ _flushBuffer();
+ if (_writer != null) {
+ if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
+ _writer.flush();
+ }
+ }
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ super.close();
+
+ /* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open
+ * scopes.
+ */
+ // First: let's see that we still have buffers...
+ if (_outputBuffer != null
+ && isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
+ while (true) {
+ JsonStreamContext ctxt = getOutputContext();
+ if (ctxt.inArray()) {
+ writeEndArray();
+ } else if (ctxt.inObject()) {
+ writeEndObject();
+ } else {
+ break;
+ }
+ }
+ }
+ _flushBuffer();
+ _outputHead = 0;
+ _outputTail = 0;
+
+ /* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
+ * on the underlying Reader, unless we "own" it, or auto-closing
+ * feature is enabled.
+ * One downside: when using UTF8Writer, underlying buffer(s)
+ * may not be properly recycled if we don't close the writer.
+ */
+ if (_writer != null) {
+ if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
+ _writer.close();
+ } else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
+ // If we can't close it, we should at least flush
+ _writer.flush();
+ }
+ }
+ // Internal buffer(s) generator has can now be released as well
+ _releaseBuffers();
+ }
+
+ @Override
+ protected void _releaseBuffers()
+ {
+ char[] buf = _outputBuffer;
+ if (buf != null) {
+ _outputBuffer = null;
+ _ioContext.releaseConcatBuffer(buf);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Internal methods, low-level writing; text, default
+ /**********************************************************
+ */
+
+ private void _writeString(String text) throws IOException
+ {
+ /* One check first: if String won't fit in the buffer, let's
+ * segment writes. No point in extending buffer to huge sizes
+ * (like if someone wants to include multi-megabyte base64
+ * encoded stuff or such)
+ */
+ final int len = text.length();
+ if (len > _outputEnd) { // Let's reserve space for entity at begin/end
+ _writeLongString(text);
+ return;
+ }
+
+ // Ok: we know String will fit in buffer ok
+ // But do we need to flush first?
+ if ((_outputTail + len) > _outputEnd) {
+ _flushBuffer();
+ }
+ text.getChars(0, len, _outputBuffer, _outputTail);
+
+ if (_characterEscapes != null) {
+ _writeStringCustom(len);
+ } else if (_maximumNonEscapedChar != 0) {
+ _writeStringASCII(len, _maximumNonEscapedChar);
+ } else {
+ _writeString2(len);
+ }
+ }
+
+ private void _writeString2(final int len) throws IOException
+ {
+ // And then we'll need to verify need for escaping etc:
+ final int end = _outputTail + len;
+ final int[] escCodes = _outputEscapes;
+ final int escLen = escCodes.length;
+
+ output_loop:
+ while (_outputTail < end) {
+ // Fast loop for chars not needing escaping
+ escape_loop:
+ while (true) {
+ char c = _outputBuffer[_outputTail];
+ if (c < escLen && escCodes[c] != 0) {
+ break escape_loop;
+ }
+ if (++_outputTail >= end) {
+ break output_loop;
+ }
+ }
+
+ // Ok, bumped into something that needs escaping.
+ /* First things first: need to flush the buffer.
+ * Inlined, as we don't want to lose tail pointer
+ */
+ int flushLen = (_outputTail - _outputHead);
+ if (flushLen > 0) {
+ _writer.write(_outputBuffer, _outputHead, flushLen);
+ }
+ /* In any case, tail will be the new start, so hopefully
+ * we have room now.
+ */
+ char c = _outputBuffer[_outputTail++];
+ _prependOrWriteCharacterEscape(c, escCodes[c]);
+ }
+ }
+
+ /**
+ * Method called to write "long strings", strings whose length exceeds
+ * output buffer length.
+ */
+ private void _writeLongString(String text) throws IOException
+ {
+ // First things first: let's flush the buffer to get some more room
+ _flushBuffer();
+
+ // Then we can write
+ final int textLen = text.length();
+ int offset = 0;
+ do {
+ int max = _outputEnd;
+ int segmentLen = ((offset + max) > textLen)
+ ? (textLen - offset) : max;
+ text.getChars(offset, offset+segmentLen, _outputBuffer, 0);
+ if (_characterEscapes != null) {
+ _writeSegmentCustom(segmentLen);
+ } else if (_maximumNonEscapedChar != 0) {
+ _writeSegmentASCII(segmentLen, _maximumNonEscapedChar);
+ } else {
+ _writeSegment(segmentLen);
+ }
+ offset += segmentLen;
+ } while (offset < textLen);
+ }
+
+ /**
+ * Method called to output textual context which has been copied
+ * to the output buffer prior to call. If any escaping is needed,
+ * it will also be handled by the method.
+ *
+ *
+ */
+
+package com.fasterxml.jackson.core;
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/sym/ByteQuadsCanonicalizer.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,1272 @@
+package com.fasterxml.jackson.core.sym;
+
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReference;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.util.InternCache;
+
+/**
+ * Replacement for JsonNode
) with the basic
+ *parsers and generators (iff using mapping-supporting factory: which
+ *is part of Mapping API, not core)
+ * com.fasterxml.jackson.databind.ObjectMapper
)
+ * can be exposed, without adding direct dependency to implementation.
+ * BytesToNameCanonicalizer
which aims at more localized
+ * memory access due to flattening of name quad data.
+ * Performance improvement modest for simple JSON document data binding (maybe 3%),
+ * but should help more for larger symbol tables, or for binary formats like Smile.
+ *
+ * @since 2.6
+ */
+public final class ByteQuadsCanonicalizer
+{
+ /**
+ * Initial size of the primary hash area. Each entry consumes 4 ints (16 bytes),
+ * and secondary area is same as primary; so default size will use 2kB of memory_tertiaryStart
+ * (plus 64x4 or 64x8 (256/512 bytes) for references to Strings, and Strings
+ * themselves).
+ */
+ private static final int DEFAULT_T_SIZE = 64;
+// private static final int DEFAULT_T_SIZE = 256;
+
+ /**
+ * Let's not expand symbol tables past some maximum size;
+ * this should protected against OOMEs caused by large documents
+ * with unique (~= random) names.
+ * Size is in
+ */
+ private static final int MAX_T_SIZE = 0x10000; // 64k entries == 2M mem hash area
+
+ /**
+ * No point in trying to construct tiny tables, just need to resize soon.
+ */
+ final static int MIN_HASH_SIZE = 16;
+
+ /**
+ * Let's only share reasonably sized symbol tables. Max size set to 3/4 of 8k;
+ * this corresponds to 256k main hash index. This should allow for enough distinct
+ * names for almost any case, while preventing ballooning for cases where names
+ * are unique (or close thereof).
+ */
+ final static int MAX_ENTRIES_FOR_REUSE = 6000;
+
+ /*
+ /**********************************************************
+ /* Linkage, needed for merging symbol tables
+ /**********************************************************
+ */
+
+ /**
+ * Reference to the root symbol table, for child tables, so
+ * that they can merge table information back as necessary.
+ */
+ final protected ByteQuadsCanonicalizer _parent;
+
+ /**
+ * Member that is only used by the root table instance: root
+ * passes immutable state into child instances, and children
+ * may return new state if they add entries to the table.
+ * Child tables do NOT use the reference.
+ */
+ final protected AtomicReference2 * _hashSize
+ * entries of 16 bytes (4 ints), arranged in a cascading lookup
+ * structure (details of which may be tweaked depending on expected rates
+ * of collisions).
+ */
+ protected int[] _hashArea;
+
+ /**
+ * Number of slots for primary entries within {@link #_hashArea}; which is
+ * at most 1/8
of actual size of the underlying array (4-int slots,
+ * primary covers only half of the area; plus, additional area for longer
+ * symbols after hash area).
+ */
+ protected int _hashSize;
+
+ /**
+ * Offset within {@link #_hashArea} where secondary entries start
+ */
+ protected int _secondaryStart;
+
+ /**
+ * Offset within {@link #_hashArea} where tertiary entries start
+ */
+ protected int _tertiaryStart;
+
+ /**
+ * Constant that determines size of buckets for tertiary entries:
+ * 1 << _tertiaryShift
is the size, and shift value
+ * is also used for translating from primary offset into
+ * tertiary bucket (shift right by 4 + _tertiaryShift
).
+ *String
instances matching
+ * entries in {@link #_hashArea}.
+ * Contains nulls for unused entries. Note that this size is twice
+ * that of {@link #_hashArea}
+ */
+ protected String[] _names;
+
+ /*
+ /**********************************************************
+ /* Then information on collisions etc
+ /**********************************************************
+ */
+
+ /**
+ * Pointer to the offset within spill-over area where there is room
+ * for more spilled over entries (if any).
+ * Spill over area is within fixed-size portion of {@link #_hashArea}.
+ */
+ protected int _spilloverEnd;
+
+ /**
+ * Offset within {@link #_hashArea} that follows main slots and contains
+ * quads for longer names (13 bytes or longers), and points to the
+ * first available int that may be used for appending quads of the next
+ * long name.
+ * Note that long name area follows immediately after the fixed-size
+ * main hash area ({@link #_hashArea}).
+ */
+ protected int _longNameOffset;
+
+ /**
+ * This flag is set if, after adding a new entry, it is deemed
+ * that a rehash is warranted if any more entries are to be added.
+ */
+ private transient boolean _needRehash;
+
+ /*
+ /**********************************************************
+ /* Sharing, versioning
+ /**********************************************************
+ */
+
+ // // // Which of the buffers may be shared (and are copy-on-write)?
+
+ /**
+ * Flag that indicates whether underlying data structures for
+ * the main hash area are shared or not. If they are, then they
+ * need to be handled in copy-on-write way, i.e. if they need
+ * to be modified, a copy needs to be made first; at this point
+ * it will not be shared any more, and can be modified.
+ *JsonFactory
"root"
+ * symbol tables: ones used for merging and sharing common symbols
+ *
+ * @param sz Initial primary hash area size
+ * @param intern Whether Strings contained should be {@link String#intern}ed
+ * @param seed Random seed valued used to make it more difficult to cause
+ * collisions (used for collision-based DoS attacks).
+ */
+ private ByteQuadsCanonicalizer(int sz, boolean intern, int seed, boolean failOnDoS) {
+ _parent = null;
+ _seed = seed;
+ _intern = intern;
+ _failOnDoS = failOnDoS;
+ // Sanity check: let's now allow hash sizes below certain minimum value
+ if (sz < MIN_HASH_SIZE) {
+ sz = MIN_HASH_SIZE;
+ } else {
+ // Also; size must be 2^N; otherwise hash algorithm won't
+ // work... so let's just pad it up, if so
+ if ((sz & (sz - 1)) != 0) { // only true if it's 2^N
+ int curr = MIN_HASH_SIZE;
+ while (curr < sz) {
+ curr += curr;
+ }
+ sz = curr;
+ }
+ }
+ _tableInfo = new AtomicReference
+ * Finally, rehashing is also more expensive, as hash codes are not
+ * stored; rehashing requires all entries' hash codes to be recalculated.
+ * Reason for not storing hash codes is reduced memory usage, hoping
+ * for better memory locality.
+ *release
),
+ * parent's shared tables may be updated from the child instance.
+ */
+ protected CharsToNameCanonicalizer _parent;
+
+ /**
+ * Seed value we use as the base to make hash codes non-static between
+ * different runs, but still stable for lifetime of a single symbol table
+ * instance.
+ * This is done for security reasons, to avoid potential DoS attack via
+ * hash collisions.
+ *
+ * @since 2.1
+ */
+ final private int _hashSeed;
+
+ final protected int _flags;
+
+ /**
+ * Whether any canonicalization should be attempted (whether using
+ * intern or not)
+ */
+ protected boolean _canonicalize;
+
+ /*
+ /**********************************************************
+ /* Actual symbol table data
+ /**********************************************************
+ */
+
+ /**
+ * Primary matching symbols; it's expected most match occur from
+ * here.
+ */
+ protected String[] _symbols;
+
+ /**
+ * Overflow buckets; if primary doesn't match, lookup is done
+ * from here.
+ *_buckets.length - 1
, when _buckets.length is
+ * a power of two.
+ */
+ protected int _indexMask;
+
+ /**
+ * We need to keep track of the longest collision list; this is needed
+ * both to indicate problems with attacks and to allow flushing for
+ * other cases.
+ *
+ * @since 2.1
+ */
+ protected int _longestCollisionList;
+
+ /*
+ /**********************************************************
+ /* State regarding shared arrays
+ /**********************************************************
+ */
+
+ /**
+ * Flag that indicates if any changes have been made to the data;
+ * used to both determine if bucket array needs to be copied when
+ * (first) change is made, and potentially if updated bucket list
+ * is to be resync'ed back to master instance.
+ */
+ protected boolean _dirty;
+
+ /*
+ /**********************************************************
+ /* Bit of DoS detection goodness
+ /**********************************************************
+ */
+
+ /**
+ * Lazily constructed structure that is used to keep track of
+ * collision buckets that have overflowed once: this is used
+ * to detect likely attempts at denial-of-service attacks that
+ * uses hash collisions.
+ *
+ * @since 2.4
+ */
+ protected BitSet _overflows;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ /**
+ * Method called to create root canonicalizer for a {@link com.fasterxml.jackson.core.JsonFactory}
+ * instance. Root instance is never used directly; its main use is for
+ * storing and sharing underlying symbol arrays as needed.
+ */
+ public static CharsToNameCanonicalizer createRoot() {
+ /* [Issue-21]: Need to use a variable seed, to thwart hash-collision
+ * based attacks.
+ */
+ long now = System.currentTimeMillis();
+ // ensure it's not 0; and might as well require to be odd so:
+ int seed = (((int) now) + ((int) (now >>> 32))) | 1;
+ return createRoot(seed);
+ }
+
+ protected static CharsToNameCanonicalizer createRoot(int hashSeed) {
+ return sBootstrapSymbolTable.makeOrphan(hashSeed);
+ }
+
+ /**
+ * Main method for constructing a master symbol table instance.
+ */
+ private CharsToNameCanonicalizer() {
+ // these settings don't really matter for the bootstrap instance
+ _canonicalize = true;
+ _flags = -1;
+ // And we'll also set flags so no copying of buckets is needed:
+ _dirty = true;
+ _hashSeed = 0;
+ _longestCollisionList = 0;
+ initTables(DEFAULT_T_SIZE);
+ }
+
+ private void initTables(int initialSize)
+ {
+ _symbols = new String[initialSize];
+ _buckets = new Bucket[initialSize >> 1];
+ // Mask is easy to calc for powers of two.
+ _indexMask = initialSize - 1;
+ _size = 0;
+ _longestCollisionList = 0;
+ // Hard-coded fill factor is 75%
+ _sizeThreshold = _thresholdSize(initialSize);
+ }
+
+ private static int _thresholdSize(int hashAreaSize) { return hashAreaSize - (hashAreaSize >> 2); }
+
+ /**
+ * Internal constructor used when creating child instances.
+ */
+ private CharsToNameCanonicalizer(CharsToNameCanonicalizer parent, int flags,
+ String[] symbols, Bucket[] buckets, int size, int hashSeed, int longestColl) {
+ _parent = parent;
+
+ _flags = flags;
+ _canonicalize = JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(flags);
+
+ _symbols = symbols;
+ _buckets = buckets;
+ _size = size;
+ _hashSeed = hashSeed;
+ // Hard-coded fill factor, 75%
+ int arrayLen = (symbols.length);
+ _sizeThreshold = _thresholdSize(arrayLen);
+ _indexMask = (arrayLen - 1);
+ _longestCollisionList = longestColl;
+
+ // Need to make copies of arrays, if/when adding new entries
+ _dirty = false;
+ }
+
+ /**
+ * "Factory" method; will create a new child instance of this symbol
+ * table. It will be a copy-on-write instance, ie. it will only use
+ * read-only copy of parent's data, but when changes are needed, a
+ * copy will be created.
+ *JavaType
from "databind" bundle -- this
+ * abstraction is only needed so that types can be passed through
+ * {@link com.fasterxml.jackson.core.JsonParser#readValueAs} methods.
+ *
+ * @since 2.0
+ */
+public abstract class ResolvedType
+{
+ /*
+ /**********************************************************
+ /* Public API, simple property accessors
+ /**********************************************************
+ */
+
+ /**
+ * Accessor for type-erased {@link Class} of resolved type.
+ */
+ public abstract Class> getRawClass();
+
+ public abstract boolean hasRawClass(Class> clz);
+
+ public abstract boolean isAbstract();
+
+ public abstract boolean isConcrete();
+
+ public abstract boolean isThrowable();
+
+ public abstract boolean isArrayType();
+
+ public abstract boolean isEnumType();
+
+ public abstract boolean isInterface();
+
+ public abstract boolean isPrimitive();
+
+ public abstract boolean isFinal();
+
+ public abstract boolean isContainerType();
+
+ public abstract boolean isCollectionLikeType();
+
+ /**
+ * Whether this type is a referential type, meaning that values are
+ * basically pointers to "real" values (or null) and not regular
+ * values themselves. Typical examples include things like
+ * {@link java.util.concurrent.atomic.AtomicReference}, and various
+ * Optional
types (in JDK8, Guava).
+ *
+ * @since 2.6
+ */
+ public boolean isReferenceType() {
+ return getReferencedType() != null;
+ }
+
+ public abstract boolean isMapLikeType();
+
+ /*
+ /**********************************************************
+ /* Public API, type parameter access
+ /**********************************************************
+ */
+
+ /**
+ * Method that can be used to find out if the type directly declares generic
+ * parameters (for its direct super-class and/or super-interfaces).
+ */
+ public abstract boolean hasGenericTypes();
+
+ /**
+ * Accessor that can be used to find out type for which parameterization
+ * is applied: this is often NOT same as what {@link #getRawClass} returns,
+ * but rather one of it supertype.
+ *TypeFactory
from mapper package).
+ * For simple types this is same as calling
+ * {@link Class#getName}, but for structured types it may additionally
+ * contain type information about contents.
+ */
+ public abstract String toCanonical();
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/type/TypeReference.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/type/TypeReference.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/type/TypeReference.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,58 @@
+package com.fasterxml.jackson.core.type;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/**
+ * This generic abstract class is used for obtaining full generics type information
+ * by sub-classing; it must be converted to {@link ResolvedType} implementation
+ * (implemented by JavaType
from "databind" bundle) to be used.
+ * Class is based on ideas from
+ * http://gafter.blogspot.com/2006/12/super-type-tokens.html,
+ * Additional idea (from a suggestion made in comments of the article)
+ * is to require bogus implementation of Comparable
+ * (any such generic interface would do, as long as it forces a method
+ * with generic type to be implemented).
+ * to ensure that a Type argument is indeed given.
+ *List<Integer>
:
+ *
+ * TypeReference ref = new TypeReference<List<Integer>>() { };
+ *
+ * which can be passed to methods that accept TypeReference, or resolved
+ * using TypeFactory
to obtain {@link ResolvedType}.
+ */
+public abstract class TypeReferenceComparable
) is to prevent constructing a
+ * reference without type information.
+ */
+ @Override
+ public int compareTo(TypeReferenceThreadLocal
member of the owning class pointing to
+ * instance of this class through a SoftReference
. The
+ * end result is a low-overhead GC-cleanable recycling: hopefully
+ * ideal for use by stream readers.
+ */
+public class BufferRecycler
+{
+ /**
+ * Buffer used for reading byte-based input.
+ */
+ public final static int BYTE_READ_IO_BUFFER = 0;
+
+ /**
+ * Buffer used for temporarily storing encoded content; used
+ * for example by UTF-8 encoding writer
+ */
+ public final static int BYTE_WRITE_ENCODING_BUFFER = 1;
+
+ /**
+ * Buffer used for temporarily concatenating output; used for
+ * example when requesting output as byte array.
+ */
+ public final static int BYTE_WRITE_CONCAT_BUFFER = 2;
+
+ /**
+ * Buffer used for concatenating binary data that is either being
+ * encoded as base64 output, or decoded from base64 input.
+ *
+ * @since 2.1
+ */
+ public final static int BYTE_BASE64_CODEC_BUFFER = 3;
+
+ public final static int CHAR_TOKEN_BUFFER = 0; // Tokenizable input
+ public final static int CHAR_CONCAT_BUFFER = 1; // concatenated output
+ public final static int CHAR_TEXT_BUFFER = 2; // Text content from input
+ public final static int CHAR_NAME_COPY_BUFFER = 3; // Temporary buffer for getting name characters
+
+ // Buffer lengths, defined in 2.4 (smaller before that)
+
+ private final static int[] BYTE_BUFFER_LENGTHS = new int[] { 8000, 8000, 2000, 2000 };
+ private final static int[] CHAR_BUFFER_LENGTHS = new int[] { 4000, 4000, 200, 200 };
+
+ final protected byte[][] _byteBuffers;
+ final protected char[][] _charBuffers;
+
+ /*
+ /**********************************************************
+ /* Construction
+ /**********************************************************
+ */
+
+ /**
+ * Default constructor used for creating instances of this default
+ * implementation.
+ */
+ public BufferRecycler() {
+ this(4, 4);
+ }
+
+ /**
+ * Alternate constructor to be used by sub-classes, to allow customization
+ * of number of low-level buffers in use.
+ *
+ * @since 2.4
+ */
+ protected BufferRecycler(int bbCount, int cbCount) {
+ _byteBuffers = new byte[bbCount][];
+ _charBuffers = new char[cbCount][];
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, byte buffers
+ /**********************************************************
+ */
+
+ /**
+ * @param ix One of READ_IO_BUFFER
constants.
+ */
+ public final byte[] allocByteBuffer(int ix) {
+ return allocByteBuffer(ix, 0);
+ }
+
+ public byte[] allocByteBuffer(int ix, int minSize) {
+ final int DEF_SIZE = byteBufferLength(ix);
+ if (minSize < DEF_SIZE) {
+ minSize = DEF_SIZE;
+ }
+ byte[] buffer = _byteBuffers[ix];
+ if (buffer == null || buffer.length < minSize) {
+ buffer = balloc(minSize);
+ } else {
+ _byteBuffers[ix] = null;
+ }
+ return buffer;
+ }
+
+ public final void releaseByteBuffer(int ix, byte[] buffer) {
+ _byteBuffers[ix] = buffer;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, char buffers
+ /**********************************************************
+ */
+
+ public final char[] allocCharBuffer(int ix) {
+ return allocCharBuffer(ix, 0);
+ }
+
+ public char[] allocCharBuffer(int ix, int minSize) {
+ final int DEF_SIZE = charBufferLength(ix);
+ if (minSize < DEF_SIZE) {
+ minSize = DEF_SIZE;
+ }
+ char[] buffer = _charBuffers[ix];
+ if (buffer == null || buffer.length < minSize) {
+ buffer = calloc(minSize);
+ } else {
+ _charBuffers[ix] = null;
+ }
+ return buffer;
+ }
+
+ public void releaseCharBuffer(int ix, char[] buffer) {
+ _charBuffers[ix] = buffer;
+ }
+
+ /*
+ /**********************************************************
+ /* Overridable helper methods
+ /**********************************************************
+ */
+
+ protected int byteBufferLength(int ix) {
+ return BYTE_BUFFER_LENGTHS[ix];
+ }
+
+ protected int charBufferLength(int ix) {
+ return CHAR_BUFFER_LENGTHS[ix];
+ }
+
+ /*
+ /**********************************************************
+ /* Actual allocations separated for easier debugging/profiling
+ /**********************************************************
+ */
+
+ protected byte[] balloc(int size) { return new byte[size]; }
+ protected char[] calloc(int size) { return new char[size]; }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/ByteArrayBuilder.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/ByteArrayBuilder.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/ByteArrayBuilder.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,244 @@
+/* Jackson JSON-processor.
+ *
+ * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
+ */
+
+package com.fasterxml.jackson.core.util;
+
+import java.io.OutputStream;
+import java.util.*;
+
+/**
+ * Helper class that is similar to {@link java.io.ByteArrayOutputStream}
+ * in usage, but more geared to Jackson use cases internally.
+ * Specific changes include segment storage (no need to have linear
+ * backing buffer, can avoid reallocations, copying), as well API
+ * not based on {@link java.io.OutputStream}. In short, a very much
+ * specialized builder object.
+ *indent
string to indent one level
+ * and the eol
string to separate lines.
+ */
+ public DefaultIndenter(String indent, String eol)
+ {
+ charsPerLevel = indent.length();
+
+ indents = new char[indent.length() * INDENT_LEVELS];
+ int offset = 0;
+ for (int i=0; idelagateCopyMethod
+ * and which defines whether copy methods are handled locally (false), or
+ * delegated to configured
+ */
+ public JsonGeneratorDelegate(JsonGenerator d, boolean delegateCopyMethods) {
+ delegate = d;
+ this.delegateCopyMethods = delegateCopyMethods;
+ }
+
+ @Override
+ public Object getCurrentValue() {
+ return delegate.getCurrentValue();
+ }
+
+ @Override
+ public void setCurrentValue(Object v) {
+ delegate.setCurrentValue(v);
+ }
+
+ /*
+ /**********************************************************
+ /* Extended API
+ /**********************************************************
+ */
+
+ public JsonGenerator getDelegate() { return delegate; }
+
+ /*
+ /**********************************************************
+ /* Public API, metadata
+ /**********************************************************
+ */
+
+ @Override public ObjectCodec getCodec() { return delegate.getCodec(); }
+
+ @Override public JsonGenerator setCodec(ObjectCodec oc) {
+ delegate.setCodec(oc);
+ return this;
+ }
+
+ @Override public void setSchema(FormatSchema schema) { delegate.setSchema(schema); }
+ @Override public FormatSchema getSchema() { return delegate.getSchema(); }
+ @Override public Version version() { return delegate.version(); }
+ @Override public Object getOutputTarget() { return delegate.getOutputTarget(); }
+ @Override public int getOutputBuffered() { return delegate.getOutputBuffered(); }
+
+ /*
+ /**********************************************************
+ /* Public API, capability introspection (since 2.3, mostly)
+ /**********************************************************
+ */
+
+ @Override
+ public boolean canUseSchema(FormatSchema schema) { return delegate.canUseSchema(schema); }
+
+ @Override
+ public boolean canWriteTypeId() { return delegate.canWriteTypeId(); }
+
+ @Override
+ public boolean canWriteObjectId() { return delegate.canWriteObjectId(); }
+
+ @Override
+ public boolean canWriteBinaryNatively() { return delegate.canWriteBinaryNatively(); }
+
+ @Override
+ public boolean canOmitFields() { return delegate.canOmitFields(); }
+
+ /*
+ /**********************************************************
+ /* Public API, configuration
+ /**********************************************************
+ */
+
+ @Override
+ public JsonGenerator enable(Feature f) {
+ delegate.enable(f);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator disable(Feature f) {
+ delegate.disable(f);
+ return this;
+ }
+
+ @Override
+ public boolean isEnabled(Feature f) { return delegate.isEnabled(f); }
+
+ // final, can't override (and no need to)
+ //public final JsonGenerator configure(Feature f, boolean state)
+
+ @Override
+ public int getFeatureMask() { return delegate.getFeatureMask(); }
+
+ @Override
+ @Deprecated
+ public JsonGenerator setFeatureMask(int mask) {
+ delegate.setFeatureMask(mask);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator overrideStdFeatures(int values, int mask) {
+ delegate.overrideStdFeatures(values, mask);
+ return this;
+ }
+
+ @Override
+ public JsonGenerator overrideFormatFeatures(int values, int mask) {
+ delegate.overrideFormatFeatures(values, mask);
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* Configuring generator
+ /**********************************************************
+ */
+
+ @Override
+ public JsonGenerator setPrettyPrinter(PrettyPrinter pp) {
+ delegate.setPrettyPrinter(pp);
+ return this;
+ }
+
+ @Override
+ public PrettyPrinter getPrettyPrinter() { return delegate.getPrettyPrinter(); }
+
+ @Override
+ public JsonGenerator useDefaultPrettyPrinter() { delegate.useDefaultPrettyPrinter();
+ return this; }
+
+ @Override
+ public JsonGenerator setHighestNonEscapedChar(int charCode) { delegate.setHighestNonEscapedChar(charCode);
+ return this; }
+
+ @Override
+ public int getHighestEscapedChar() { return delegate.getHighestEscapedChar(); }
+
+ @Override
+ public CharacterEscapes getCharacterEscapes() { return delegate.getCharacterEscapes(); }
+
+ @Override
+ public JsonGenerator setCharacterEscapes(CharacterEscapes esc) { delegate.setCharacterEscapes(esc);
+ return this; }
+
+ @Override
+ public JsonGenerator setRootValueSeparator(SerializableString sep) { delegate.setRootValueSeparator(sep);
+ return this; }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, structural
+ /**********************************************************
+ */
+
+ @Override
+ public void writeStartArray() throws IOException { delegate.writeStartArray(); }
+
+ @Override
+ public void writeStartArray(int size) throws IOException { delegate.writeStartArray(size); }
+
+ @Override
+ public void writeEndArray() throws IOException { delegate.writeEndArray(); }
+
+ @Override
+ public void writeStartObject() throws IOException { delegate.writeStartObject(); }
+
+ @Override
+ public void writeEndObject() throws IOException { delegate.writeEndObject(); }
+
+ @Override
+ public void writeFieldName(String name) throws IOException { delegate.writeFieldName(name); }
+
+ @Override
+ public void writeFieldName(SerializableString name) throws IOException { delegate.writeFieldName(name); }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, text/String values
+ /**********************************************************
+ */
+
+ @Override
+ public void writeString(String text) throws IOException { delegate.writeString(text); }
+
+ @Override
+ public void writeString(char[] text, int offset, int len) throws IOException { delegate.writeString(text, offset, len); }
+
+ @Override
+ public void writeString(SerializableString text) throws IOException { delegate.writeString(text); }
+
+ @Override
+ public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException { delegate.writeRawUTF8String(text, offset, length); }
+
+ @Override
+ public void writeUTF8String(byte[] text, int offset, int length) throws IOException { delegate.writeUTF8String(text, offset, length); }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, binary/raw content
+ /**********************************************************
+ */
+
+ @Override
+ public void writeRaw(String text) throws IOException { delegate.writeRaw(text); }
+
+ @Override
+ public void writeRaw(String text, int offset, int len) throws IOException { delegate.writeRaw(text, offset, len); }
+
+ @Override
+ public void writeRaw(SerializableString raw) throws IOException { delegate.writeRaw(raw); }
+
+ @Override
+ public void writeRaw(char[] text, int offset, int len) throws IOException { delegate.writeRaw(text, offset, len); }
+
+ @Override
+ public void writeRaw(char c) throws IOException { delegate.writeRaw(c); }
+
+ @Override
+ public void writeRawValue(String text) throws IOException { delegate.writeRawValue(text); }
+
+ @Override
+ public void writeRawValue(String text, int offset, int len) throws IOException { delegate.writeRawValue(text, offset, len); }
+
+ @Override
+ public void writeRawValue(char[] text, int offset, int len) throws IOException { delegate.writeRawValue(text, offset, len); }
+
+ @Override
+ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len) throws IOException { delegate.writeBinary(b64variant, data, offset, len); }
+
+ @Override
+ public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException { return delegate.writeBinary(b64variant, data, dataLength); }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, other value types
+ /**********************************************************
+ */
+
+ @Override
+ public void writeNumber(short v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(int v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(long v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(BigInteger v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(double v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(float v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(BigDecimal v) throws IOException { delegate.writeNumber(v); }
+
+ @Override
+ public void writeNumber(String encodedValue) throws IOException, UnsupportedOperationException { delegate.writeNumber(encodedValue); }
+
+ @Override
+ public void writeBoolean(boolean state) throws IOException { delegate.writeBoolean(state); }
+
+ @Override
+ public void writeNull() throws IOException { delegate.writeNull(); }
+
+ /*
+ /**********************************************************
+ /* Overridden field methods
+ /**********************************************************
+ */
+
+ @Override
+ public void writeOmittedField(String fieldName) throws IOException { delegate.writeOmittedField(fieldName); }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, Native Ids
+ /**********************************************************
+ */
+
+ @Override
+ public void writeObjectId(Object id) throws IOException { delegate.writeObjectId(id); }
+
+ @Override
+ public void writeObjectRef(Object id) throws IOException { delegate.writeObjectRef(id); }
+
+ @Override
+ public void writeTypeId(Object id) throws IOException { delegate.writeTypeId(id); }
+
+ /*
+ /**********************************************************
+ /* Public API, write methods, serializing Java objects
+ /**********************************************************
+ */
+
+ @Override
+ public void writeObject(Object pojo) throws IOException,JsonProcessingException {
+ if (delegateCopyMethods) {
+ delegate.writeObject(pojo);
+ return;
+ }
+ // NOTE: copied from
+ if (pojo == null) {
+ writeNull();
+ } else {
+ if (getCodec() != null) {
+ getCodec().writeValue(this, pojo);
+ return;
+ }
+ _writeSimpleObject(pojo);
+ }
+ }
+
+ @Override
+ public void writeTree(TreeNode rootNode) throws IOException {
+ if (delegateCopyMethods) {
+ delegate.writeTree(rootNode);
+ return;
+ }
+ // As with 'writeObject()', we are not check if write would work
+ if (rootNode == null) {
+ writeNull();
+ } else {
+ if (getCodec() == null) {
+ throw new IllegalStateException("No ObjectCodec defined");
+ }
+ getCodec().writeValue(this, rootNode);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, convenience field write methods
+ /**********************************************************
+ */
+
+ // // These are fine, just delegate to other methods...
+
+ /*
+ /**********************************************************
+ /* Public API, copy-through methods
+ /**********************************************************
+ */
+
+ @Override
+ public void copyCurrentEvent(JsonParser jp) throws IOException {
+ if (delegateCopyMethods) delegate.copyCurrentEvent(jp);
+ else super.copyCurrentEvent(jp);
+ }
+
+ @Override
+ public void copyCurrentStructure(JsonParser jp) throws IOException {
+ if (delegateCopyMethods) delegate.copyCurrentStructure(jp);
+ else super.copyCurrentStructure(jp);
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, context access
+ /**********************************************************
+ */
+
+ @Override public JsonStreamContext getOutputContext() { return delegate.getOutputContext(); }
+
+ /*
+ /**********************************************************
+ /* Public API, buffer handling
+ /**********************************************************
+ */
+
+ @Override public void flush() throws IOException { delegate.flush(); }
+ @Override public void close() throws IOException { delegate.close(); }
+
+ /*
+ /**********************************************************
+ /* Closeable implementation
+ /**********************************************************
+ */
+
+ @Override public boolean isClosed() { return delegate.isClosed(); }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonParserDelegate.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonParserDelegate.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonParserDelegate.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,230 @@
+package com.fasterxml.jackson.core.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Helper class that implements
+ * delegation pattern for {@link JsonParser},
+ * to allow for simple overridability of basic parsing functionality.
+ * The idea is that any functionality to be modified can be simply
+ * overridden; and anything else will be delegated by default.
+ */
+public class JsonParserDelegate extends JsonParser
+{
+ /**
+ * Delegate object that method calls are delegated to.
+ */
+ protected JsonParser delegate;
+
+ public JsonParserDelegate(JsonParser d) {
+ delegate = d;
+ }
+
+ @Override
+ public Object getCurrentValue() {
+ return delegate.getCurrentValue();
+ }
+
+ @Override
+ public void setCurrentValue(Object v) {
+ delegate.setCurrentValue(v);
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, configuration
+ /**********************************************************
+ */
+
+ @Override public void setCodec(ObjectCodec c) { delegate.setCodec(c); }
+ @Override public ObjectCodec getCodec() { return delegate.getCodec(); }
+
+ @Override
+ public JsonParser enable(Feature f) {
+ delegate.enable(f);
+ return this;
+ }
+
+ @Override
+ public JsonParser disable(Feature f) {
+ delegate.disable(f);
+ return this;
+ }
+
+ @Override public boolean isEnabled(Feature f) { return delegate.isEnabled(f); }
+ @Override public int getFeatureMask() { return delegate.getFeatureMask(); }
+
+ @Override
+ @Deprecated // since 2.7
+ public JsonParser setFeatureMask(int mask) {
+ delegate.setFeatureMask(mask);
+ return this;
+ }
+
+ @Override
+ public JsonParser overrideStdFeatures(int values, int mask) {
+ delegate.overrideStdFeatures(values, mask);
+ return this;
+ }
+
+ @Override
+ public JsonParser overrideFormatFeatures(int values, int mask) {
+ delegate.overrideFormatFeatures(values, mask);
+ return this;
+ }
+
+ @Override public FormatSchema getSchema() { return delegate.getSchema(); }
+ @Override public void setSchema(FormatSchema schema) { delegate.setSchema(schema); }
+ @Override public boolean canUseSchema(FormatSchema schema) { return delegate.canUseSchema(schema); }
+ @Override public Version version() { return delegate.version(); }
+ @Override public Object getInputSource() { return delegate.getInputSource(); }
+
+ /*
+ /**********************************************************
+ /* Capability introspection
+ /**********************************************************
+ */
+
+ @Override public boolean requiresCustomCodec() { return delegate.requiresCustomCodec(); }
+
+ /*
+ /**********************************************************
+ /* Closeable impl
+ /**********************************************************
+ */
+
+ @Override public void close() throws IOException { delegate.close(); }
+ @Override public boolean isClosed() { return delegate.isClosed(); }
+
+ /*
+ /**********************************************************
+ /* Public API, token accessors
+ /**********************************************************
+ */
+
+ @Override public JsonToken getCurrentToken() { return delegate.getCurrentToken(); }
+ @Override public int getCurrentTokenId() { return delegate.getCurrentTokenId(); }
+ @Override public boolean hasCurrentToken() { return delegate.hasCurrentToken(); }
+ @Override public boolean hasTokenId(int id) { return delegate.hasTokenId(id); }
+ @Override public boolean hasToken(JsonToken t) { return delegate.hasToken(t); }
+
+ @Override public String getCurrentName() throws IOException { return delegate.getCurrentName(); }
+ @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
+ @Override public JsonStreamContext getParsingContext() { return delegate.getParsingContext(); }
+ @Override public boolean isExpectedStartArrayToken() { return delegate.isExpectedStartArrayToken(); }
+ @Override public boolean isExpectedStartObjectToken() { return delegate.isExpectedStartObjectToken(); }
+
+ /*
+ /**********************************************************
+ /* Public API, token state overrides
+ /**********************************************************
+ */
+
+ @Override public void clearCurrentToken() { delegate.clearCurrentToken(); }
+ @Override public JsonToken getLastClearedToken() { return delegate.getLastClearedToken(); }
+ @Override public void overrideCurrentName(String name) { delegate.overrideCurrentName(name); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, text
+ /**********************************************************
+ */
+
+ @Override public String getText() throws IOException { return delegate.getText(); }
+ @Override public boolean hasTextCharacters() { return delegate.hasTextCharacters(); }
+ @Override public char[] getTextCharacters() throws IOException { return delegate.getTextCharacters(); }
+ @Override public int getTextLength() throws IOException { return delegate.getTextLength(); }
+ @Override public int getTextOffset() throws IOException { return delegate.getTextOffset(); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, numeric
+ /**********************************************************
+ */
+
+ @Override
+ public BigInteger getBigIntegerValue() throws IOException { return delegate.getBigIntegerValue(); }
+
+ @Override
+ public boolean getBooleanValue() throws IOException { return delegate.getBooleanValue(); }
+
+ @Override
+ public byte getByteValue() throws IOException { return delegate.getByteValue(); }
+
+ @Override
+ public short getShortValue() throws IOException { return delegate.getShortValue(); }
+
+ @Override
+ public BigDecimal getDecimalValue() throws IOException { return delegate.getDecimalValue(); }
+
+ @Override
+ public double getDoubleValue() throws IOException { return delegate.getDoubleValue(); }
+
+ @Override
+ public float getFloatValue() throws IOException { return delegate.getFloatValue(); }
+
+ @Override
+ public int getIntValue() throws IOException { return delegate.getIntValue(); }
+
+ @Override
+ public long getLongValue() throws IOException { return delegate.getLongValue(); }
+
+ @Override
+ public NumberType getNumberType() throws IOException { return delegate.getNumberType(); }
+
+ @Override
+ public Number getNumberValue() throws IOException { return delegate.getNumberValue(); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token information, coercion/conversion
+ /**********************************************************
+ */
+
+ @Override public int getValueAsInt() throws IOException { return delegate.getValueAsInt(); }
+ @Override public int getValueAsInt(int defaultValue) throws IOException { return delegate.getValueAsInt(defaultValue); }
+ @Override public long getValueAsLong() throws IOException { return delegate.getValueAsLong(); }
+ @Override public long getValueAsLong(long defaultValue) throws IOException { return delegate.getValueAsLong(defaultValue); }
+ @Override public double getValueAsDouble() throws IOException { return delegate.getValueAsDouble(); }
+ @Override public double getValueAsDouble(double defaultValue) throws IOException { return delegate.getValueAsDouble(defaultValue); }
+ @Override public boolean getValueAsBoolean() throws IOException { return delegate.getValueAsBoolean(); }
+ @Override public boolean getValueAsBoolean(boolean defaultValue) throws IOException { return delegate.getValueAsBoolean(defaultValue); }
+ @Override public String getValueAsString() throws IOException { return delegate.getValueAsString(); }
+ @Override public String getValueAsString(String defaultValue) throws IOException { return delegate.getValueAsString(defaultValue); }
+
+ /*
+ /**********************************************************
+ /* Public API, access to token values, other
+ /**********************************************************
+ */
+
+ @Override public Object getEmbeddedObject() throws IOException { return delegate.getEmbeddedObject(); }
+ @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { return delegate.getBinaryValue(b64variant); }
+ @Override public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException { return delegate.readBinaryValue(b64variant, out); }
+ @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
+ @Override public JsonToken nextToken() throws IOException { return delegate.nextToken(); }
+ @Override public JsonToken nextValue() throws IOException { return delegate.nextValue(); }
+
+ @Override
+ public JsonParser skipChildren() throws IOException {
+ delegate.skipChildren();
+ // NOTE: must NOT delegate this method to delegate, needs to be self-reference for chaining
+ return this;
+ }
+
+ /*
+ /**********************************************************
+ /* Public API, Native Ids (type, object)
+ /**********************************************************
+ */
+
+ @Override public boolean canReadObjectId() { return delegate.canReadObjectId(); }
+ @Override public boolean canReadTypeId() { return delegate.canReadTypeId(); }
+ @Override public Object getObjectId() throws IOException { return delegate.getObjectId(); }
+ @Override public Object getTypeId() throws IOException { return delegate.getTypeId(); }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonParserSequence.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonParserSequence.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/JsonParserSequence.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,145 @@
+package com.fasterxml.jackson.core.util;
+
+import java.io.IOException;
+import java.util.*;
+
+import com.fasterxml.jackson.core.*;
+
+/**
+ * Helper class that can be used to sequence multiple physical
+ * {@link JsonParser}s to create a single logical sequence of
+ * tokens, as a single {@link JsonParser}.
+ *
+ *
+ */
+public final class TextBuffer
+{
+ final static char[] NO_CHARS = new char[0];
+
+ /**
+ * Let's start with sizable but not huge buffer, will grow as necessary
+ */
+ final static int MIN_SEGMENT_LEN = 1000;
+
+ /**
+ * Let's limit maximum segment length to something sensible
+ * like 256k
+ */
+ final static int MAX_SEGMENT_LEN = 0x40000;
+
+ /*
+ /**********************************************************
+ /* Configuration:
+ /**********************************************************
+ */
+
+ private final BufferRecycler _allocator;
+
+ /*
+ /**********************************************************
+ /* Shared input buffers
+ /**********************************************************
+ */
+
+ /**
+ * Shared input buffer; stored here in case some input can be returned
+ * as is, without being copied to collector's own buffers. Note that
+ * this is read-only for this Object.
+ */
+ private char[] _inputBuffer;
+
+ /**
+ * Character offset of first char in input buffer; -1 to indicate
+ * that input buffer currently does not contain any useful char data
+ */
+ private int _inputStart;
+
+ private int _inputLen;
+
+ /*
+ /**********************************************************
+ /* Aggregation segments (when not using input buf)
+ /**********************************************************
+ */
+
+ /**
+ * List of segments prior to currently active segment.
+ */
+ private ArrayListchar
array regardless of whether they were collected in a segmented
+ * fashion or not.
+ */
+ public char[] getTextBuffer()
+ {
+ // Are we just using shared input buffer?
+ if (_inputStart >= 0) return _inputBuffer;
+ if (_resultArray != null) return _resultArray;
+ if (_resultString != null) {
+ return (_resultArray = _resultString.toCharArray());
+ }
+ // Nope; but does it fit in just one segment?
+ if (!_hasSegments) {
+ return (_currentSegment == null) ? NO_CHARS : _currentSegment;
+ }
+ // Nope, need to have/create a non-segmented array and return it
+ return contentsAsArray();
+ }
+
+ /*
+ /**********************************************************
+ /* Other accessors:
+ /**********************************************************
+ */
+
+ public String contentsAsString()
+ {
+ if (_resultString == null) {
+ // Has array been requested? Can make a shortcut, if so:
+ if (_resultArray != null) {
+ _resultString = new String(_resultArray);
+ } else {
+ // Do we use shared array?
+ if (_inputStart >= 0) {
+ if (_inputLen < 1) {
+ return (_resultString = "");
+ }
+ _resultString = new String(_inputBuffer, _inputStart, _inputLen);
+ } else { // nope... need to copy
+ // But first, let's see if we have just one buffer
+ int segLen = _segmentSize;
+ int currLen = _currentSize;
+
+ if (segLen == 0) { // yup
+ _resultString = (currLen == 0) ? "" : new String(_currentSegment, 0, currLen);
+ } else { // no, need to combine
+ StringBuilder sb = new StringBuilder(segLen + currLen);
+ // First stored segments
+ if (_segments != null) {
+ for (int i = 0, len = _segments.size(); i < len; ++i) {
+ char[] curr = _segments.get(i);
+ sb.append(curr, 0, curr.length);
+ }
+ }
+ // And finally, current segment:
+ sb.append(_currentSegment, 0, _currentSize);
+ _resultString = sb.toString();
+ }
+ }
+ }
+ }
+ return _resultString;
+ }
+
+ public char[] contentsAsArray() {
+ char[] result = _resultArray;
+ if (result == null) {
+ _resultArray = result = resultArray();
+ }
+ return result;
+ }
+
+ /**
+ * Convenience method for converting contents of the buffer
+ * into a {@link BigDecimal}.
+ */
+ public BigDecimal contentsAsDecimal() throws NumberFormatException
+ {
+ // Already got a pre-cut array?
+ if (_resultArray != null) {
+ return NumberInput.parseBigDecimal(_resultArray);
+ }
+ // Or a shared buffer?
+ if ((_inputStart >= 0) && (_inputBuffer != null)) {
+ return NumberInput.parseBigDecimal(_inputBuffer, _inputStart, _inputLen);
+ }
+ // Or if not, just a single buffer (the usual case)
+ if ((_segmentSize == 0) && (_currentSegment != null)) {
+ return NumberInput.parseBigDecimal(_currentSegment, 0, _currentSize);
+ }
+ // If not, let's just get it aggregated...
+ return NumberInput.parseBigDecimal(contentsAsArray());
+ }
+
+ /**
+ * Convenience method for converting contents of the buffer
+ * into a Double value.
+ */
+ public double contentsAsDouble() throws NumberFormatException {
+ return NumberInput.parseDouble(contentsAsString());
+ }
+
+ /*
+ /**********************************************************
+ /* Public mutators:
+ /**********************************************************
+ */
+
+ /**
+ * Method called to make sure that buffer is not using shared input
+ * buffer; if it is, it will copy such contents to private buffer.
+ */
+ public void ensureNotShared() {
+ if (_inputStart >= 0) {
+ unshare(16);
+ }
+ }
+
+ public void append(char c) {
+ // Using shared buffer so far?
+ if (_inputStart >= 0) {
+ unshare(16);
+ }
+ _resultString = null;
+ _resultArray = null;
+ // Room in current segment?
+ char[] curr = _currentSegment;
+ if (_currentSize >= curr.length) {
+ expand(1);
+ curr = _currentSegment;
+ }
+ curr[_currentSize++] = c;
+ }
+
+ public void append(char[] c, int start, int len)
+ {
+ // Can't append to shared buf (sanity check)
+ if (_inputStart >= 0) {
+ unshare(len);
+ }
+ _resultString = null;
+ _resultArray = null;
+
+ // Room in current segment?
+ char[] curr = _currentSegment;
+ int max = curr.length - _currentSize;
+
+ if (max >= len) {
+ System.arraycopy(c, start, curr, _currentSize, len);
+ _currentSize += len;
+ return;
+ }
+ // No room for all, need to copy part(s):
+ if (max > 0) {
+ System.arraycopy(c, start, curr, _currentSize, max);
+ start += max;
+ len -= max;
+ }
+ /* And then allocate new segment; we are guaranteed to now
+ * have enough room in segment.
+ */
+ // Except, as per [Issue-24], not for HUGE appends... so:
+ do {
+ expand(len);
+ int amount = Math.min(_currentSegment.length, len);
+ System.arraycopy(c, start, _currentSegment, 0, amount);
+ _currentSize += amount;
+ start += amount;
+ len -= amount;
+ } while (len > 0);
+ }
+
+ public void append(String str, int offset, int len)
+ {
+ // Can't append to shared buf (sanity check)
+ if (_inputStart >= 0) {
+ unshare(len);
+ }
+ _resultString = null;
+ _resultArray = null;
+
+ // Room in current segment?
+ char[] curr = _currentSegment;
+ int max = curr.length - _currentSize;
+ if (max >= len) {
+ str.getChars(offset, offset+len, curr, _currentSize);
+ _currentSize += len;
+ return;
+ }
+ // No room for all, need to copy part(s):
+ if (max > 0) {
+ str.getChars(offset, offset+max, curr, _currentSize);
+ len -= max;
+ offset += max;
+ }
+ /* And then allocate new segment; we are guaranteed to now
+ * have enough room in segment.
+ */
+ // Except, as per [Issue-24], not for HUGE appends... so:
+ do {
+ expand(len);
+ int amount = Math.min(_currentSegment.length, len);
+ str.getChars(offset, offset+amount, _currentSegment, 0);
+ _currentSize += amount;
+ offset += amount;
+ len -= amount;
+ } while (len > 0);
+ }
+
+ /*
+ /**********************************************************
+ /* Raw access, for high-performance use:
+ /**********************************************************
+ */
+
+ public char[] getCurrentSegment()
+ {
+ /* Since the intention of the caller is to directly add stuff into
+ * buffers, we should NOT have anything in shared buffer... ie. may
+ * need to unshare contents.
+ */
+ if (_inputStart >= 0) {
+ unshare(1);
+ } else {
+ char[] curr = _currentSegment;
+ if (curr == null) {
+ _currentSegment = buf(0);
+ } else if (_currentSize >= curr.length) {
+ // Plus, we better have room for at least one more char
+ expand(1);
+ }
+ }
+ return _currentSegment;
+ }
+
+ public char[] emptyAndGetCurrentSegment()
+ {
+ // inlined 'resetWithEmpty()'
+ _inputStart = -1; // indicates shared buffer not used
+ _currentSize = 0;
+ _inputLen = 0;
+
+ _inputBuffer = null;
+ _resultString = null;
+ _resultArray = null;
+
+ // And then reset internal input buffers, if necessary:
+ if (_hasSegments) {
+ clearSegments();
+ }
+ char[] curr = _currentSegment;
+ if (curr == null) {
+ _currentSegment = curr = buf(0);
+ }
+ return curr;
+ }
+
+ public int getCurrentSegmentSize() { return _currentSize; }
+ public void setCurrentLength(int len) { _currentSize = len; }
+
+ /**
+ * @since 2.6
+ */
+ public String setCurrentAndReturn(int len) {
+ _currentSize = len;
+ // We can simplify handling here compared to full `contentsAsString()`:
+ if (_segmentSize > 0) { // longer text; call main method
+ return contentsAsString();
+ }
+ // more common case: single segment
+ int currLen = _currentSize;
+ String str = (currLen == 0) ? "" : new String(_currentSegment, 0, currLen);
+ _resultString = str;
+ return str;
+ }
+
+ public char[] finishCurrentSegment() {
+ if (_segments == null) {
+ _segments = new ArrayListPackageVersion
classes to decode version injected by Maven build.
+ */
+ public static Version parseVersion(String s, String groupId, String artifactId)
+ {
+ if (s != null && (s = s.trim()).length() > 0) {
+ String[] parts = V_SEP.split(s);
+ return new Version(parseVersionPart(parts[0]),
+ (parts.length > 1) ? parseVersionPart(parts[1]) : 0,
+ (parts.length > 2) ? parseVersionPart(parts[2]) : 0,
+ (parts.length > 3) ? parts[3] : null,
+ groupId, artifactId);
+ }
+ return Version.unknownVersion();
+ }
+
+ protected static int parseVersionPart(String s) {
+ int number = 0;
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ char c = s.charAt(i);
+ if (c > '9' || c < '0') break;
+ number = (number * 10) + (c - '0');
+ }
+ return number;
+ }
+
+ private final static void _close(Closeable c) {
+ try {
+ c.close();
+ } catch (IOException e) { }
+ }
+
+ /*
+ /**********************************************************
+ /* Orphan utility methods
+ /**********************************************************
+ */
+
+ public final static void throwInternal() {
+ throw new RuntimeException("Internal error: this code path should never get executed");
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/package-info.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/package-info.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/core/util/package-info.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,4 @@
+/**
+ * Utility classes used by Jackson Core functionality.
+ */
+package com.fasterxml.jackson.core.util;
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/databind/AbstractTypeResolver.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/databind/AbstractTypeResolver.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/databind/AbstractTypeResolver.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,67 @@
+package com.fasterxml.jackson.databind;
+
+
+/**
+ * Defines interface for resolvers that can resolve abstract types into concrete
+ * ones; either by using static mappings, or possibly by materializing
+ * implementations dynamically.
+ */
+public abstract class AbstractTypeResolver
+{
+ /**
+ * Try to locate a subtype for given abstract type, to either resolve
+ * to a concrete type, or at least to a more-specific (and hopefully supported)
+ * abstract type, one which may have registered deserializers.
+ * Method is called before trying to locate registered deserializers
+ * (as well as standard abstract type defaulting that core Jackson does),
+ * so it is typically implemented to add custom mappings of common abstract
+ * types (like specify which concrete implementation to use for binding
+ * {@link java.util.List}s).
+ *DeserializationConfig
+ */
+ public JavaType findTypeMapping(DeserializationConfig config, JavaType type) {
+ return null;
+ }
+
+ // !!! 29-Nov-2015, tatu: TODO: mark deprecated in 2.8
+ /**
+ * Older variant of {@link #resolveAbstractType(DeserializationConfig, BeanDescription)};
+ * obsoleted in 2.7, to be deprecated in 2.8
+ */
+ public JavaType resolveAbstractType(DeserializationConfig config,
+ JavaType type) {
+ return null;
+ }
+
+ /**
+ * Method called to try to resolve an abstract type into
+ * concrete type (usually for purposes of deserializing),
+ * when no concrete implementation was found.
+ * It will be called after checking all other possibilities,
+ * including defaulting.
+ *DeserializationConfig
+ * @param typeDesc Description of the POJO type to resolve
+ *
+ * @return Resolved concrete type (which should retain generic
+ * type parameters of input type, if any), if resolution succeeds;
+ * null if resolver does not know how to resolve given type
+ *
+ * @since 2.7
+ */
+ public JavaType resolveAbstractType(DeserializationConfig config,
+ BeanDescription typeDesc) {
+ return resolveAbstractType(config, typeDesc.getType());
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/databind/AnnotationIntrospector.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/databind/AnnotationIntrospector.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/databind/AnnotationIntrospector.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,1393 @@
+package com.fasterxml.jackson.databind;
+
+import java.lang.annotation.Annotation;
+import java.util.*;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.core.Versioned;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.cfg.MapperConfig;
+import com.fasterxml.jackson.databind.deser.ValueInstantiator;
+import com.fasterxml.jackson.databind.introspect.*;
+import com.fasterxml.jackson.databind.jsontype.NamedType;
+import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder;
+import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
+import com.fasterxml.jackson.databind.type.MapLikeType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.fasterxml.jackson.databind.util.Converter;
+import com.fasterxml.jackson.databind.util.NameTransformer;
+
+/**
+ * Abstract class that defines API used for introspecting annotation-based
+ * configuration for serialization and deserialization. Separated
+ * so that different sets of annotations can be supported, and support
+ * plugged-in dynamically.
+ *Object.class
)
+ */
+ public Class>[] findViews(Annotated a) { return null; }
+
+ /**
+ * Method for finding format annotations for property or class.
+ * Return value is typically used by serializers and/or
+ * deserializers to customize presentation aspects of the
+ * serialized value.
+ *
+ * @since 2.1
+ */
+ public JsonFormat.Value findFormat(Annotated memberOrClass) { return null; }
+
+ /**
+ * Method used to check if specified property has annotation that indicates
+ * that it should be wrapped in an element; and if so, name to use.
+ * Note that not all serializers and deserializers support use this method:
+ * currently (2.1) it is only used by XML-backed handlers.
+ *
+ * @return Wrapper name to use, if any, or {@link PropertyName#USE_DEFAULT}
+ * to indicate that no wrapper element should be used.
+ *
+ * @since 2.1
+ */
+ public PropertyName findWrapperName(Annotated ann) { return null; }
+
+ /**
+ * Method for finding suggested default value (as simple textual serialization)
+ * for the property. While core databind does not make any use of it, it is exposed
+ * for extension modules to use: an expected use is generation of schema representations
+ * and documentation.
+ *
+ * @since 2.5
+ */
+ public String findPropertyDefaultValue(Annotated ann) { return null; }
+
+ /**
+ * Method used to check whether specified property member (accessor
+ * or mutator) defines human-readable description to use for documentation.
+ * There are no further definitions for contents; for example, whether
+ * these may be marked up using HTML is not defined.
+ *
+ * @return Human-readable description, if any.
+ *
+ * @since 2.3
+ */
+ public String findPropertyDescription(Annotated ann) { return null; }
+
+ /**
+ * Method used to check whether specified property member (accessor
+ * or mutator) defines numeric index, and if so, what is the index value.
+ * Possible use cases for index values included use by underlying data format
+ * (some binary formats mandate use of index instead of name) and ordering
+ * of properties (for documentation, or during serialization).
+ *
+ * @since 2.4
+ *
+ * @return Explicitly specified index for the property, if any
+ */
+ public Integer findPropertyIndex(Annotated ann) { return null; }
+
+ /**
+ * Method for finding implicit name for a property that given annotated
+ * member (field, method, creator parameter) may represent.
+ * This is different from explicit, annotation-based property name, in that
+ * it is "weak" and does not either proof that a property exists (for example,
+ * if visibility is not high enough), or override explicit names.
+ * In practice this method is used to introspect optional names for creator
+ * parameters (which may or may not be available and can not be detected
+ * by standard databind); or to provide alternate name mangling for
+ * fields, getters and/or setters.
+ *
+ * @since 2.4
+ */
+ public String findImplicitPropertyName(AnnotatedMember member) { return null; }
+
+ /**
+ * Method for finding optional access definition for a property, annotated
+ * on one of its accessors. If a definition for read-only, write-only
+ * or read-write cases, visibility rules may be modified. Note, however,
+ * that even more specific annotations (like one for ignoring specific accessor)
+ * may further override behavior of the access definition.
+ *
+ * @since 2.6
+ */
+ public JsonProperty.Access findPropertyAccess(Annotated ann) { return null; }
+
+ /**
+ * Method called in cases where a class has two methods eligible to be used
+ * for the same logical property, and default logic is not enough to figure
+ * out clear precedence. Introspector may try to choose one to use; or, if
+ * unable, return `null` to indicate it can not resolve the problem.
+ *
+ * @since 2.7
+ */
+ public AnnotatedMethod resolveSetterConflict(MapperConfig> config,
+ AnnotatedMethod setter1, AnnotatedMethod setter2) {
+ return null;
+ }
+
+ /*
+ /**********************************************************
+ /* Serialization: general annotations
+ /**********************************************************
+ */
+
+ /**
+ * Method for getting a serializer definition on specified method
+ * or field. Type of definition is either instance (of type
+ * {@link JsonSerializer}) or Class (of type
+ * Class<JsonSerializer>
); if value of different
+ * type is returned, a runtime exception may be thrown by caller.
+ */
+ public Object findSerializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for getting a serializer definition for keys of associated Map
property.
+ * Type of definition is either instance (of type
+ * {@link JsonSerializer}) or Class (of type
+ * Class<JsonSerializer>
); if value of different
+ * type is returned, a runtime exception may be thrown by caller.
+ */
+ public Object findKeySerializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for getting a serializer definition for content (values) of
+ * associated Collection
, array
or Map
property.
+ * Type of definition is either instance (of type
+ * {@link JsonSerializer}) or Class (of type
+ * Class<JsonSerializer>
); if value of different
+ * type is returned, a runtime exception may be thrown by caller.
+ */
+ public Object findContentSerializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for getting a serializer definition for serializer to use
+ * for nulls (null values) of associated property or type.
+ *
+ * @since 2.3
+ */
+ public Object findNullSerializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for accessing declared typing mode annotated (if any).
+ * This is used for type detection, unless more granular settings
+ * (such as actual exact type; or serializer to use which means
+ * no type information is needed) take precedence.
+ *
+ * @return Typing mode to use, if annotation is found; null otherwise
+ */
+ public JsonSerialize.Typing findSerializationTyping(Annotated a) {
+ return null;
+ }
+
+ /**
+ * Method for finding {@link Converter} that annotated entity
+ * (property or class) has indicated to be used as part of
+ * serialization. If not null, either has to be actual
+ * {@link Converter} instance, or class for such converter;
+ * and resulting converter will be used first to convert property
+ * value to converter target type, and then serializer for that
+ * type is used for actual serialization.
+ *Enum
values
+ * have explicitly defined name. Method will overwrite entries in incoming names
+ * array with explicit names found, if any, leaving other entries unmodified.
+ *name()
+ * to give explicit value).
+ *
+ * @since 2.7
+ */
+ public String[] findEnumValues(Class> enumType, Enum>[] enumValues, String[] names) {
+ for (int i = 0, len = enumValues.length; i < len; ++i) {
+ /* 12-Mar-2016, tatu: This is quite tricky, considering that we should NOT
+ * overwrite values with default `name`... so for now, let's only delegate
+ * if no value has been set. Still not optimal but has to do
+ */
+ // TODO: In 2.8, stop delegation?
+ if (names[i] == null) {
+ names[i] = findEnumValue(enumValues[i]);
+ }
+ }
+ return names;
+ }
+
+ /*
+ /**********************************************************
+ /* Deserialization: general annotations
+ /**********************************************************
+ */
+
+ /**
+ * Method for getting a deserializer definition on specified method
+ * or field.
+ * Type of definition is either instance (of type
+ * {@link JsonDeserializer}) or Class (of type
+ * Class<JsonDeserializer>
); if value of different
+ * type is returned, a runtime exception may be thrown by caller.
+ */
+ public Object findDeserializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for getting a deserializer definition for keys of
+ * associated Map
property.
+ * Type of definition is either instance (of type
+ * {@link JsonDeserializer}) or Class (of type
+ * Class<JsonDeserializer>
); if value of different
+ * type is returned, a runtime exception may be thrown by caller.
+ */
+ public Object findKeyDeserializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for getting a deserializer definition for content (values) of
+ * associated Collection
, array
or
+ * Map
property.
+ * Type of definition is either instance (of type
+ * {@link JsonDeserializer}) or Class (of type
+ * Class<JsonDeserializer>
); if value of different
+ * type is returned, a runtime exception may be thrown by caller.
+ */
+ public Object findContentDeserializer(Annotated am) {
+ return null;
+ }
+
+ /**
+ * Method for finding {@link Converter} that annotated entity
+ * (property or class) has indicated to be used as part of
+ * deserialization.
+ * If not null, either has to be actual
+ * {@link Converter} instance, or class for such converter;
+ * and resulting converter will be used after Jackson has deserializer
+ * data into intermediate type (Converter input type), and Converter
+ * needs to convert this into its target type to be set as property value.
+ *
+ * return annotated.getAnnotation(annoClass);
+ *
+ *
+ * @since 2.5
+ */
+ protected A _findAnnotation(Annotated annotated,
+ Class annoClass) {
+ return annotated.getAnnotation(annoClass);
+ }
+
+ /**
+ * Method that should be used by sub-classes for ALL
+ * annotation existence access;
+ * overridable so that sub-classes may, if they choose to, mangle actual access to
+ * block access ("hide" annotations) or perhaps change value seen.
+ *
+ * return annotated.hasAnnotation(annoClass);
+ *
+ *
+ * @since 2.5
+ */
+ protected boolean _hasAnnotation(Annotated annotated, Class extends Annotation> annoClass) {
+ return annotated.hasAnnotation(annoClass);
+ }
+
+ /**
+ * Alternative lookup method that is used to see if annotation has at least one of
+ * annotations of types listed in second argument.
+ *
+ * @since 2.7
+ */
+ protected boolean _hasOneOf(Annotated annotated, Class extends Annotation>[] annoClasses) {
+ return annotated.hasOneOf(annoClasses);
+ }
+}
Index: 3rdParty_sources/jackson/com/fasterxml/jackson/databind/BeanDescription.java
===================================================================
diff -u
--- 3rdParty_sources/jackson/com/fasterxml/jackson/databind/BeanDescription.java (revision 0)
+++ 3rdParty_sources/jackson/com/fasterxml/jackson/databind/BeanDescription.java (revision 38430d27ece1cd540759760d4c30dd4eb29cdd03)
@@ -0,0 +1,262 @@
+package com.fasterxml.jackson.databind;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.fasterxml.jackson.databind.introspect.*;
+import com.fasterxml.jackson.databind.type.TypeBindings;
+import com.fasterxml.jackson.databind.util.Annotations;
+import com.fasterxml.jackson.databind.util.Converter;
+
+/**
+ * Basic container for information gathered by {@link ClassIntrospector} to
+ * help in constructing serializers and deserializers.
+ * Note that the main implementation type is
+ * {@link com.fasterxml.jackson.databind.introspect.BasicBeanDescription},
+ * meaning that it is safe to upcast to this type.
+ */
+public abstract class BeanDescription
+{
+ /*
+ /**********************************************************
+ /* Configuration
+ /**********************************************************
+ */
+
+ /**
+ * Bean type information, including raw class and possible
+ * * generics information
+ */
+ protected final JavaType _type;
+
+ /*
+ /**********************************************************
+ /* Life-cycle
+ /**********************************************************
+ */
+
+ protected BeanDescription(JavaType type) {
+ _type = type;
+ }
+
+ /*
+ /**********************************************************
+ /* Simple accesors
+ /**********************************************************
+ */
+
+ /**
+ * Method for accessing declared type of bean being introspected,
+ * including full generic type information (from declaration)
+ */
+ public JavaType getType() { return _type; }
+
+ public Class> getBeanClass() { return _type.getRawClass(); }
+
+ /**
+ * Method for accessing low-level information about Class this
+ * item describes.
+ */
+ public abstract AnnotatedClass getClassInfo();
+
+ /**
+ * Accessor for getting information about Object Id expected to
+ * be used for this POJO type, if any.
+ */
+ public abstract ObjectIdInfo getObjectIdInfo();
+
+ /**
+ * Method for checking whether class being described has any
+ * annotations recognized by registered annotation introspector.
+ */
+ public abstract boolean hasKnownClassAnnotations();
+
+ /**
+ * Accessor for type bindings that may be needed to fully resolve
+ * types of member object, such as return and argument types of
+ * methods and constructors, and types of fields.
+ *
+ * @deprecated Since 2.7, use {@link #resolveType(java.lang.reflect.Type)} instead.
+ */
+ @Deprecated
+ public abstract TypeBindings bindingsForBeanType();
+
+ /**
+ * Method for resolving given JDK type, using this bean as the
+ * generic type resolution context.
+ */
+ public abstract JavaType resolveType(java.lang.reflect.Type jdkType);
+
+ /**
+ * Method for accessing collection of annotations the bean
+ * class has.
+ */
+ public abstract Annotations getClassAnnotations();
+
+ /*
+ /**********************************************************
+ /* Basic API for finding properties
+ /**********************************************************
+ */
+
+ /**
+ * @return Ordered Map with logical property name as key, and
+ * matching getter method as value.
+ */
+ public abstract List