diff --git a/sdk/serialization/azure-json/spotbugs-exclude.xml b/sdk/serialization/azure-json/spotbugs-exclude.xml index a4a142e7e43c..9b7b2327c77d 100644 --- a/sdk/serialization/azure-json/spotbugs-exclude.xml +++ b/sdk/serialization/azure-json/spotbugs-exclude.xml @@ -2,14 +2,6 @@ - - - - - - - - @@ -21,38 +13,18 @@ + + + + - - - - - - - - - - - - - - - - - - - - - - - - @@ -64,16 +36,4 @@ - - - - - - - - - - - - diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java index 01b715e52b71..42fb5a1ecc38 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonReader.java @@ -19,7 +19,7 @@ * Default {@link JsonReader} implementation. */ public final class DefaultJsonReader extends JsonReader { - private static final JsonFactory FACTORY = JsonFactory.builder().build(); + private static final JsonFactory FACTORY = new JsonFactory(); private final JsonParser parser; private final byte[] jsonBytes; @@ -89,7 +89,7 @@ private DefaultJsonReader(JsonParser parser, boolean resetSupported, byte[] json this.parser = parser; this.resetSupported = resetSupported; this.parser.configure(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS.mappedFeature(), nonNumericNumbersSupported); - this.parser.configure(JsonParser.Feature.ALLOW_COMMENTS, jsoncSupported); + this.parser.configure(JsonReadFeature.ALLOW_JAVA_COMMENTS.mappedFeature(), jsoncSupported); this.jsonBytes = jsonBytes; this.jsonString = jsonString; this.nonNumericNumbersSupported = nonNumericNumbersSupported; diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java index 9b8f16ffec37..d06024740d6e 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/DefaultJsonWriter.java @@ -20,7 +20,7 @@ * Default {@link JsonWriter} implementation. */ public final class DefaultJsonWriter extends JsonWriter { - private static final JsonFactory FACTORY = JsonFactory.builder().build(); + private static final JsonFactory FACTORY = new JsonFactory(); private final JsonGenerator generator; diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variant.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variant.java index 0bf8d8d22258..785f7d162698 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variant.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variant.java @@ -18,44 +18,10 @@ * * @author Tatu Saloranta */ -public final class Base64Variant implements java.io.Serializable { - /** - * Defines how the Base64Variant deals with Padding while reading - * - * @since 2.12 - */ - public enum PaddingReadBehaviour { - /** - * Padding is not allowed in Base64 content being read (finding something - * that looks like padding at the end of content results in an exception) - */ - PADDING_FORBIDDEN, - - /** - * Padding is required in Base64 content being read - * (missing padding for incomplete ending quartet results in an exception) - */ - PADDING_REQUIRED, - - /** - * Padding is allowed but not required in Base64 content being read: no - * exception thrown based on existence or absence, as long as proper - * padding characters are used. - */ - PADDING_ALLOWED - } +public final class Base64Variant { 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 @@ -92,74 +58,20 @@ public enum PaddingReadBehaviour { */ 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. - *

- * Also: must not be private, accessed from `BaseVariants` - */ - final String _name; - - /** - * Character used for padding, if any ({@link #PADDING_CHAR_NONE} if not). - */ - private final char _paddingChar; - - /** - * Maximum number of encoded base64 characters to output during encoding - * before adding a linefeed, if line length is to be limited - * ({@link Integer#MAX_VALUE} if not limited). - *

- * Note: for some output modes (when writing attributes) linefeeds may - * need to be avoided, and this value ignored. - */ - private final int _maxLineLength; - - /** - * Whether this variant uses padding when writing out content or not. - * - * @since 2.12 - */ - private final boolean _writePadding; - - /** - * Whether padding characters should be required or not while decoding - * - * @since 2.12 - */ - private final PaddingReadBehaviour _paddingReadBehaviour; - /* * /********************************************************** * /* Life-cycle * /********************************************************** */ - public Base64Variant(String name, String base64Alphabet, boolean writePadding, char paddingChar, - int maxLineLength) { - _name = name; - _writePadding = writePadding; - _paddingChar = paddingChar; - _maxLineLength = maxLineLength; - + public Base64Variant() { // 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 + ")"); - } + int alphaLen = Base64Variants.STD_BASE64_ALPHABET.length(); // And then secondary encoding table and decoding table: - base64Alphabet.getChars(0, alphaLen, _base64ToAsciiC, 0); + Base64Variants.STD_BASE64_ALPHABET.getChars(0, alphaLen, _base64ToAsciiC, 0); Arrays.fill(_asciiToBase64, BASE64_VALUE_INVALID); for (int i = 0; i < alphaLen; ++i) { char alpha = _base64ToAsciiC[i]; @@ -168,135 +80,7 @@ public Base64Variant(String name, String base64Alphabet, boolean writePadding, c } // Plus if we use padding, add that in too - if (writePadding) { - _asciiToBase64[paddingChar] = BASE64_VALUE_PADDING; - } - - // By default, require padding on input if written on output; do not - // accept if padding not written - _paddingReadBehaviour - = writePadding ? PaddingReadBehaviour.PADDING_REQUIRED : PaddingReadBehaviour.PADDING_FORBIDDEN; - } - - /** - * "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). - * - * @param base Variant to use for settings not specific by other parameters - * @param name Name of this variant - * @param maxLineLength Maximum length (in characters) of lines to output before - * using linefeed - */ - public Base64Variant(Base64Variant base, String name, int maxLineLength) { - this(base, name, base._writePadding, 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 - * - * @param base Variant to use for settings not specific by other parameters - * @param name Name of this variant - * @param writePadding Whether variant will use padding when encoding - * @param paddingChar Padding character used for encoding, excepted on reading, if any - * @param maxLineLength Maximum length (in characters) of lines to output before - * using linefeed - */ - public Base64Variant(Base64Variant base, String name, boolean writePadding, char paddingChar, int maxLineLength) { - this(base, name, writePadding, paddingChar, base._paddingReadBehaviour, maxLineLength); - } - - private Base64Variant(Base64Variant base, String name, boolean writePadding, char paddingChar, - PaddingReadBehaviour paddingReadBehaviour, 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); - - _writePadding = writePadding; - _paddingChar = paddingChar; - _maxLineLength = maxLineLength; - _paddingReadBehaviour = paddingReadBehaviour; - } - - private Base64Variant(Base64Variant base, PaddingReadBehaviour paddingReadBehaviour) { - this(base, base._name, base._writePadding, base._paddingChar, paddingReadBehaviour, base._maxLineLength); - } - - /** - * @return Base64Variant which does not require padding on read - * - * @since 2.12 - */ - public Base64Variant withPaddingAllowed() { - return withReadPadding(PaddingReadBehaviour.PADDING_ALLOWED); - } - - /** - * @return Base64Variant which requires padding on read - * @since 2.12 - */ - public Base64Variant withPaddingRequired() { - return withReadPadding(PaddingReadBehaviour.PADDING_REQUIRED); - } - - /** - * @return Base64Variant which does not accept padding on read - * @since 2.12 - */ - public Base64Variant withPaddingForbidden() { - return withReadPadding(PaddingReadBehaviour.PADDING_FORBIDDEN); - } - - /** - * @param readPadding Padding read behavior desired - * - * @return Instance with desired padding read behavior setting (this - * if already has setting; new instance otherwise) - * - * @since 2.12 - */ - public Base64Variant withReadPadding(PaddingReadBehaviour readPadding) { - return (readPadding == _paddingReadBehaviour) ? this : new Base64Variant(this, readPadding); - } - - /** - * @param writePadding Determines if padding is output on write or not - * - * @return Base64Variant which writes padding or not depending on writePadding - * - * @since 2.12 - */ - public Base64Variant withWritePadding(boolean writePadding) { - return (writePadding == _writePadding) - ? this - : new Base64Variant(this, _name, writePadding, _paddingChar, _maxLineLength); - } - - /* - * /********************************************************** - * /* Serializable overrides - * /********************************************************** - */ - - // 26-Oct-2020, tatu: Much more complicated with 2.12 as it is - // possible to create differently configured instances. - // Need to start with name to regenerate tables etc but then - // handle overrides - private Object readResolve() { - Base64Variant base = Base64Variants.valueOf(_name); - if ((_writePadding != base._writePadding) - || (_paddingChar != base._paddingChar) - || (_paddingReadBehaviour != base._paddingReadBehaviour) - || (_maxLineLength != base._maxLineLength)) { - return new Base64Variant(base, _name, _writePadding, _paddingChar, _paddingReadBehaviour, _maxLineLength); - } - return base; + _asciiToBase64['='] = BASE64_VALUE_PADDING; } /* @@ -305,50 +89,8 @@ private Object readResolve() { * /********************************************************** */ - public String getName() { - return _name; - } - - /** - * @return True if this Base64 encoding will write padding on output - * (note: before Jackson 2.12 also dictated whether padding was accepted on read) - */ - public boolean usesPadding() { - return _writePadding; - } - - /** - * @return {@code True} if this variant requires padding on content decoded; {@code false} if not. - * - * @since 2.12 - */ - public boolean requiresPaddingOnRead() { - return _paddingReadBehaviour == PaddingReadBehaviour.PADDING_REQUIRED; - } - - /** - * @return {@code True} if this variant accepts padding on content decoded; {@code false} if not. - * - * @since 2.12 - */ - public boolean acceptsPaddingOnRead() { - return _paddingReadBehaviour != PaddingReadBehaviour.PADDING_FORBIDDEN; - } - - public boolean usesPaddingChar(char c) { - return c == _paddingChar; - } - - public boolean usesPaddingChar(int ch) { - return ch == (int) _paddingChar; - } - - public char getPaddingChar() { - return _paddingChar; - } - public int getMaxLineLength() { - return _maxLineLength; + return Integer.MAX_VALUE; } /* @@ -412,14 +154,8 @@ public int encodeBase64Chunk(int b24, char[] buffer, int outPtr) { 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]; - } - } + buffer[outPtr++] = (outputBytes == 2) ? _base64ToAsciiC[(bits >> 6) & 0x3F] : '='; + buffer[outPtr++] = '='; return outPtr; } @@ -457,15 +193,9 @@ public int encodeBase64Chunk(int b24, byte[] buffer, int outPtr) { 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]; - } - } + byte pb = (byte) '='; + buffer[outPtr++] = (outputBytes == 2) ? _base64ToAsciiB[(bits >> 6) & 0x3F] : pb; + buffer[outPtr++] = pb; return outPtr; } @@ -475,25 +205,6 @@ public int encodeBase64Partial(int bits, int outputBytes, byte[] buffer, int out * /********************************************************** */ - /** - * Convenience method for decoding contents of a Base64-encoded String, - * using this variant's settings. - * - * @param input Base64-encoded input String to decode - * - * @return Byte array of decoded contents - * - * @since 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 @@ -530,7 +241,7 @@ public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentE int decodedData = bits; // then second base64 char; can't get padding yet, nor ws if (ptr >= len) { - _reportBase64EOF(); + throw new IllegalArgumentException(missingPaddingMessage()); } ch = str.charAt(ptr++); bits = decodeBase64Char(ch); @@ -541,12 +252,7 @@ public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentE // third base64 char; can be padding, but not ws if (ptr >= len) { // but as per [JACKSON-631] can be end-of-input, iff padding is not required - if (!requiresPaddingOnRead()) { - decodedData >>= 4; - builder.append(decodedData); - break; - } - _reportBase64EOF(); + throw new IllegalArgumentException(missingPaddingMessage()); } ch = str.charAt(ptr++); bits = decodeBase64Char(ch); @@ -556,16 +262,13 @@ public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentE if (bits != Base64Variant.BASE64_VALUE_PADDING) { _reportInvalidBase64(ch, 2, null); } - if (!acceptsPaddingOnRead()) { - _reportBase64UnexpectedPadding(); - } // Ok, must get padding if (ptr >= len) { - _reportBase64EOF(); + throw new IllegalArgumentException(missingPaddingMessage()); } ch = str.charAt(ptr++); - if (!usesPaddingChar(ch)) { - _reportInvalidBase64(ch, 3, "expected padding character '" + getPaddingChar() + "'"); + if (ch != '=') { + _reportInvalidBase64(ch, 3, "expected padding character '='"); } // Got 12 bits, only need 8, need to shift decodedData >>= 4; @@ -577,12 +280,7 @@ public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentE // 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 padding on read is not required - if (!requiresPaddingOnRead()) { - decodedData >>= 2; - builder.appendTwoBytes(decodedData); - break; - } - _reportBase64EOF(); + throw new IllegalArgumentException(missingPaddingMessage()); } ch = str.charAt(ptr++); bits = decodeBase64Char(ch); @@ -590,9 +288,6 @@ public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentE if (bits != Base64Variant.BASE64_VALUE_PADDING) { _reportInvalidBase64(ch, 3, null); } - if (!acceptsPaddingOnRead()) { - _reportBase64UnexpectedPadding(); - } decodedData >>= 2; builder.appendTwoBytes(decodedData); } else { @@ -611,7 +306,7 @@ public void decode(String str, ByteArrayBuilder builder) throws IllegalArgumentE @Override public String toString() { - return _name; + return "MIME-NO-LINEFEEDS"; } @Override @@ -620,20 +315,12 @@ public boolean equals(Object o) { // 26-Oct-2020, tatu: ... not any more with 2.12 if (o == this) return true; - if (o == null || o.getClass() != getClass()) - return false; - - Base64Variant other = (Base64Variant) o; - return (other._paddingChar == _paddingChar) - && (other._maxLineLength == _maxLineLength) - && (other._writePadding == _writePadding) - && (other._paddingReadBehaviour == _paddingReadBehaviour) - && (_name.equals(other._name)); + return o != null && o.getClass() == getClass(); } @Override public int hashCode() { - return _name.hashCode(); + return "MIME-NO-LINEFEEDS".hashCode(); } /* @@ -653,8 +340,8 @@ private void _reportInvalidBase64(char ch, int bindex, String msg) throws Illega 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) + } else if (ch == '=') { + base = "Unexpected padding character ('=') 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) @@ -668,28 +355,6 @@ private void _reportInvalidBase64(char ch, int bindex, String msg) throws Illega throw new IllegalArgumentException(base); } - private void _reportBase64EOF() throws IllegalArgumentException { - throw new IllegalArgumentException(missingPaddingMessage()); - } - - private void _reportBase64UnexpectedPadding() throws IllegalArgumentException { - throw new IllegalArgumentException(unexpectedPaddingMessage()); - } - - /** - * Helper method that will construct a message to use in exceptions for cases where input ends - * prematurely in place where padding is not expected. - * - * @return Exception message for indicating "unexpected padding" case - * - * @since 2.12 - */ - private String unexpectedPaddingMessage() { - return String.format( - "Unexpected end of base64-encoded String: base64 variant '%s' expects no padding at the end while decoding. This Base64Variant might have been incorrectly configured", - getName()); - } - /** * Helper method that will construct a message to use in exceptions for cases where input ends * prematurely in place where padding would be expected. @@ -698,9 +363,8 @@ private String unexpectedPaddingMessage() { * * @since 2.10 */ - public String missingPaddingMessage() { // !!! TODO: why is this 'public'? - return String.format( - "Unexpected end of base64-encoded String: base64 variant '%s' expects padding (one or more '%c' characters) at the end. This Base64Variant might have been incorrectly configured", - getName(), getPaddingChar()); + public static String missingPaddingMessage() { // !!! TODO: why is this 'public'? + return "Unexpected end of base64-encoded String: base64 variant 'MIME-NO-LINEFEEDS' expects padding " + + "(one or more '=' characters) at the end. This Base64Variant might have been incorrectly configured"; } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variants.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variants.java index bbb38e9b20d6..4acc76a2a282 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variants.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Base64Variants.java @@ -9,26 +9,13 @@ /** * Container for commonly used Base64 variants: *

* See entries for full description of differences. *

* Note that for default {@link Base64Variant} instances listed above, configuration * is such that if padding is written on output, it will also be required on - * reading. This behavior may be changed by using methods: - *

+ * reading. * * @author Tatu Saloranta */ @@ -36,66 +23,14 @@ public final class Base64Variants { final static String STD_BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** - * This variant is what most people would think of "the standard" - * Base64 encoding. - *

- * 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 instead used because of JSON requirement of escaping all linefeeds. - *

- * Writes padding on output; requires padding when reading (may change later with a call to {@link Base64Variant#withWritePadding}) - */ - 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 + * Slightly non-standard modification of {@code 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). *

- * Writes padding on output; requires padding when reading (may change later with a call to {@link Base64Variant#withWritePadding}) - */ - 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. - *

- * Writes padding on output; requires padding when reading (may change later with a call to {@link Base64Variant#withWritePadding}) + * Writes padding on output; requires padding when reading */ - 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). - *

- * Does not write padding on output; does not accept padding when reading (may change later with a call to {@link Base64Variant#withWritePadding}) - */ - 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); - } + public final static Base64Variant MIME_NO_LINEFEEDS = new Base64Variant(); /** * Method used to get the default variant -- {@link #MIME_NO_LINEFEEDS} -- for cases @@ -108,36 +43,4 @@ public final class Base64Variants { public static Base64Variant getDefaultVariant() { return MIME_NO_LINEFEEDS; } - - /** - * Lookup method for finding one of standard variants by name. - * If name does not match any of standard variant names, - * a {@link IllegalArgumentException} is thrown. - * - * @param name Name of base64 variant to return - * - * @return Standard base64 variant that matches given {@code name} - * - * @throws IllegalArgumentException if no standard variant with given name exists - */ - 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 = ""; - } else { - name = "'" + name + "'"; - } - throw new IllegalArgumentException("No Base64Variant with name " + name); - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/FormatFeature.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/FormatFeature.java deleted file mode 100644 index 03a7bc6e1498..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/FormatFeature.java +++ /dev/null @@ -1,37 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import com.azure.json.implementation.jackson.core.util.JacksonFeature; - -/** - * Marker interface that is to be implemented by data format - specific features. - * Interface used since Java Enums can not extend classes or other Enums, but - * they can implement interfaces; and as such we may be able to use limited - * amount of generic functionality. - *

- * Since 2.12 this is more of an extra marker feature, as its core API is now - * defined in more general {@link JacksonFeature}. - * - * @since 2.6 - */ -public interface FormatFeature extends JacksonFeature // since 2.12 -{ - /** - * Accessor for checking whether this feature is enabled by default. - */ - @Override - boolean enabledByDefault(); - - /** - * Returns bit mask for this feature instance; must be a single bit, - * that is of form (1 << N) - */ - @Override - int getMask(); - - /** - * Convenience method for checking whether feature is enabled in given bitmask - */ - @Override - boolean enabledIn(int flags); -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/FormatSchema.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/FormatSchema.java deleted file mode 100644 index 9532cec79297..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/FormatSchema.java +++ /dev/null @@ -1,38 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/* - * Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - */ - -package com.azure.json.implementation.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. - * Others like CSV and Java Properties may optionally use schemas (and/or use simple - * default schema to use if caller does not specify one) which specifies - * some aspects of structuring content. - *

- * 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 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. - * - * @return Logical name of schema type - */ - String getSchemaType(); -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JacksonException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JacksonException.java index c26b52dc6c7b..ca43e8cde238 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JacksonException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JacksonException.java @@ -14,20 +14,8 @@ public abstract class JacksonException extends java.io.IOException { private final static long serialVersionUID = 123; // eclipse complains otherwise - protected JacksonException(String msg) { - super(msg); - } - protected JacksonException(String msg, Throwable rootCause) { super(msg, rootCause); - // 23-Sep-2020, tatu: before 2.12, had null checks for some reason... - // But I don't think that is actually required; Javadocs for - // `java.lang.Throwable` constructor claim {@code null} is fine. - /* - * if (rootCause != null) { - * initCause(rootCause); - * } - */ } /* @@ -48,20 +36,4 @@ protected JacksonException(String msg, Throwable rootCause) { * available; {@code null} otherwise. */ public abstract JsonLocation getLocation(); - - /** - * Method that allows accessing underlying processor that triggered - * this exception; typically either {@link JsonParser} or {@link JsonGenerator} - * for exceptions that originate from streaming API, but may be other types - * when thrown by databinding. - *

- * Note that it is possible that {@code null} may be returned if code throwing - * exception either has no access to the 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; {@code null} if not. - */ - public abstract Object getProcessor(); } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactory.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactory.java index 6dcee79cfae8..8a315b85fd45 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactory.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactory.java @@ -6,16 +6,10 @@ */ package com.azure.json.implementation.jackson.core; -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; import com.azure.json.implementation.jackson.core.io.ContentReference; import com.azure.json.implementation.jackson.core.io.IOContext; -import com.azure.json.implementation.jackson.core.io.InputDecorator; -import com.azure.json.implementation.jackson.core.io.OutputDecorator; -import com.azure.json.implementation.jackson.core.io.SerializedString; import com.azure.json.implementation.jackson.core.io.UTF8Writer; import com.azure.json.implementation.jackson.core.json.ByteSourceJsonBootstrapper; -import com.azure.json.implementation.jackson.core.json.JsonWriteFeature; -import com.azure.json.implementation.jackson.core.json.PackageVersion; import com.azure.json.implementation.jackson.core.json.ReaderBasedJsonParser; import com.azure.json.implementation.jackson.core.json.UTF8JsonGenerator; import com.azure.json.implementation.jackson.core.json.WriterBasedJsonGenerator; @@ -23,20 +17,13 @@ import com.azure.json.implementation.jackson.core.sym.CharsToNameCanonicalizer; import com.azure.json.implementation.jackson.core.util.BufferRecycler; import com.azure.json.implementation.jackson.core.util.BufferRecyclers; -import com.azure.json.implementation.jackson.core.util.JacksonFeature; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; -import java.io.Serializable; -import java.io.StringReader; import java.io.Writer; -import java.lang.ref.SoftReference; -import java.net.URL; /** * The main factory class of Jackson package, used to configure and @@ -58,1095 +45,72 @@ * * @author Tatu Saloranta */ -@SuppressWarnings("resource") -public class JsonFactory extends TokenStreamFactory implements Versioned, Serializable // since 2.1 (for - // Android, mostly) -{ - private static final long serialVersionUID = 2; - - /* - * /********************************************************** - * /* Helper types - * /********************************************************** - */ - - /** - * Enumeration that defines all on/off features that can only be - * changed for {@link JsonFactory}. - */ - public enum Feature implements JacksonFeature // since 2.12 - { - // // // 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 intern()ing) is disabled) as protective - * measure. - *

- * 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 - * jackson-core#189 - * for a possible case) - *

- * This setting is enabled by default. - * - * @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. - * - * @return Bit field of features enabled by default - */ - public static int collectDefaults() { - int flags = 0; - for (Feature f : values()) { - if (f.enabledByDefault()) { - flags |= f.getMask(); - } - } - return flags; - } - - Feature(boolean defaultState) { - _defaultState = defaultState; - } - - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & getMask()) != 0; - } - - @Override - 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 = 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(); - - public final static SerializableString DEFAULT_ROOT_VALUE_SEPARATOR = new SerializedString(" "); - - /** - * @since 2.10 - */ - public final static char DEFAULT_QUOTE_CHAR = '"'; +public class JsonFactory { /* * /********************************************************** * /* Buffer, symbol table management - * /********************************************************** - */ - - /** - * Each factory comes equipped with a shared root symbol table. - * It should not be linked back to the original blueprint, to - * avoid contents from leaking between factories. - */ - protected final transient CharsToNameCanonicalizer _rootCharSymbols = CharsToNameCanonicalizer.createRoot(); - - /** - * Alternative to the basic symbol table, some stream-based - * parsers use different name canonicalization method. - *

- * TODO: should clean up this; looks messy having 2 alternatives - * with not very clear differences. - * - * @since 2.6 - */ - protected final transient ByteQuadsCanonicalizer _byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot(); - - /* - * /********************************************************** - * /* Configuration, simple feature flags - * /********************************************************** - */ - - /** - * 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; - - /* - * /********************************************************** - * /* Configuration, helper objects - * /********************************************************** - */ - - /** - * 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; - - /** - * 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; - - /** - * Optional threshold used for automatically escaping character above certain character - * code value: either {@code 0} to indicate that no threshold is specified, or value - * at or above 127 to indicate last character code that is NOT automatically escaped - * (but depends on other configuration rules for checking). - * - * @since 2.10 - */ - protected int _maximumNonEscapedChar; - - /** - * Character used for quoting field names (if field name quoting has not - * been disabled with {@link JsonWriteFeature#QUOTE_FIELD_NAMES}) - * and JSON String values. - */ - protected final char _quoteChar; - - /* - * /********************************************************** - * /* 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((ObjectCodec) null); - } - - public JsonFactory(ObjectCodec oc) { - _objectCodec = oc; - _quoteChar = DEFAULT_QUOTE_CHAR; - } - - /** - * Constructor used when copy()ing a factory instance. - * - * @param src Original factory to copy settings from - * @param codec Databinding-level codec to use, if any - * - * @since 2.2.1 - */ - protected JsonFactory(JsonFactory src, ObjectCodec codec) { - _objectCodec = codec; - - // General - _factoryFeatures = src._factoryFeatures; - _parserFeatures = src._parserFeatures; - _generatorFeatures = src._generatorFeatures; - _inputDecorator = src._inputDecorator; - _outputDecorator = src._outputDecorator; - - // JSON-specific - _characterEscapes = src._characterEscapes; - _rootValueSeparator = src._rootValueSeparator; - _maximumNonEscapedChar = src._maximumNonEscapedChar; - _quoteChar = src._quoteChar; - } - - /** - * Constructor used by {@link JsonFactoryBuilder} for instantiation. - * - * @param b Builder that contains settings to use - * - * @since 2.10 - */ - public JsonFactory(JsonFactoryBuilder b) { - _objectCodec = null; - - // General - _factoryFeatures = b._factoryFeatures; - _parserFeatures = b._streamReadFeatures; - _generatorFeatures = b._streamWriteFeatures; - _inputDecorator = b._inputDecorator; - _outputDecorator = b._outputDecorator; - - // JSON-specific - _characterEscapes = b._characterEscapes; - _rootValueSeparator = b._rootValueSeparator; - _maximumNonEscapedChar = b._maximumNonEscapedChar; - _quoteChar = b._quoteChar; - } - - /** - * Constructor for subtypes; needed to work around the fact that before 3.0, - * this factory has cumbersome dual role as generic type as well as actual - * implementation for json. - * - * @param b Builder that contains settings to use - * @param bogus Argument only needed to separate constructor signature; ignored - */ - protected JsonFactory(TSFBuilder b, boolean bogus) { - _objectCodec = null; - - _factoryFeatures = b._factoryFeatures; - _parserFeatures = b._streamReadFeatures; - _generatorFeatures = b._streamWriteFeatures; - _inputDecorator = b._inputDecorator; - _outputDecorator = b._outputDecorator; - - // JSON-specific: need to assign even if not really used - _characterEscapes = null; - _rootValueSeparator = null; - _maximumNonEscapedChar = 0; - _quoteChar = DEFAULT_QUOTE_CHAR; - } - - /** - * Main factory method to use for constructing {@link JsonFactory} instances with - * different configuration: creates and returns a builder for collecting configuration - * settings; instance created by calling {@code build()} after all configuration - * set. - *

- * NOTE: signature unfortunately does not expose true implementation type; this - * will be fixed in 3.0. - * - * @return Builder instance to use - */ - public static TSFBuilder builder() { - return new JsonFactoryBuilder(); - } - - /** - * 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. - * - * @return Copy of this factory instance - * - * @since 2.1 - */ - public JsonFactory copy() { - _checkInvalidCopy(JsonFactory.class); - // as per above, do clear ObjectCodec - return new JsonFactory(this, null); - } - - 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: needed to allow JDK serializability of - * factory instances. - *

- * Note: must be overridden by sub-classes as well. - * - * @return Newly constructed instance - */ - protected Object readResolve() { - return new JsonFactory(this, _objectCodec); - } - - /* - * /********************************************************** - * /* Capability introspection - * /********************************************************** - */ - - /** - * 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. - *

- * Default implementation returns 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. - * - * @return Whether format supported by this factory - * supports native binary content - * - * @since 2.3 - */ - @Override - 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 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 String} content by first copying it into - * recyclable intermediate buffer. - * - * @return Whether access to decoded textual content can be efficiently - * accessed using parser method {@code getTextCharacters()}. - * - * @since 2.4 - */ - public boolean canUseCharArrays() { - return true; - } - - /* - * /********************************************************** - * /* Format detection functionality - * /********************************************************** - */ - - /** - * Method that returns short textual id identifying format - * this factory supports. - *

- * Note: sub-classes should override this method; default - * implementation will return null for all sub-classes - * - * @return Name of the format handled by parsers, generators this factory creates - */ - @Override - 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; - } - - /* - * /********************************************************** - * /* 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) - * - * @param f Feature to enable/disable - * @param state Whether to enable or disable the feature - * - * @return This factory instance (to allow call chaining) - * - * @deprecated since 2.10 use {@link JsonFactoryBuilder#configure(Feature, boolean)} instead - */ - @Deprecated - public final JsonFactory configure(Feature f, boolean state) { - return state ? enable(f) : disable(f); - } - - /** - * Method for enabling specified parser feature - * (check {@link Feature} for list of features) - * - * @param f Feature to enable - * - * @return This factory instance (to allow call chaining) - * - * @deprecated since 2.10 use {@link JsonFactoryBuilder#configure(Feature, boolean)} instead - */ - @Deprecated - public JsonFactory enable(Feature f) { - _factoryFeatures |= f.getMask(); - return this; - } - - /** - * Method for disabling specified parser features - * (check {@link Feature} for list of features) - * - * @param f Feature to disable - * - * @return This factory instance (to allow call chaining) - * - * @deprecated since 2.10 use {@link JsonFactoryBuilder#configure(Feature, boolean)} instead - */ - @Deprecated - public JsonFactory disable(Feature f) { - _factoryFeatures &= ~f.getMask(); - return this; - } - - /** - * Checked whether specified parser feature is enabled. - * - * @param f Feature to check - * - * @return True if the specified feature is enabled - */ - public final boolean isEnabled(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) - * - * @param f Feature to enable/disable - * @param state Whether to enable or disable the feature - * - * @return This factory instance (to allow call chaining) - */ - 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) - * - * @param f Feature to enable - * - * @return This factory instance (to allow call chaining) - */ - 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) - * - * @param f Feature to disable - * - * @return This factory instance (to allow call chaining) - */ - public JsonFactory disable(JsonParser.Feature f) { - _parserFeatures &= ~f.getMask(); - return this; - } - - /** - * Method for checking if the specified parser feature is enabled. - * - * @param f Feature to check - * - * @return True if specified feature is enabled - */ - @Override - public final boolean isEnabled(JsonParser.Feature f) { - return (_parserFeatures & f.getMask()) != 0; - } - - /** - * Method for checking if the specified stream read feature is enabled. - * - * @param f Feature to check - * - * @return True if specified feature is enabled - * - * @since 2.10 - */ - public final boolean isEnabled(StreamReadFeature f) { - return (_parserFeatures & f.mappedFeature().getMask()) != 0; - } - - /** - * Method for overriding currently configured input decorator - * - * @param d Decorator to configure for this factory, if any ({@code null} if none) - * - * @return This factory instance (to allow call chaining) - * - * @deprecated Since 2.10 use {@link JsonFactoryBuilder#inputDecorator(InputDecorator)} instead - */ - @Deprecated - 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) - * - * @param f Feature to enable/disable - * @param state Whether to enable or disable the feature - * - * @return This factory instance (to allow call chaining) - */ - 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) - * - * @param f Feature to enable - * - * @return This factory instance (to allow call chaining) - */ - 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) - * - * @param f Feature to disable - * - * @return This factory instance (to allow call chaining) - */ - public JsonFactory disable(JsonGenerator.Feature f) { - _generatorFeatures &= ~f.getMask(); - return this; - } - - /** - * Check whether specified generator feature is enabled. - * - * @param f Feature to check - * - * @return Whether specified feature is enabled - */ - @Override - public final boolean isEnabled(JsonGenerator.Feature f) { - return (_generatorFeatures & f.getMask()) != 0; - } - - /** - * Check whether specified stream write feature is enabled. - * - * @param f Feature to check - * - * @return Whether specified feature is enabled - * - * @since 2.10 - */ - public final boolean isEnabled(StreamWriteFeature f) { - return (_generatorFeatures & f.mappedFeature().getMask()) != 0; - } - - /** - * Method for overriding currently configured output decorator - * - * @return This factory instance (to allow call chaining) - * - * @param d Output decorator to use, if any - * - * @deprecated Since 2.10 use {@link JsonFactoryBuilder#outputDecorator(OutputDecorator)} instead - */ - @Deprecated - public JsonFactory setOutputDecorator(OutputDecorator d) { - _outputDecorator = d; - return this; - } - - /* - * /********************************************************** - * /* Configuration, other - * /********************************************************** - */ - - /** - * Method for associating a {@link ObjectCodec} (typically - * a 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. - * - * @param oc Codec to use - * - * @return This factory instance (to allow call chaining) - */ - public JsonFactory setCodec(ObjectCodec oc) { - _objectCodec = oc; - return this; - } - - public ObjectCodec getCodec() { - return _objectCodec; - } - - /* - * /********************************************************** - * /* Parser factories, traditional (blocking) I/O sources - * /********************************************************** - */ - - /** - * 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(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 - */ - @Override - public JsonParser createParser(File f) throws IOException { - // true, since we create InputStream from File - IOContext ctxt = _createContext(_createContentReference(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(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 - */ - @Override - public JsonParser createParser(URL url) throws IOException { - // true, since we create InputStream from URL - IOContext ctxt = _createContext(_createContentReference(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 StreamReadFeature#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(Reader)}. - * - * @param in InputStream to use for reading JSON content to parse - * - * @since 2.1 - */ - @Override - public JsonParser createParser(InputStream in) throws IOException { - IOContext ctxt = _createContext(_createContentReference(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 StreamReadFeature#AUTO_CLOSE_SOURCE} - * is enabled. - * - * @param r Reader to use for reading JSON content to parse - * - * @since 2.1 - */ - @Override - public JsonParser createParser(Reader r) throws IOException { - // false -> we do NOT own Reader (did not create it) - IOContext ctxt = _createContext(_createContentReference(r), false); - return _createParser(_decorate(r, ctxt), ctxt); - } - - /** - * Method for constructing parser for parsing - * the contents of given byte array. - * - * @since 2.1 - */ - @Override - public JsonParser createParser(byte[] data) throws IOException { - IOContext ctxt = _createContext(_createContentReference(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 - */ - @Override - public JsonParser createParser(byte[] data, int offset, int len) throws IOException { - IOContext ctxt = _createContext(_createContentReference(data, offset, len), 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 - */ - @Override - public JsonParser createParser(String content) throws IOException { - 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(_createContentReference(content), true); - char[] buf = ctxt.allocTokenBuffer(strLen); - content.getChars(0, strLen, buf, 0); - return _createParser(buf, 0, strLen, ctxt, true); - } - - /* - * /********************************************************** - * /* Parser factories, non-blocking (async) sources - * /********************************************************** - */ - - /* - * /********************************************************** - * /* Generator factories - * /********************************************************** - */ - - /** - * 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 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 - */ - @Override - public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { - // false -> we won't manage the stream unless explicitly directed to - IOContext ctxt = _createContext(_createContentReference(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 + * Each factory comes equipped with a shared root symbol table. + * It should not be linked back to the original blueprint, to + * avoid contents from leaking between factories. */ - @Override - public JsonGenerator createGenerator(OutputStream out) throws IOException { - return createGenerator(out, JsonEncoding.UTF8); - } + protected final transient CharsToNameCanonicalizer _rootCharSymbols = CharsToNameCanonicalizer.createRoot(); /** - * Method for constructing JSON generator for writing JSON content - * using specified Writer. + * Alternative to the basic symbol table, some stream-based + * parsers use different name canonicalization method. *

- * 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 JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). - * Using application needs to close it explicitly. - * - * @since 2.1 + * TODO: should clean up this; looks messy having 2 alternatives + * with not very clear differences. * - * @param w Writer to use for writing JSON content + * @since 2.6 */ - @Override - public JsonGenerator createGenerator(Writer w) throws IOException { - IOContext ctxt = _createContext(_createContentReference(w), false); - return _createGenerator(_decorate(w, ctxt), ctxt); - } + protected final transient ByteQuadsCanonicalizer _byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot(); /* * /********************************************************** - * /* Deprecated parser factory methods: to be removed from 3.x + * /* Configuration, simple feature flags * /********************************************************** */ /** - * 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(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 - * - * @return Parser constructed - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(File)} instead. + * Currently enabled parser features. */ - @Deprecated - public JsonParser createJsonParser(File f) throws IOException { - return createParser(f); - } + private static final int _parserFeatures = JsonParser.Feature.collectDefaults(); /** - * 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(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 - * - * @return Parser constructed + * Currently enabled generator features. + */ + private static final int _generatorFeatures = JsonGenerator.Feature.collectDefaults(); + + /* + * /********************************************************** + * /* Construction + * /********************************************************** + */ + + /** + * Constructor used when copy()ing a factory instance. * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(URL)} instead. + * @since 2.2.1 */ - @Deprecated - public JsonParser createJsonParser(URL url) throws IOException { - return createParser(url); + public JsonFactory() { } + /* + * /********************************************************** + * /* Parser factories, traditional (blocking) I/O sources + * /********************************************************** + */ + /** * 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 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 @@ -1156,90 +120,58 @@ public JsonParser createJsonParser(URL url) throws IOException { * * @param in InputStream to use for reading JSON content to parse * - * @return Parser constructed - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(InputStream)} instead. + * @since 2.1 */ - @Deprecated - public JsonParser createJsonParser(InputStream in) throws IOException { - return createParser(in); + public JsonParser createParser(InputStream in) throws IOException { + return new ByteSourceJsonBootstrapper(_createContext(ContentReference.construct(in), false), in) + .constructParser(_parserFeatures, _byteSymbolCanonicalizer, _rootCharSymbols); } /** * 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 JsonParser.Feature#AUTO_CLOSE_SOURCE} - * is enabled. * * @param r Reader to use for reading JSON content to parse * - * @return Parser constructed - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(Reader)} instead. - */ - @Deprecated - public JsonParser createJsonParser(Reader r) throws IOException { - return createParser(r); - } - - /** - * Method for constructing parser for parsing the contents of given byte array. - * - * @param data Input content to parse - * - * @return Parser constructed - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(byte[])} instead. + * @since 2.1 */ - @Deprecated - public JsonParser createJsonParser(byte[] data) throws IOException { - return createParser(data); + public JsonParser createParser(Reader r) { + // false -> we do NOT own Reader (did not create it) + return new ReaderBasedJsonParser(_createContext(ContentReference.construct(r), false), _parserFeatures, r, + _rootCharSymbols.makeChild()); } /** * 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 - * - * @return Parser constructed - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(byte[],int,int)} instead. + * @since 2.1 */ - @Deprecated - public JsonParser createJsonParser(byte[] data, int offset, int len) throws IOException { - return createParser(data, offset, len); + public JsonParser createParser(byte[] data) throws IOException { + IOContext ctxt = _createContext(ContentReference.construct(data), true); + return new ByteSourceJsonBootstrapper(ctxt, data, 0, data.length).constructParser(_parserFeatures, + _byteSymbolCanonicalizer, _rootCharSymbols); } /** * Method for constructing parser for parsing * contents of given String. * - * @param content Input content to parse - * - * @return Parser constructed - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * @deprecated Since 2.2, use {@link #createParser(String)} instead. + * @since 2.1 */ - @Deprecated - public JsonParser createJsonParser(String content) throws IOException { - return createParser(content); + public JsonParser createParser(String content) { + final int strLen = content.length(); + // Actually, let's use this for medium-sized content, up to 64kB chunk (32kb char) + IOContext ctxt = _createContext(ContentReference.construct(content), true); + char[] buf = ctxt.allocTokenBuffer(strLen); + content.getChars(0, strLen, buf, 0); + return new ReaderBasedJsonParser(ctxt, _parserFeatures, null, _rootCharSymbols.makeChild(), buf, 0, strLen, + true); } /* * /********************************************************** - * /* Deprecated generator factory methods: to be removed from 3.x + * /* Generator factories * /********************************************************** */ @@ -1263,39 +195,17 @@ public JsonParser createJsonParser(String content) throws IOException { * @param out OutputStream to use for writing JSON content * @param enc Character encoding to use * - * @return Generator constructed - * - * @throws IOException if parser initialization fails due to I/O (write) problem - * - * @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 JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). - * Using application needs to close it explicitly. - * - * @param out Writer to use for writing JSON content - * - * @return Generator constructed - * - * @throws IOException if parser initialization fails due to I/O (write) problem - * - * @deprecated Since 2.2, use {@link #createGenerator(Writer)} instead. + * @since 2.1 */ - @Deprecated - public JsonGenerator createJsonGenerator(Writer out) throws IOException { - return createGenerator(out); + public JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { + // false -> we won't manage the stream unless explicitly directed to + IOContext ctxt = _createContext(ContentReference.construct(out), false); + ctxt.setEncoding(enc); + if (enc == JsonEncoding.UTF8) { + return new UTF8JsonGenerator(ctxt, _generatorFeatures, out); + } + Writer w = _createWriter(out, enc, ctxt); + return _createGenerator(w, ctxt); } /** @@ -1304,115 +214,29 @@ public JsonGenerator createJsonGenerator(Writer out) throws IOException { *

* Note: there are formats that use fixed encoding (like most binary data formats). * - * @param out OutputStream to use for writing JSON content - * - * @return Generator constructed - * - * @throws IOException if parser initialization fails due to I/O (write) problem - * - * @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. - * - * @param in InputStream to use for reading content to parse - * @param ctxt I/O context to use for parsing - * - * @throws IOException if parser initialization fails due to I/O (read) problem - * - * @return Parser constructed - * * @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); + public JsonGenerator createGenerator(OutputStream out) throws IOException { + return createGenerator(out, JsonEncoding.UTF8); } /** - * Overridable factory method that actually instantiates parser - * using given {@link Reader} object for reading content. + * Method for constructing JSON generator for writing JSON content + * using specified Writer. *

- * 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. - * - * @param r Reader to use for reading content to parse - * @param ctxt I/O context to use for parsing - * - * @return Actual parser to use + * 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 JsonGenerator.Feature#AUTO_CLOSE_TARGET} is enabled). + * Using application needs to close it explicitly. * * @since 2.1 - */ - protected JsonParser _createParser(Reader r, IOContext ctxt) { - return new ReaderBasedJsonParser(ctxt, _parserFeatures, r, _objectCodec, - _rootCharSymbols.makeChild(_factoryFeatures)); - } - - /** - * Overridable factory method that actually instantiates parser - * using given char[] object for accessing content. - * - * @param data Buffer that contains content to parse - * @param offset Offset to the first character of data to parse - * @param len Number of characters within buffer to parse - * @param ctxt I/O context to use for parsing - * @param recyclable Whether input buffer is recycled by the factory - * - * @return Actual parser to use - * - * @since 2.4 - */ - protected JsonParser _createParser(char[] data, int offset, int len, IOContext ctxt, boolean recyclable) { - 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. - *

- * 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. * - * @param data Buffer that contains content to parse - * @param offset Offset to the first character of data to parse - * @param len Number of characters within buffer to parse - * @param ctxt I/O context to use for parsing - * - * @return Actual parser to use - * - * @throws IOException if parser initialization fails due to I/O (read) problem + * @param w Writer to use for writing JSON content */ - 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); + public JsonGenerator createGenerator(Writer w) { + return _createGenerator(w, _createContext(ContentReference.construct(w), false)); } /* @@ -1439,50 +263,7 @@ protected JsonParser _createParser(byte[] data, int offset, int len, IOContext c * */ protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) { - WriterBasedJsonGenerator gen - = new WriterBasedJsonGenerator(ctxt, _generatorFeatures, _objectCodec, out, _quoteChar); - if (_maximumNonEscapedChar > 0) { - gen.setHighestNonEscapedChar(_maximumNonEscapedChar); - } - 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. - * - * @param out OutputStream underlying writer to write generated content to - * @param ctxt I/O context to use - * - * @return This factory instance (to allow call chaining) - * - */ - protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) { - UTF8JsonGenerator gen = new UTF8JsonGenerator(ctxt, _generatorFeatures, _objectCodec, out, _quoteChar); - if (_maximumNonEscapedChar > 0) { - gen.setHighestNonEscapedChar(_maximumNonEscapedChar); - } - if (_characterEscapes != null) { - gen.setCharacterEscapes(_characterEscapes); - } - SerializableString rootSep = _rootValueSeparator; - if (rootSep != DEFAULT_ROOT_VALUE_SEPARATOR) { - gen.setRootValueSeparator(rootSep); - } - return gen; + return new WriterBasedJsonGenerator(ctxt, _generatorFeatures, out); } protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctxt) throws IOException { @@ -1494,52 +275,6 @@ protected Writer _createWriter(OutputStream out, JsonEncoding enc, IOContext ctx return new OutputStreamWriter(out, enc.getJavaName()); } - /* - * /********************************************************** - * /* Internal factory methods, decorator handling - * /********************************************************** - */ - - 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; - } - - 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; - } - - 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; - } - - 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 @@ -1554,14 +289,8 @@ protected final Writer _decorate(Writer out, IOContext ctxt) throws IOException * * @return Buffer recycler instance to use */ - public BufferRecycler _getBufferRecycler() { - // 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 (Feature.USE_THREAD_LOCAL_FOR_BUFFER_RECYCLING.enabledIn(_factoryFeatures)) { - return BufferRecyclers.getBufferRecycler(); - } - return new BufferRecycler(); + private static BufferRecycler _getBufferRecycler() { + return BufferRecyclers.getBufferRecycler(); } /** @@ -1573,72 +302,9 @@ public BufferRecycler _getBufferRecycler() { * * @return I/O context created */ - protected IOContext _createContext(ContentReference contentRef, boolean resourceManaged) { + private static IOContext _createContext(ContentReference contentRef, boolean resourceManaged) { // 21-Mar-2021, tatu: Bit of defensive coding for backwards compatibility - if (contentRef == null) { - contentRef = ContentReference.unknown(); - } return new IOContext(_getBufferRecycler(), contentRef, resourceManaged); } - /** - * Deprecated variant of {@link #_createContext(Object, boolean)} - * - * @param rawContentRef "Raw" source/target reference - * @param resourceManaged Whether input/output buffer is managed by this factory or not - * - * @return I/O context created - * - * @deprecated Since 2.13 - */ - @Deprecated // @since 2.13 - protected IOContext _createContext(Object rawContentRef, boolean resourceManaged) { - return new IOContext(_getBufferRecycler(), _createContentReference(rawContentRef), resourceManaged); - } - - /** - * Overridable factory method for constructing {@link ContentReference} - * to pass to parser or generator being created; used in cases where no offset - * or length is applicable (either irrelevant, or full contents assumed). - * - * @param contentAccessor Access to underlying content; depends on source/target, - * as well as content representation - * - * @return Reference instance to use - * - * @since 2.13 - */ - protected ContentReference _createContentReference(Object contentAccessor) { - // 21-Mar-2021, tatu: For now assume "canHandleBinaryNatively()" is reliable - // indicator of textual vs binary format: - return ContentReference.construct(!canHandleBinaryNatively(), contentAccessor); - } - - /** - * Overridable factory method for constructing {@link ContentReference} - * to pass to parser or generator being created; used in cases where content - * is available in a static buffer with relevant offset and length (mostly - * when reading from {@code byte[]}, {@code char[]} or {@code String}). - * - * @param contentAccessor Access to underlying content; depends on source/target, - * as well as content representation - * @param offset Offset of content - * @param length Length of content - * - * @return Reference instance to use - * - * @since 2.13 - */ - protected ContentReference _createContentReference(Object contentAccessor, int offset, int length) { - // 21-Mar-2021, tatu: For now assume "canHandleBinaryNatively()" is reliable - // indicator of textual vs binary format: - return ContentReference.construct(!canHandleBinaryNatively(), contentAccessor, offset, length); - } - - /* - * /********************************************************** - * /* Internal helper methods - * /********************************************************** - */ - } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactoryBuilder.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactoryBuilder.java deleted file mode 100644 index db4b8c1e2e79..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonFactoryBuilder.java +++ /dev/null @@ -1,132 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; -import com.azure.json.implementation.jackson.core.json.JsonReadFeature; -import com.azure.json.implementation.jackson.core.json.JsonWriteFeature; - -/** - * {@link TSFBuilder} - * implementation for constructing vanilla {@link JsonFactory} - * instances for reading/writing JSON encoded content. - *

- * NOTE: as of Jackson 2.x, use of JSON-specific builder is bit cumbersome - * since {@link JsonFactory} serves dual duty of base class AND actual - * implementation for JSON backend. This will be fixed in Jackson 3.0. - * - * @since 2.10 - */ -public class JsonFactoryBuilder extends TSFBuilder { - protected CharacterEscapes _characterEscapes; - - protected SerializableString _rootValueSeparator; - - protected int _maximumNonEscapedChar; - - /** - * Character used for quoting field names (if field name quoting has not - * been disabled with {@link JsonWriteFeature#QUOTE_FIELD_NAMES}) - * and JSON String values. - */ - protected char _quoteChar = JsonFactory.DEFAULT_QUOTE_CHAR; - - public JsonFactoryBuilder() { - super(); - _rootValueSeparator = JsonFactory.DEFAULT_ROOT_VALUE_SEPARATOR; - _maximumNonEscapedChar = 0; - } - - /* - * /********************************************************** - * /* Mutators - * /********************************************************** - */ - - // // // JSON-parsing features - - @Override - public JsonFactoryBuilder enable(JsonReadFeature f) { - _legacyEnable(f.mappedFeature()); - return this; - } - - @Override - public JsonFactoryBuilder enable(JsonReadFeature first, JsonReadFeature... other) { - _legacyEnable(first.mappedFeature()); - enable(first); - for (JsonReadFeature f : other) { - _legacyEnable(f.mappedFeature()); - } - return this; - } - - @Override - public JsonFactoryBuilder disable(JsonReadFeature f) { - _legacyDisable(f.mappedFeature()); - return this; - } - - @Override - public JsonFactoryBuilder disable(JsonReadFeature first, JsonReadFeature... other) { - _legacyDisable(first.mappedFeature()); - for (JsonReadFeature f : other) { - _legacyEnable(f.mappedFeature()); - } - return this; - } - - @Override - public JsonFactoryBuilder configure(JsonReadFeature f, boolean state) { - return state ? enable(f) : disable(f); - } - - // // // JSON-generating features - - @Override - public JsonFactoryBuilder enable(JsonWriteFeature f) { - JsonGenerator.Feature old = f.mappedFeature(); - if (old != null) { - _legacyEnable(old); - } - return this; - } - - @Override - public JsonFactoryBuilder enable(JsonWriteFeature first, JsonWriteFeature... other) { - _legacyEnable(first.mappedFeature()); - for (JsonWriteFeature f : other) { - _legacyEnable(f.mappedFeature()); - } - return this; - } - - @Override - public JsonFactoryBuilder disable(JsonWriteFeature f) { - _legacyDisable(f.mappedFeature()); - return this; - } - - @Override - public JsonFactoryBuilder disable(JsonWriteFeature first, JsonWriteFeature... other) { - _legacyDisable(first.mappedFeature()); - for (JsonWriteFeature f : other) { - _legacyDisable(f.mappedFeature()); - } - return this; - } - - @Override - public JsonFactoryBuilder configure(JsonWriteFeature f, boolean state) { - return state ? enable(f) : disable(f); - } - - // // // JSON-specific helper objects, settings - - // // // Accessors for JSON-specific settings - - @Override - public JsonFactory build() { - // 28-Dec-2017, tatu: No special settings beyond base class ones, so: - return new JsonFactory(this); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerationException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerationException.java index 573a99544bb8..d32c676415bd 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerationException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerationException.java @@ -17,30 +17,9 @@ public class JsonGenerationException extends StreamWriteException { private final static long serialVersionUID = 123; // eclipse complains otherwise - @Deprecated // since 2.7 - public JsonGenerationException(Throwable rootCause) { - super(rootCause, null); - } - - @Deprecated // since 2.7 - public JsonGenerationException(String msg) { - super(msg, null); - } - - @Deprecated // since 2.7 - public JsonGenerationException(String msg, Throwable rootCause) { - super(msg, rootCause, null); - } - // @since 2.7 public JsonGenerationException(String msg, JsonGenerator g) { super(msg, g); _processor = g; } - - // NOTE: overloaded in 2.13 just to retain binary compatibility with 2.12 (remove from 3.0) - @Override - public JsonGenerator getProcessor() { - return _processor; - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerator.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerator.java index 9e4f382685c9..ab067b6f2b8c 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerator.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonGenerator.java @@ -6,36 +6,15 @@ */ package com.azure.json.implementation.jackson.core; -import com.azure.json.implementation.jackson.core.JsonParser.NumberType; -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; -import com.azure.json.implementation.jackson.core.util.JacksonFeatureSet; +import com.azure.json.implementation.jackson.core.io.CharTypes; +import com.azure.json.implementation.jackson.core.io.IOContext; +import com.azure.json.implementation.jackson.core.json.JsonWriteContext; import java.io.Closeable; import java.io.Flushable; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.io.Reader; import java.io.Writer; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_EMBEDDED_OBJECT; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_END_ARRAY; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_END_OBJECT; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_FALSE; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_FIELD_NAME; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NOT_AVAILABLE; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NULL; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NUMBER_FLOAT; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NUMBER_INT; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_START_ARRAY; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_START_OBJECT; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_STRING; -import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_TRUE; /** * Base class that defines public API for writing JSON content. @@ -44,25 +23,31 @@ * * @author Tatu Saloranta */ -public abstract class JsonGenerator implements Closeable, Flushable, Versioned { - /** - * Default set of {@link StreamWriteCapability}ies that may be used as - * basis for format-specific readers (or as bogus instance if non-null - * set needs to be passed). - * - * @since 2.12 +public abstract class JsonGenerator implements Closeable, Flushable { + /* + * /********************************************************** + * /* Constants + * /********************************************************** */ - protected final static JacksonFeatureSet DEFAULT_WRITE_CAPABILITIES - = JacksonFeatureSet.fromDefaults(StreamWriteCapability.values()); /** - * Default set of {@link StreamWriteCapability}ies for typical textual formats, - * to use either as-is, or as a base with possible differences. - * - * @since 2.12 + * This is the default set of escape codes, over 7-bit ASCII range + * (first 128 character codes), used for single-byte UTF-8 characters. */ - protected final static JacksonFeatureSet DEFAULT_TEXTUAL_WRITE_CAPABILITIES - = DEFAULT_WRITE_CAPABILITIES.with(StreamWriteCapability.CAN_WRITE_FORMATTED_NUMBERS); + protected final static int[] sOutputEscapes = CharTypes.get7BitOutputEscapes(); + + public final static int SURR1_FIRST = 0xD800; + public final static int SURR1_LAST = 0xDBFF; + public final static int SURR2_FIRST = 0xDC00; + public final static int SURR2_LAST = 0xDFFF; + + // // // Constants for validation messages (since 2.6) + + protected final static String WRITE_BINARY = "write a binary value"; + protected final static String WRITE_BOOLEAN = "write a boolean value"; + protected final static String WRITE_NULL = "write a null"; + protected final static String WRITE_NUMBER = "write a number"; + protected final static String WRITE_STRING = "write a string"; /** * Enumeration that defines all togglable features for generators. @@ -112,20 +97,6 @@ public enum Feature { // // 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). - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonWriteFeature#QUOTE_FIELD_NAMES} instead - */ - @Deprecated - QUOTE_FIELD_NAMES(true), - /** * Feature that determines whether "exceptional" (not real number) * float/double values are output as quoted strings. @@ -141,111 +112,7 @@ public enum Feature { * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonWriteFeature#WRITE_NAN_AS_STRINGS} instead */ @Deprecated - QUOTE_NON_NUMERIC_NUMBERS(true), - - // // Character escaping features - - /** - * 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. - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonWriteFeature#ESCAPE_NON_ASCII} instead - */ - @Deprecated - ESCAPE_NON_ASCII(false), - - // // Datatype coercion features - - /** - * Feature that forces all Java numbers to be written as Strings, - * even if the underlying data format has non-textual representation - * (which is the case for JSON as well as all binary formats). - * Default state is 'false', meaning that Java numbers are to - * be serialized using basic numeric serialization (as JSON - * numbers, integral or floating point, for example). - * If enabled, all such numeric values are instead written out as - * textual values (which for JSON means quoted in double-quotes). - *

- * 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. - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonWriteFeature#WRITE_NUMBERS_AS_STRINGS} instead - */ - @Deprecated - WRITE_NUMBERS_AS_STRINGS(false), - - /** - * Feature that determines whether {@link BigDecimal} entries are - * serialized using {@link BigDecimal#toPlainString()} to prevent - * values to be written using scientific notation. - *

- * NOTE: only affects generators that serialize {@link BigDecimal}s - * using textual representation (textual formats but potentially some binary - * formats). - *

- * 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), - - // // 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),; + QUOTE_NON_NUMERIC_NUMBERS(true); private final boolean _defaultState; private final int _mask; @@ -286,143 +153,71 @@ public int getMask() { } /* - * /********************************************************************** + * /********************************************************** * /* Configuration - * /********************************************************************** + * /********************************************************** */ - /* - * /********************************************************************** - * /* Construction, initialization - * /********************************************************************** + /** + * Bit flag composed of bits that indicate which + * {@link Feature}s + * are enabled. */ + protected int _features; - 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}). - * - * @param oc Codec to assign, if any; {@code null} if none - * - * @return This generator, to allow call chaining + /* + * /********************************************************** + * /* State + * /********************************************************** */ - public abstract JsonGenerator setCodec(ObjectCodec oc); /** - * Method for accessing the object used for writing Java - * object as JSON content - * (using method {@link #writeObject}). - * - * @return Codec assigned to this generator, if any; {@code null} if none + * Object that keeps track of the current contextual state + * of the generator. */ - public abstract ObjectCodec getCodec(); + protected JsonWriteContext _writeContext; /** - * Accessor for finding out version of the bundle that provided this generator instance. - * - * @return Version of this generator (derived from version declared for - * {@code jackson-core} jar that contains the class + * Flag that indicates whether generator is closed or not. Gets + * set when it is closed by an explicit call + * ({@link #close}). */ - @Override - public abstract Version version(); + protected boolean _closed; /* - * /********************************************************************** - * /* Public API, state, output configuration access - * /********************************************************************** - */ - - /** - * Accessor for context object that provides information about low-level - * logical position withing output token stream. - * - * @return Stream output context ({@link JsonStreamContext}) associated with this generator + * /********************************************************** + * /* Configuration, basic I/O + * /********************************************************** */ - public abstract JsonStreamContext getOutputContext(); - /** - * 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. - * - * @return Output target this generator was configured with - */ - public Object getOutputTarget() { - return null; - } + protected final IOContext _ioContext; - /** - * Helper method, usually equivalent to: - * - * getOutputContext().getCurrentValue(); - * - *

- * Note that "current value" is NOT populated (or used) by Streaming parser or generators; - * 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 "Current value" associated with the current context (state) of this generator - * - * @since 2.13 (added as replacement for older {@link #getCurrentValue()} + /* + * /********************************************************************** + * /* Construction, initialization + * /********************************************************************** */ - public Object currentValue() { - // TODO: implement directly in 2.14 or later, make getCurrentValue() call this - return getCurrentValue(); - } - /** - * Helper method, usually equivalent to: - * - * getOutputContext().setCurrentValue(v); - * - * - * @param v Current value to assign for the current context of this generator - * - * @since 2.13 (added as replacement for older {@link #setCurrentValue} - */ - public void assignCurrentValue(Object v) { - // TODO: implement directly in 2.14 or later, make setCurrentValue() call this - setCurrentValue(v); + protected JsonGenerator(IOContext ctxt, int features) { + _ioContext = ctxt; + _features = features; + _writeContext = JsonWriteContext.createRootContext(); } - // TODO: deprecate in 2.14 or later - /** - * Alias for {@link #currentValue()}, to be deprecated in later - * Jackson 2.x versions (and removed from Jackson 3.0). - * - * @return Location of the last processed input unit (byte or character) + /* + * /********************************************************************** + * /* Public API, state, output configuration access + * /********************************************************************** */ - public Object getCurrentValue() { - JsonStreamContext ctxt = getOutputContext(); - return (ctxt == null) ? null : ctxt.getCurrentValue(); - } - // TODO: deprecate in 2.14 or later /** - * Alias for {@link #assignCurrentValue}, to be deprecated in later - * Jackson 2.x versions (and removed from Jackson 3.0). + * Accessor for context object that provides information about low-level + * logical position withing output token stream. * - * @param v Current value to assign for the current context of this generator + * @return Stream output context ({@link JsonStreamContext}) associated with this generator */ - public void setCurrentValue(Object v) { - JsonStreamContext ctxt = getOutputContext(); - if (ctxt != null) { - ctxt.setCurrentValue(v); - } + public JsonStreamContext getOutputContext() { + return _writeContext; } /* @@ -431,26 +226,6 @@ public void setCurrentValue(Object v) { * /********************************************************************** */ - /** - * Method for enabling specified generator feature: - * check {@link Feature} for list of available features. - * - * @param f Feature to enable - * - * @return This generator, to allow call chaining - */ - public abstract JsonGenerator enable(Feature f); - - /** - * Method for disabling specified feature - * (check {@link Feature} for list of features) - * - * @param f Feature to disable - * - * @return This generator, to allow call chaining - */ - public abstract JsonGenerator disable(Feature f); - /** * Method for enabling or disabling specified feature: * check {@link Feature} for list of available features. @@ -461,10 +236,11 @@ public void setCurrentValue(Object v) { * @return This generator, to allow call chaining */ public final JsonGenerator configure(Feature f, boolean state) { + final int mask = f.getMask(); if (state) - enable(f); + _features |= mask; else - disable(f); + _features &= ~mask; return this; } @@ -476,902 +252,161 @@ public final JsonGenerator configure(Feature f, boolean state) { * * @return True if specified feature is enabled; false if not */ - public abstract boolean isEnabled(Feature f); + public final boolean isEnabled(Feature f) { + return (_features & f.getMask()) != 0; + } + + /* + * /********************************************************************** + * /* Public API, write methods, structural + * /********************************************************************** + */ /** - * Method for checking whether given feature is enabled. - * Check {@link Feature} for list of available features. - * - * @param f Feature to check - * - * @return True if specified feature is enabled; false if not + * 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. * - * @since 2.10 + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public boolean isEnabled(StreamWriteFeature f) { - return isEnabled(f.mappedFeature()); - } + public abstract void writeStartArray() throws IOException; /** - * Bulk access method for getting state of all standard (non-dataformat-specific) - * {@link Feature}s. - * - * @return Bit mask that defines current states of all standard {@link Feature}s. + * 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. * - * @since 2.3 + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public abstract int getFeatureMask(); + public abstract void writeEndArray() throws IOException; /** - * 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 generator, to allow call chaining + * Method for writing starting marker of an 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. * - * @deprecated Since 2.7, use {@link #overrideStdFeatures(int, int)} instead -- remove from 2.9 + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - @Deprecated - public abstract JsonGenerator setFeatureMask(int values); + public abstract void writeStartObject() throws IOException; /** - * Bulk set method for (re)setting states of features specified by 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 - * - * @return This generator, to allow call chaining + * Method for writing closing marker of an 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). * - * @since 2.6 + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public JsonGenerator overrideStdFeatures(int values, int mask) { - int oldState = getFeatureMask(); - int newState = (oldState & ~mask) | (values & mask); - return setFeatureMask(newState); - } + public abstract void writeEndObject() throws IOException; /** - * 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. + * 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. *

- * 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 + * 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). * - * @return This generator, to allow call chaining + * @param name Field name to write * - * @since 2.6 + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public JsonGenerator overrideFormatFeatures(int values, int mask) { - // 08-Oct-2018, tatu: For 2.10 we actually do get `JsonWriteFeature`s, although they - // are (for 2.x only, not for 3.x) mapper to legacy settings. So do not throw exception: - // throw new IllegalArgumentException("No FormatFeatures defined for generator of type "+getClass().getName()); - return this; - } + public abstract void writeFieldName(String name) throws IOException; /* * /********************************************************************** - * /* Public API, Schema configuration + * /* Public API, write methods, text/String values * /********************************************************************** */ /** - * 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 + * 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. * - * @throws UnsupportedOperationException if generator does not support schema - */ - public void setSchema(FormatSchema schema) { - throw new UnsupportedOperationException(String.format( - "Generator of type %s does not support schema of type '%s'", getClass().getName(), schema.getSchemaType())); - } - - /** - * Method for accessing Schema that this generator uses, if any; {@code null} if none. - * Default implementation returns null. + * @param text Text value to write * - * @return Schema in use by this generator, if any; {@code null} if none + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public FormatSchema getSchema() { - return null; - } + public abstract void writeString(String text) throws IOException; /* * /********************************************************************** - * /* Public API, other configuration + * /* Public API, write methods, binary/raw content * /********************************************************************** */ /** - * 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. + * 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. *

- * Default implementation does nothing; sub-classes need to redefine - * it according to rules of supported data format. + * Note that not all generator implementations necessarily support + * such by-pass methods: those that do not will throw + * {@link UnsupportedOperationException}. * - * @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. + * @param text Textual contents to include as-is in output. * - * @return This generator, to allow call chaining + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public JsonGenerator setHighestNonEscapedChar(int charCode) { - return this; - } + public abstract void writeRaw(String text) throws IOException; /** - * 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. + * 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}. * - * @return Currently active limitation for highest non-escaped character, - * if defined; or 0 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. + * @param text String that has contents to include as-is in output + * @param offset Offset within {@code text} of the first character to output + * @param len Length of content (from {@code text}, starting at offset {@code offset}) to output * - * @return {@link CharacterEscapes} configured for this generator, if any; {@code null} if none + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer */ - public CharacterEscapes getCharacterEscapes() { - return null; - } + public abstract void writeRaw(String text, int offset, int len) throws IOException; /** - * Method for defining custom escapes factory uses for {@link JsonGenerator}s - * it creates. - *

- * Default implementation does nothing and simply returns this instance. - * - * @param esc {@link CharacterEscapes} to configure this generator to use, if any; {@code null} if none - * - * @return This generator, to allow call chaining - */ - 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 - * - * @return This generator, to allow call chaining - */ - public JsonGenerator setRootValueSeparator(SerializableString sep) { - throw new UnsupportedOperationException(); - } - - /* - * /********************************************************************** - * /* Public API, output state access - * /********************************************************************** - */ - - /** - * 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 OutputStream}, `char` for {@link 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; - } - - /* - * /********************************************************************** - * /* 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}. - *

- * 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. - * - * @return {@code True} if this generator is capable of writing "native" Object Ids - * (which is typically determined by capabilities of the underlying format), - * {@code false} if not - * - * @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. - * - * @return {@code True} if this generator is capable of writing "native" Type Ids - * (which is typically determined by capabilities of the underlying format), - * {@code false} if not - * - * @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. - * - * @return {@code True} if this generator is capable of writing "raw" Binary - * Content - * (this is typically determined by capabilities of the underlying format); - * {@code false} if not - * - * @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. - * - * @return {@code True} if this generator is allowed to only write values - * of some Object fields and omit the rest; {@code false} if not - * - * @since 2.3 - */ - public boolean canOmitFields() { - return true; - } - - /** - * Introspection method to call to check whether it is possible - * to write numbers using {@link #writeNumber(String)} - * using possible custom format, or not. Typically textual formats - * allow this (and JSON specifically does), whereas binary formats - * do not allow this (except by writing them as Strings). - * Usual reason for calling this method is to check whether custom - * formatting of numbers may be applied by higher-level code (databinding) - * or not. - * - * @return {@code True} if this generator is capable of writing "formatted" - * numbers (and if so, need to be passed using - * {@link #writeNumber(String)}, that is, passed as {@code String}); - * {@code false} if not - * - * @since 2.8 - */ - public boolean canWriteFormattedNumbers() { - return false; - } - - /** - * Accessor for getting metadata on capabilities of this generator, based on - * underlying data format being read (directly or indirectly). - * - * @return Set of write capabilities for content written using this generator - * - * @since 2.12 - */ - public JacksonFeatureSet getWriteCapabilities() { - return DEFAULT_WRITE_CAPABILITIES; - } - - /* - * /********************************************************************** - * /* 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. - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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 (and SHOULD if format itself encodes length) - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.4 - * - * @deprecated Since 2.12 Use {@link #writeStartArray(Object, int)} instead - */ - @Deprecated - public void writeStartArray(int size) throws IOException { - writeStartArray(); - } - - /** - * Method for writing start marker of an Array value, similar - * to {@link #writeStartArray()}, - * but also specifying the "current value" - * to assign to the new Array context being created. - * - * @param forValue "Current value" to assign for the Array context being created - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.10 - */ - public void writeStartArray(Object forValue) throws IOException { - writeStartArray(); - setCurrentValue(forValue); - } - - /** - * Method for writing start marker of an Array value, similar - * to {@link #writeStartArray()}, but also specifying the "current value" - * to assign to the new Array context being created - * as well as how many elements will be written for the array before calling - * {@link #writeEndArray()}. - * - * @param forValue "Current value" to assign for the Array context being created - * @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 (and SHOULD if format itself encodes length) - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.10 - */ - public void writeStartArray(Object forValue, int size) throws IOException { - writeStartArray(size); - setCurrentValue(forValue); - } - - /** - * 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. - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeEndArray() throws IOException; - - /** - * Method for writing starting marker of an 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. - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeStartObject() throws IOException; - - /** - * Method for writing starting marker of an Object value - * to represent the given Java Object value. - * Argument is offered as metadata, but more - * importantly it should be assigned as the "current value" - * for the Object content that gets constructed and initialized. - *

- * Object values can be written in any context where values - * are allowed: meaning everywhere except for when - * a field name is expected. - * - * @param forValue "Current value" to assign for the Object context being created - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.8 - */ - public void writeStartObject(Object forValue) throws IOException { - writeStartObject(); - setCurrentValue(forValue); - } - - /** - * Method for writing starting marker of an Object value - * to represent the given Java Object value. - * Argument is offered as metadata, but more - * importantly it should be assigned as the "current value" - * for the Object content that gets constructed and initialized. - * In addition, caller knows number of key/value pairs ("properties") - * that will get written for the Object value: this is relevant for - * some format backends (but not, as an example, for JSON). - *

- * Object values can be written in any context where values - * are allowed: meaning everywhere except for when - * a field name is expected. - * - * @param forValue "Current value" to assign for the Object context being created - * @param size Number of key/value pairs this Object will have: actual - * number of entries written (before matching call to - * {@link #writeEndObject()} MUST match; generator MAY verify - * this is the case (and SHOULD if format itself encodes length) - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.10 - */ - public void writeStartObject(Object forValue, int size) throws IOException { - writeStartObject(); - setCurrentValue(forValue); - } - - /** - * Method for writing closing marker of an 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). - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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). - * - * @param name Field name to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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. - * - * @param name Field name to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeFieldName(SerializableString name) throws IOException; - - /** - * Alternative to {@link #writeFieldName(String)} that may be used - * in cases where property key is of numeric type; either where - * underlying format supports such notion (some binary formats do, - * unlike JSON), or for convenient conversion into String presentation. - * Default implementation will simply convert id into String - * and call {@link #writeFieldName(String)}. - * - * @param id Field id to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.8 - */ - public void writeFieldId(long id) throws IOException { - writeFieldName(Long.toString(id)); - } - - /* - * /********************************************************************** - * /* Public API, write methods, scalar arrays (2.8) - * /********************************************************************** - */ - - /** - * Value write method that can be called to write a single - * array (sequence of {@link JsonToken#START_ARRAY}, zero or - * more {@link JsonToken#VALUE_NUMBER_INT}, {@link JsonToken#END_ARRAY}) - * - * @param array Array that contains values to write - * @param offset Offset of the first element to write, within array - * @param length Number of elements in array to write, from `offset` to `offset + len - 1` - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.8 - */ - public void writeArray(int[] array, int offset, int length) throws IOException { - if (array == null) { - throw new IllegalArgumentException("null array"); - } - _verifyOffsets(array.length, offset, length); - writeStartArray(array, length); - for (int i = offset, end = offset + length; i < end; ++i) { - writeNumber(array[i]); - } - writeEndArray(); - } - - /** - * Value write method that can be called to write a single - * array (sequence of {@link JsonToken#START_ARRAY}, zero or - * more {@link JsonToken#VALUE_NUMBER_INT}, {@link JsonToken#END_ARRAY}) - * - * @param array Array that contains values to write - * @param offset Offset of the first element to write, within array - * @param length Number of elements in array to write, from `offset` to `offset + len - 1` - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.8 - */ - public void writeArray(long[] array, int offset, int length) throws IOException { - if (array == null) { - throw new IllegalArgumentException("null array"); - } - _verifyOffsets(array.length, offset, length); - writeStartArray(array, length); - for (int i = offset, end = offset + length; i < end; ++i) { - writeNumber(array[i]); - } - writeEndArray(); - } - - /** - * Value write method that can be called to write a single - * array (sequence of {@link JsonToken#START_ARRAY}, zero or - * more {@link JsonToken#VALUE_NUMBER_FLOAT}, {@link JsonToken#END_ARRAY}) - * - * @param array Array that contains values to write - * @param offset Offset of the first element to write, within array - * @param length Number of elements in array to write, from `offset` to `offset + len - 1` - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.8 - */ - public void writeArray(double[] array, int offset, int length) throws IOException { - if (array == null) { - throw new IllegalArgumentException("null array"); - } - _verifyOffsets(array.length, offset, length); - writeStartArray(array, length); - for (int i = offset, end = offset + length; i < end; ++i) { - writeNumber(array[i]); - } - writeEndArray(); - } - - /** - * Value write method that can be called to write a single - * array (sequence of {@link JsonToken#START_ARRAY}, zero or - * more {@link JsonToken#VALUE_STRING}, {@link JsonToken#END_ARRAY}) - * - * @param array Array that contains values to write - * @param offset Offset of the first element to write, within array - * @param length Number of elements in array to write, from `offset` to `offset + len - 1` - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.11 - */ - public void writeArray(String[] array, int offset, int length) throws IOException { - if (array == null) { - throw new IllegalArgumentException("null array"); - } - _verifyOffsets(array.length, offset, length); - writeStartArray(array, length); - for (int i = offset, end = offset + length; i < end; ++i) { - writeString(array[i]); - } - writeEndArray(); - } - - /* - * /********************************************************************** - * /* 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. - * - * @param text Text value to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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. - * If {@code len} is < 0, then write all contents of the reader. - * Otherwise, write only len characters. - *

- * Note: actual length of content available may exceed {@code len} but - * can not be less than it: if not enough content available, a - * {@link JsonGenerationException} will be thrown. - * - * @param reader Reader to use for reading Text value to write - * @param len Maximum Length of Text value to read (in {@code char}s, non-negative) - * if known; {@code -1} to indicate "read and write it all" - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer; or if length ({@code len}) is specified but - * {@code reader} does not provide enough content - * - * @since 2.9 - */ - public void writeString(Reader reader, int len) throws IOException { - // Implemented as "unsupported" for backwards compatibility - _reportUnsupportedOperation(); - } - - /** - * 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. - * - * @param buffer Buffer that contains String value to write - * @param offset Offset in {@code buffer} of the first character of String value to write - * @param len Length of the String value (in characters) to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeString(char[] buffer, 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. - * - * @param text Pre-encoded String value to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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 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. - * - * @param buffer Buffer that contains String value to write - * @param offset Offset in {@code buffer} of the first byte of String value to write - * @param len Length of the String value (in characters) to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeRawUTF8String(byte[] buffer, int offset, int len) 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 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. - * - * @param buffer Buffer that contains String value to write - * @param offset Offset in {@code buffer} of the first byte of String value to write - * @param len Length of the String value (in characters) to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeUTF8String(byte[] buffer, int offset, int len) 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}. - * - * @param text Textual contents to include as-is in output. - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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}. - * - * @param text String that has contents to include as-is in output - * @param offset Offset within {@code text} of the first character to output - * @param len Length of content (from {@code text}, starting at offset {@code offset}) to output - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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. + * 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 @@ -1386,52 +421,6 @@ public void writeString(Reader reader, int len) throws IOException { */ 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}. - * - * @param c Character to included in output - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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). - * - * @param raw Pre-encoded textual contents to included in output - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - // public abstract void writeRaw(SerializableString raw) throws IOException; - 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 @@ -1445,26 +434,9 @@ public void writeRaw(SerializableString raw) throws IOException { * @throws IOException if there is either an underlying I/O problem or encoding * issue at format layer */ - 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)}. - * - * @param raw Pre-encoded textual contents to included in output - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.5 - */ - public void writeRawValue(SerializableString raw) throws IOException { - writeRawValue(raw.getValue()); + public void writeRawValue(String text) throws IOException { + _verifyValueWrite("write raw value"); + writeRaw(text); } /** @@ -1486,21 +458,7 @@ public void writeRawValue(SerializableString raw) throws IOException { * @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. - * @param data Buffer that contains binary data to write - * @param offset Offset in {@code data} of the first byte of data to write - * @param len Length of data to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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}). - * + * and also the underlying alphabet to use. * @param data Buffer that contains binary data to write * @param offset Offset in {@code data} of the first byte of data to write * @param len Length of data to write @@ -1508,9 +466,7 @@ public void writeRawValue(SerializableString raw) throws IOException { * @throws IOException if there is either an underlying I/O problem or encoding * issue at format layer */ - public void writeBinary(byte[] data, int offset, int len) throws IOException { - writeBinary(Base64Variants.getDefaultVariant(), data, offset, len); - } + public abstract void writeBinary(Base64Variant bv, byte[] data, int offset, int len) throws IOException; /** * Similar to {@link #writeBinary(Base64Variant,byte[],int,int)}, @@ -1527,76 +483,12 @@ 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 - * - * @return Number of bytes actually written - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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, 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 - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract int writeBinary(Base64Variant bv, InputStream data, int dataLength) throws IOException; - /* * /********************************************************************** * /* Public API, write methods, numeric * /********************************************************************** */ - /** - * 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 - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @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 @@ -1625,20 +517,6 @@ public void writeNumber(short v) throws IOException { */ 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 - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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 @@ -1667,64 +545,6 @@ public void writeNumber(short v) throws IOException { */ 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 - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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. - *

- * 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}. - * - * @param encodedValue Textual (possibly format) number representation to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * @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; - - /** - * Overloaded version of {@link #writeNumber(String)} with same semantics - * but possibly more efficient operation. - * - * @param encodedValueBuffer Buffer that contains the textual number representation to write - * @param offset Offset of the first character of value to write - * @param len Length of the value (in characters) to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.11 - */ - public void writeNumber(char[] encodedValueBuffer, int offset, int len) throws IOException { - writeNumber(new String(encodedValueBuffer, offset, len)); - } - /* * /********************************************************************** * /* Public API, write methods, other value types @@ -1758,459 +578,6 @@ public void writeNumber(char[] encodedValueBuffer, int offset, int len) throws I */ public abstract void writeNull() throws IOException; - /** - * Method that can be called on backends that support passing opaque native - * values that some data formats support; not used with JSON backend, - * more common with binary formats. - *

- * NOTE: this is NOT the method to call for serializing regular POJOs, - * see {@link #writeObject} instead. - * - * @param object Native format-specific value to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @since 2.8 - */ - public void writeEmbeddedObject(Object object) throws IOException { - // 01-Sep-2016, tatu: As per [core#318], handle small number of cases - if (object == null) { - writeNull(); - return; - } - if (object instanceof byte[]) { - writeBinary((byte[]) object); - return; - } - throw new JsonGenerationException( - "No native support for writing embedded objects of type " + object.getClass().getName(), this); - } - - /* - * /********************************************************************** - * /* 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. - * - * @param id Native Object Id to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * @throws JsonGenerationException if Object ID output is not allowed - * (either at all, or specifically in this position in output) - * - * @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. - * - * @param referenced Referenced value, for which Object Id is expected to be written - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * @throws JsonGenerationException if Object ID output is not allowed - * (either at all, or specifically in this position in output) - */ - public void writeObjectRef(Object referenced) 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. - * - * @param id Native Type Id to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * @throws JsonGenerationException if Type ID output is not allowed - * (either at all, or specifically in this position in output) - * - * @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 - * /********************************************************************** - */ - - // TODO: deprecate in 2.14 or later - /** - * Older alias for {@link #writePOJO(Object)} - * - * @param pojo Java value (usually POJO) to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - 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. - * - * @param rootNode {@link TreeNode} to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public abstract void writeTree(TreeNode rootNode) throws IOException; - - /* - * /********************************************************************** - * /* Public API, convenience field write methods - * /********************************************************************** - */ - - // 04-Oct-2019, tatu: Reminder: these could be defined final to - // remember NOT to override in delegating sub-classes -- but - // not final in 2.x to reduce compatibility issues - - /** - * Convenience method for outputting a field entry ("member") - * that has a boolean value. Equivalent to: - *

-     *  writeFieldName(fieldName);
-     *  writeBoolean(value);
-     *
- * - * @param fieldName Name of the field to write - * @param value Boolean value of the field to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public void writeBooleanField(String fieldName, boolean value) throws IOException { - writeFieldName(fieldName); - writeBoolean(value); - } - - /** - * Convenience method for outputting a field entry ("member") - * that has a String value. Equivalent to: - *
-     *  writeFieldName(fieldName);
-     *  writeString(value);
-     *
- * - * @param fieldName Name of the field to write - * @param value String value of the field to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public void writeStringField(String fieldName, String value) throws IOException { - writeFieldName(fieldName); - writeString(value); - } - - // TODO: deprecate in 2.14 or later - - // // // But this method does need to be delegate so... - - /** - * 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()}. - *

- * Default implementation does nothing. - * - * @param fieldName Name of the field omitted - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - * - * @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) - * - * @param p Parser that points to event (token) to copy - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public void copyCurrentEvent(JsonParser p) throws IOException { - JsonToken t = p.currentToken(); - final int token = (t == null) ? ID_NOT_AVAILABLE : t.id(); - switch (token) { - case ID_NOT_AVAILABLE: - _reportError("No current event to copy"); - break; // never gets here - - 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: - throw new IllegalStateException("Internal error: unknown current token, " + t); - } - } - - /** - * 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. - * - * @param p Parser that points to the value to copy - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - public void copyCurrentStructure(JsonParser p) throws IOException { - JsonToken t = p.currentToken(); - // Let's handle field-name separately first - int id = (t == null) ? ID_NOT_AVAILABLE : t.id(); - if (id == ID_FIELD_NAME) { - writeFieldName(p.getCurrentName()); - t = p.nextToken(); - id = (t == null) ? ID_NOT_AVAILABLE : t.id(); - // fall-through to copy the associated value - } - switch (id) { - case ID_START_OBJECT: - writeStartObject(); - _copyCurrentContents(p); - return; - - case ID_START_ARRAY: - writeStartArray(); - _copyCurrentContents(p); - return; - - default: - copyCurrentEvent(p); - } - } - - // @since 2.10 - protected void _copyCurrentContents(JsonParser p) throws IOException { - int depth = 1; - JsonToken t; - - // Mostly copied from `copyCurrentEvent()`, but with added nesting counts - while ((t = p.nextToken()) != null) { - switch (t.id()) { - case ID_FIELD_NAME: - writeFieldName(p.getCurrentName()); - break; - - case ID_START_ARRAY: - writeStartArray(); - ++depth; - break; - - case ID_START_OBJECT: - writeStartObject(); - ++depth; - break; - - case ID_END_ARRAY: - writeEndArray(); - if (--depth == 0) { - return; - } - break; - - case ID_END_OBJECT: - writeEndObject(); - if (--depth == 0) { - return; - } - 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: - throw new IllegalStateException("Internal error: unknown current token, " + t); - } - } - } - /* * /********************************************************************** * /* Public API, buffer handling @@ -2228,14 +595,6 @@ protected void _copyCurrentContents(JsonParser p) throws IOException { @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. - * - * @return {@code True} if this generator instance has been closed - */ - public abstract boolean isClosed(); - /* * /********************************************************************** * /* Closeable implementation @@ -2257,7 +616,34 @@ protected void _copyCurrentContents(JsonParser p) throws IOException { * @throws IOException if there is either an underlying I/O problem */ @Override - public abstract void close() throws IOException; + public void close() throws IOException { + _closed = true; + } + + /* + * /********************************************************** + * /* Package methods for this, sub-classes + * /********************************************************** + */ + + /** + * Method called to release any buffers generator may be holding, + * once generator is being closed. + */ + protected abstract void _releaseBuffers(); + + /** + * Method called before trying to write a value (scalar or structured), + * to verify that this is legal in current output state, as well as to + * output separators if and as necessary. + * + * @param typeMsg Additional message used for generating exception message + * if value output is NOT legal in current generator output state. + * + * @throws IOException if there is either an underlying I/O problem or encoding + * issue at format layer + */ + protected abstract void _verifyValueWrite(String typeMsg) throws IOException; /* * /********************************************************************** @@ -2280,88 +666,23 @@ protected void _reportError(String msg) throws JsonGenerationException { throw new JsonGenerationException(msg, this); } - protected void _reportUnsupportedOperation() { - throw new UnsupportedOperationException("Operation not supported by generator of type " + getClass().getName()); - } - - // @since 2.8 - protected final void _verifyOffsets(int arrayLength, int offset, int length) { - if ((offset < 0) || (offset + length) > arrayLength) { - throw new IllegalArgumentException( - String.format("invalid argument(s) (offset=%d, length=%d) for input array of %d element", offset, - length, arrayLength)); - } + protected void _reportCantWriteValueExpectName(String typeMsg) throws IOException { + _reportError("Can not " + typeMsg + ", expecting field name (context: " + _writeContext.typeDesc() + ")"); } - /** - * 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 Value to write - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer + /* + * /********************************************************** + * /* UTF-8 related helper method(s) + * /********************************************************** */ - 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; + + // @since 2.5 + protected final int _decodeSurrogate(int surr1, int surr2) throws IOException { + // First is known to be valid, but how about the other? + if (surr2 < SURR2_FIRST || surr2 > SURR2_LAST) { + String msg = String.format("Incomplete surrogate pair: first char 0x%04X, second 0x%04X", surr1, surr2); + _reportError(msg); } - throw new IllegalStateException( - "No ObjectCodec defined for the generator, can only serialize simple wrapper types (type passed " - + value.getClass().getName() + ")"); + return 0x10000 + ((surr1 - SURR1_FIRST) << 10) + (surr2 - SURR2_FIRST); } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonLocation.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonLocation.java index 6afac2d55d38..6a184b7b49e5 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonLocation.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonLocation.java @@ -22,12 +22,6 @@ public class JsonLocation implements java.io.Serializable { private static final long serialVersionUID = 2L; // in 2.13 - /** - * @deprecated Since 2.13 use {@link ContentReference#DEFAULT_MAX_CONTENT_SNIPPET} instead - */ - @Deprecated - public static final int MAX_CONTENT_SNIPPET = 500; - /** * Shared immutable "N/A location" that can be returned to indicate * that no location information is available. @@ -81,23 +75,6 @@ public JsonLocation(ContentReference contentRef, long totalBytes, long totalChar _columnNr = columnNr; } - @Deprecated // since 2.13 - public JsonLocation(Object srcRef, long totalChars, int lineNr, int columnNr) { - this(_wrap(srcRef), totalChars, lineNr, columnNr); - } - - @Deprecated // since 2.13 - public JsonLocation(Object srcRef, long totalBytes, long totalChars, int lineNr, int columnNr) { - this(_wrap(srcRef), totalBytes, totalChars, lineNr, columnNr); - } - - protected static ContentReference _wrap(Object srcRef) { - if (srcRef instanceof ContentReference) { - return (ContentReference) srcRef; - } - return ContentReference.construct(false, srcRef); - } - /* * /********************************************************************** * /* Simple accessors @@ -105,33 +82,15 @@ protected static ContentReference _wrap(Object srcRef) { */ /** - * 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. - * - * @return Source reference this location was constructed with, if any; {@code null} if none - * - * @deprecated Since 2.13 Use {@link #contentReference} instead - */ - @Deprecated - public Object getSourceRef() { - return _contentReference.getRawContent(); - } - - /** - * Accessor for getting a textual description of source reference - * (Object returned by {@link #getSourceRef()}), as included in - * description returned by {@link #toString()}. + * Accessor for getting a textual description of source reference, + * as included in description returned by {@link #toString()}. *

* Note: implementation will simply call * {@link ContentReference#buildSourceDescription()}) *

* NOTE: not added as a "getter" to prevent it from getting serialized. * - * @return Description of the source reference (see {@link #getSourceRef()} + * @return Description of the source reference * * @since 2.9 */ diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParseException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParseException.java index ff447d49e55a..2a56cfeadb7a 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParseException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParseException.java @@ -8,7 +8,6 @@ package com.azure.json.implementation.jackson.core; import com.azure.json.implementation.jackson.core.exc.StreamReadException; -import com.azure.json.implementation.jackson.core.util.RequestPayload; /** * Exception type for parsing problems, used when non-well-formed content @@ -18,20 +17,8 @@ public class JsonParseException extends StreamReadException { private static final long serialVersionUID = 2L; // 2.7 - @Deprecated // since 2.7 - public JsonParseException(String msg, JsonLocation loc) { - super(msg, loc, null); - } - - @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. + * Constructor that uses current parsing location as location. * * @param p Parser in use when encountering issue reported * @param msg Base exception message to use @@ -46,56 +33,4 @@ public JsonParseException(JsonParser p, String msg) { public JsonParseException(JsonParser p, String msg, Throwable root) { super(p, msg, root); } - - // @since 2.7 - public JsonParseException(JsonParser p, String msg, JsonLocation loc) { - super(p, msg, loc); - } - - // @since 2.7 - public JsonParseException(JsonParser p, String msg, JsonLocation loc, Throwable root) { - super(msg, loc, root); - } - - /** - * Fluent method that may be used to assign payload to this exception, - * to let recipient access it for diagnostics purposes. - *

- * NOTE: `this` instance is modified and no new instance is constructed. - * - * @param payload Payload to assign to this exception - * - * @return This exception instance to allow call chaining - * - * @since 2.8 - */ - @Override - public JsonParseException withRequestPayload(RequestPayload payload) { - _requestPayload = payload; - return this; - } - - // NOTE: overloaded in 2.10 just to retain binary compatibility with 2.9 (remove from 3.0) - @Override - public JsonParser getProcessor() { - return super.getProcessor(); - } - - // NOTE: overloaded in 2.10 just to retain binary compatibility with 2.9 (remove from 3.0) - @Override - public RequestPayload getRequestPayload() { - return super.getRequestPayload(); - } - - // NOTE: overloaded in 2.10 just to retain binary compatibility with 2.9 (remove from 3.0) - @Override - public String getRequestPayloadAsString() { - return super.getRequestPayloadAsString(); - } - - // NOTE: overloaded in 2.10 just to retain binary compatibility with 2.9 (remove from 3.0) - @Override - public String getMessage() { - return super.getMessage(); - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParser.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParser.java index 2f1ba05790cd..4b2c3fc3038f 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParser.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonParser.java @@ -7,14 +7,23 @@ package com.azure.json.implementation.jackson.core; -import java.io.*; +import com.azure.json.implementation.jackson.core.exc.InputCoercionException; +import com.azure.json.implementation.jackson.core.io.ContentReference; +import com.azure.json.implementation.jackson.core.io.IOContext; +import com.azure.json.implementation.jackson.core.io.JsonEOFException; +import com.azure.json.implementation.jackson.core.io.NumberInput; +import com.azure.json.implementation.jackson.core.json.JsonReadContext; +import com.azure.json.implementation.jackson.core.util.ByteArrayBuilder; +import com.azure.json.implementation.jackson.core.util.TextBuffer; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; import java.math.BigDecimal; import java.math.BigInteger; - -import com.azure.json.implementation.jackson.core.exc.InputCoercionException; -import com.azure.json.implementation.jackson.core.type.TypeReference; -import com.azure.json.implementation.jackson.core.util.JacksonFeatureSet; -import com.azure.json.implementation.jackson.core.util.RequestPayload; +import java.util.Arrays; /** * Base class that defines public API for reading JSON content. @@ -24,52 +33,109 @@ * @author Tatu Saloranta */ @SuppressWarnings("cast") -public abstract class JsonParser implements Closeable, Versioned { - private final static int MIN_BYTE_I = Byte.MIN_VALUE; - // as per [JACKSON-804], allow range up to and including 255 - private final static int MAX_BYTE_I = 255; +public abstract class JsonParser implements Closeable { + // 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; + + protected final static int INT_RBRACKET = ']'; + 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_ASTERISK = '*'; + protected final static int INT_COLON = ':'; + protected final static int INT_COMMA = ','; + protected final static int INT_HASH = '#'; + + // Number chars + protected final static int INT_0 = '0'; + protected final static int INT_9 = '9'; + protected final static int INT_MINUS = '-'; + protected final static int INT_PLUS = '+'; + + protected final static int INT_PERIOD = '.'; + protected final static int INT_e = 'e'; + protected final static int INT_E = 'E'; + + protected final static char CHAR_NULL = '\0'; + + /** + * @since 2.9 + */ + protected final static byte[] NO_BYTES = new byte[0]; + + /* + * /********************************************************** + * /* Constants and fields of former 'JsonNumericParserBase' + * /********************************************************** + */ + + protected final static int NR_UNKNOWN = 0; + + // First, integer types + + protected final static int NR_INT = 0x0001; + protected final static int NR_LONG = 0x0002; + protected final static int NR_BIGINT = 0x0004; + + // And then floating point types - private final static int MIN_SHORT_I = Short.MIN_VALUE; - private final static int MAX_SHORT_I = Short.MAX_VALUE; + protected final static int NR_DOUBLE = 0x008; + protected final static int NR_BIGDECIMAL = 0x0010; /** - * Enumeration of possible "native" (optimal) types that can be - * used for numbers. + * NOTE! Not used by JSON implementation but used by many of binary codecs + * + * @since 2.9 + */ + protected final static int NR_FLOAT = 0x020; + + // Also, we need some numeric constants + + protected final static BigInteger BI_MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); + protected final static BigInteger BI_MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); + + protected final static BigInteger BI_MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE); + protected final static BigInteger BI_MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); + + protected final static BigDecimal BD_MIN_LONG = new BigDecimal(BI_MIN_LONG); + protected final static BigDecimal BD_MAX_LONG = new BigDecimal(BI_MAX_LONG); + + protected final static BigDecimal BD_MIN_INT = new BigDecimal(BI_MIN_INT); + protected final static BigDecimal BD_MAX_INT = new BigDecimal(BI_MAX_INT); + + protected final static long MIN_INT_L = Integer.MIN_VALUE; + protected final static long MAX_INT_L = Integer.MAX_VALUE; + + // These are not very accurate, but have to do... (for bounds checks) + + protected final static double MIN_LONG_D = (double) Long.MIN_VALUE; + protected final static double MAX_LONG_D = (double) Long.MAX_VALUE; + + protected final static double MIN_INT_D = Integer.MIN_VALUE; + protected final static double MAX_INT_D = Integer.MAX_VALUE; + + /* + * /********************************************************** + * /* Misc other constants + * /********************************************************** */ - public enum NumberType { - INT, LONG, BIG_INTEGER, FLOAT, DOUBLE, BIG_DECIMAL - } /** - * Default set of {@link StreamReadCapability}ies that may be used as - * basis for format-specific readers (or as bogus instance if non-null - * set needs to be passed). + * Maximum number of characters to include in token reported + * as part of error messages. * - * @since 2.12 + * @since 2.9 */ - protected final static JacksonFeatureSet DEFAULT_READ_CAPABILITIES - = JacksonFeatureSet.fromDefaults(StreamReadCapability.values()); + protected final static int MAX_ERROR_TOKEN_LENGTH = 256; /** * 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}. - *

- * Feature is enabled by default. - */ - AUTO_CLOSE_SOURCE(true), - // // // Support for non-standard data format constructs /** @@ -89,104 +155,6 @@ public enum Feature { */ 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. - *

- * NOTE: while not technically deprecated, since 2.10 recommended to use - * {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_YAML_COMMENTS} instead. - */ - 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. - *

- * NOTE: while not technically deprecated, since 2.10 recommended to use - * {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_UNQUOTED_FIELD_NAMES} instead. - */ - 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. - *

- * NOTE: while not technically deprecated, since 2.10 recommended to use - * {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_SINGLE_QUOTES} instead. - */ - 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. - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_UNESCAPED_CONTROL_CHARS} instead - */ - @Deprecated - 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. - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER} instead - */ - @Deprecated - 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. - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_LEADING_ZEROS_FOR_NUMBERS} instead - */ - @Deprecated - ALLOW_NUMERIC_LEADING_ZEROS(false), - - /** - * @deprecated Use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS} instead - */ - @Deprecated - ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false), - /** * Feature that allows parser to recognize set of * "Not-a-Number" (NaN) tokens as legal floating number @@ -208,123 +176,7 @@ public enum Feature { * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_NON_NUMERIC_NUMBERS} instead */ @Deprecated - ALLOW_NON_NUMERIC_NUMBERS(false), - - /** - * Feature allows the support for "missing" values in a JSON array: missing - * value meaning sequence of two commas, without value in-between but only - * optional white space. - * Enabling this feature will expose "missing" values as {@link JsonToken#VALUE_NULL} - * tokens, which typically become Java nulls in arrays and {@link java.util.Collection} - * in data-binding. - *

- * For example, enabling this feature will represent a JSON array ["value1",,"value3",] - * as ["value1", null, "value3", null] - *

- * Since the JSON specification does not allow missing values this is a non-compliant JSON - * feature and is disabled by default. - * - * @since 2.8 - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_MISSING_VALUES} instead - */ - @Deprecated - ALLOW_MISSING_VALUES(false), - - /** - * Feature that determines whether {@link JsonParser} will allow for a single trailing - * comma following the final value (in an Array) or member (in an Object). These commas - * will simply be ignored. - *

- * For example, when this feature is enabled, [true,true,] is equivalent to - * [true, true] and {"a": true,} is equivalent to - * {"a": true}. - *

- * When combined with ALLOW_MISSING_VALUES, this feature takes priority, and - * the final trailing comma in an array declaration does not imply a missing - * (null) value. For example, when both ALLOW_MISSING_VALUES - * and ALLOW_TRAILING_COMMA are enabled, [true,true,] is - * equivalent to [true, true], and [true,true,,] is equivalent to - * [true, true, null]. - *

- * Since the JSON specification does not permit trailing commas, this is a non-standard - * feature, and as such disabled by default. - * - * @since 2.9 - * - * @deprecated Since 2.10 use {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_TRAILING_COMMA} instead - */ - @Deprecated - ALLOW_TRAILING_COMMA(false), - - // // // Validity checks - - /** - * 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), - - // // // Other - - /** - * Feature that determines whether {@link JsonLocation} instances should be constructed - * with reference to source or not. If source reference is included, its type and contents - * are included when `toString()` method is called (most notably when printing out parse - * exception with that location information). If feature is disabled, no source reference - * is passed and source is only indicated as "UNKNOWN". - *

- * Most common reason for disabling this feature is to avoid leaking information about - * internal information; this may be done for security reasons. - * Note that even if source reference is included, only parts of contents are usually - * printed, and not the whole contents. Further, many source reference types can not - * necessarily access contents (like streams), so only type is indicated, not contents. - *

- * Feature is enabled by default, meaning that "source reference" information is passed - * and some or all of the source content may be included in {@link JsonLocation} information - * constructed either when requested explicitly, or when needed for an exception. - * - * @since 2.9 - */ - INCLUDE_SOURCE_IN_LOCATION(true), - - ; + ALLOW_NON_NUMERIC_NUMBERS(false); /** * Whether feature is enabled or disabled by default. @@ -367,6 +219,19 @@ public int getMask() { } } + /* + * /********************************************************** + * /* Minimal generally useful 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; + /* * /********************************************************** * /* Minimal configuration state @@ -380,163 +245,212 @@ public int getMask() { */ protected int _features; + /* + * /********************************************************** + * /* Generic I/O state + * /********************************************************** + */ + /** - * Optional container that holds the request payload which will be displayed on JSON parsing error. - * - * @since 2.8 + * I/O context for this reader. It handles buffer allocation + * for the reader. + */ + final protected IOContext _ioContext; + + /** + * Flag that indicates whether parser is closed or not. Gets + * set when parser is either closed by explicit call + * ({@link #close}) or when end-of-input is reached. */ - protected transient RequestPayload _requestPayload; + protected boolean _closed; /* * /********************************************************** - * /* Construction, configuration, initialization + * /* Current input data * /********************************************************** */ - protected JsonParser() { - } + // Note: type of actual buffer depends on sub-class, can't include - protected JsonParser(int features) { - _features = features; - } + /** + * Pointer to next available character in buffer + */ + protected int _inputPtr; /** - * Accessor for {@link ObjectCodec} associated with this - * parser, if any. Codec is used by {@link #readValueAs(Class)} - * method (and its variants). - * - * @return Codec assigned to this parser, if any; {@code null} if none + * Index of character after last available one in the buffer. + */ + protected int _inputEnd; + + /* + * /********************************************************** + * /* Current input location information + * /********************************************************** */ - 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). - * - * @param oc Codec to assign, if any; {@code null} if none + * Number of characters/bytes that were contained in previous blocks + * (blocks that were already processed prior to the current buffer). */ - public abstract void setCodec(ObjectCodec oc); + protected long _currInputProcessed; /** - * 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. - * - * @return Input source this parser was configured with + * Current row location of current point in input buffer, starting + * from 1, if available. */ - public Object getInputSource() { - return null; - } + protected int _currInputRow = 1; + + /** + * Current index of the first character of the current row in input + * buffer. Needed to calculate column position, if necessary; benefit + * of not having column itself is that this only has to be updated + * once per line. + */ + protected int _currInputRowStart; /* * /********************************************************** - * /* Format support + * /* Information about starting location of event + * /* Reader is pointing to; updated on-demand * /********************************************************** */ + // // // Location info at point when current token was started + /** - * 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. - *

- * If parser does not support specified schema, {@link UnsupportedOperationException} - * is thrown. - * - * @param schema Schema to use - * - * @throws UnsupportedOperationException if parser does not support schema + * Total number of bytes/characters read before start of current token. + * For big (gigabyte-sized) sizes are possible, needs to be long, + * unlike pointers and sizes related to in-memory buffers. */ - public void setSchema(FormatSchema schema) { - throw new UnsupportedOperationException("Parser of type " + getClass().getName() - + " does not support schema of type '" + schema.getSchemaType() + "'"); - } + protected long _tokenInputTotal; /** - * Method for accessing Schema that this parser uses, if any. - * Default implementation returns null. - * - * @return Schema in use by this parser, if any; {@code null} if none - * - * @since 2.1 + * Input row on which current token starts, 1-based */ - public FormatSchema getSchema() { - return null; - } + protected int _tokenInputRow = 1; /** - * 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 + * Column on input row that current token starts; 0-based (although + * in the end it'll be converted to 1-based) */ - public boolean canUseSchema(FormatSchema schema) { - return false; - } + protected int _tokenInputCol; /* * /********************************************************** - * /* Capability introspection + * /* Parsing state * /********************************************************** */ /** - * 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 format-specific codec is needed with this parser; false if a general - * {@link ObjectCodec} is enough - * - * @since 2.1 + * Information about parser context, context in which + * the next token is to be parsed (root, array, object). */ - public boolean requiresCustomCodec() { - return false; - } + protected JsonReadContext _parsingContext; /** - * Accessor for getting metadata on capabilities of this parser, based on - * underlying data format being read (directly or indirectly). - * - * @return Set of read capabilities for content to read via this parser - * - * @since 2.12 + * Secondary token related to the next token after current one; + * used if its type is known. This may be value token that + * follows FIELD_NAME, for example. */ - public JacksonFeatureSet getReadCapabilities() { - return DEFAULT_READ_CAPABILITIES; - } + protected JsonToken _nextToken; /* * /********************************************************** - * /* Versioned + * /* Buffer(s) for local name(s) and text content * /********************************************************** */ /** - * Accessor for getting version of the core package, given a parser instance. - * Left for sub-classes to implement. - * - * @return Version of this generator (derived from version declared for - * {@code jackson-core} jar that contains the class + * Buffer that contains contents of String values, including + * field names if necessary (name split across boundary, + * contains escape sequence, or access needed to char array) */ - @Override - public abstract Version version(); + protected final TextBuffer _textBuffer; + + /** + * Flag set to indicate whether the field name is available + * from the name copy buffer or not (in addition to its String + * representation being available via read context) + */ + protected boolean _nameCopied; + + /** + * ByteArrayBuilder is needed if 'getBinaryValue' is called. If so, + * we better reuse it for remainder of content. + */ + protected ByteArrayBuilder _byteArrayBuilder; + + /** + * We will hold on to decoded binary data, for duration of + * current event, so that multiple calls to + * {@link #getBinaryValue} will not need to decode data more + * than once. + */ + protected byte[] _binaryValue; + + // Numeric value holders: multiple fields used for + // for efficiency + + /** + * Bitfield that indicates which numeric representations + * have been calculated for the current type + */ + protected int _numTypesValid = NR_UNKNOWN; + + // First primitives + + protected int _numberInt; + + protected long _numberLong; + + protected double _numberDouble; + + // And then object types + + protected BigInteger _numberBigInt; + + protected BigDecimal _numberBigDecimal; + + // And then other information about value itself + + /** + * Flag that indicates whether numeric value has a negative + * value. That is, whether its textual representation starts + * with minus character. + */ + protected boolean _numberNegative; + + /** + * Length of integer part of the number, in characters + */ + protected int _intLength; + + /** + * Length of the fractional part (not including decimal + * point or exponent), in characters. + * Not used for pure integer values. + */ + protected int _fractLength; + + /** + * Length of the exponent part of the number, if any, not + * including 'e' marker or sign, just digits. + * Not used for pure integer values. + */ + protected int _expLength; + + /* + * /********************************************************** + * /* Construction, configuration, initialization + * /********************************************************** + */ + + protected JsonParser(IOContext ctxt, int features) { + _ioContext = ctxt; + _textBuffer = ctxt.constructTextBuffer(); + _features = features; + _parsingContext = JsonReadContext.createRootContext(); + } /* * /********************************************************** @@ -547,8 +461,7 @@ public JacksonFeatureSet getReadCapabilities() { /** * 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. + * if parser either owns the input source. * Whether parser owns the input source depends on factory * method that was used to construct instance (so check * {@link JsonFactory} for details, @@ -562,19 +475,20 @@ public JacksonFeatureSet getReadCapabilities() { * @throws IOException if there is either an underlying I/O problem */ @Override - public abstract void close() throws IOException; - - /** - * 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. - * - * @return {@code True} if this parser instance has been closed - */ - public abstract boolean isClosed(); + public final void close() throws IOException { + if (!_closed) { + // 19-Jan-2018, tatu: as per [core#440] need to ensure no more data assumed available + _inputPtr = Math.max(_inputPtr, _inputEnd); + _closed = true; + try { + _closeInput(); + } finally { + // as per [JACKSON-324], do in finally block + // Also, internal buffer(s) can now be released as well + _releaseBuffers(); + } + } + } /* * /********************************************************** @@ -594,7 +508,9 @@ public JacksonFeatureSet getReadCapabilities() { * * @return Stream input context ({@link JsonStreamContext}) associated with this parser */ - public abstract JsonStreamContext getParsingContext(); + public final JsonReadContext getParsingContext() { + return _parsingContext; + } /** * Method that returns location of the last processed input unit (character @@ -613,258 +529,45 @@ public JacksonFeatureSet getReadCapabilities() { * @since 2.13 */ public JsonLocation currentLocation() { - return getCurrentLocation(); + int col = _inputPtr - _currInputRowStart + 1; // 1-based + return new JsonLocation(_contentReference(), -1L, _currInputProcessed + _inputPtr, // bytes, chars + _currInputRow, col); } + /* + * /*************************************************** + * /* Public API, configuration + * /*************************************************** + */ + /** - * Method that return the starting location of the current - * (most recently returned) - * token; that is, the position of the first input unit (character or byte) from input - * that starts the current token. - *

- * Note that the location is not guaranteed to be accurate (although most - * implementation will try their best): some implementations may only - * return {@link JsonLocation#NA} due to not having access - * to input location information (when delegating actual decoding work - * to other library) + * Method for enabling or disabling specified feature + * (check {@link Feature} for list of features) * - * @return Starting location of the token parser currently points to + * @param f Feature to enable or disable + * @param state Whether to enable feature ({@code true}) or disable ({@code false}) * - * @since 2.13 (will eventually replace {@link #getTokenLocation}) + * @return This parser, to allow call chaining */ - public JsonLocation currentTokenLocation() { - return getTokenLocation(); + public JsonParser configure(Feature f, boolean state) { + if (state) + _features |= f.getMask(); + else + _features &= ~f.getMask(); + return this; } - // TODO: deprecate in 2.14 or later /** - * Alias for {@link #currentLocation()}, to be deprecated in later - * Jackson 2.x versions (and removed from Jackson 3.0). + * Method for checking whether specified {@link Feature} is enabled. * - * @return Location of the last processed input unit (byte or character) - */ - public abstract JsonLocation getCurrentLocation(); - - // TODO: deprecate in 2.14 or later - /** - * Alias for {@link #currentTokenLocation()}, to be deprecated in later - * Jackson 2.x versions (and removed from Jackson 3.0). - * - * @return Starting location of the token parser currently points to - */ - public abstract JsonLocation getTokenLocation(); - - /** - * Helper method, usually equivalent to: - * - * getParsingContext().getCurrentValue(); - * - *

- * 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. - * - * @return "Current value" associated with the current input context (state) of this parser - * - * @since 2.13 (added as replacement for older {@link #getCurrentValue()} - */ - public Object currentValue() { - // TODO: implement directly in 2.14 or later, make getCurrentValue() call this - return getCurrentValue(); - } - - /** - * Helper method, usually equivalent to: - * - * getParsingContext().setCurrentValue(v); - * - * - * @param v Current value to assign for the current input context of this parser - * - * @since 2.13 (added as replacement for older {@link #setCurrentValue} - */ - public void assignCurrentValue(Object v) { - // TODO: implement directly in 2.14 or later, make setCurrentValue() call this - setCurrentValue(v); - } - - // TODO: deprecate in 2.14 or later - /** - * Alias for {@link #currentValue()}, to be deprecated in later - * Jackson 2.x versions (and removed from Jackson 3.0). - * - * @return Location of the last processed input unit (byte or character) - */ - public Object getCurrentValue() { - JsonStreamContext ctxt = getParsingContext(); - return (ctxt == null) ? null : ctxt.getCurrentValue(); - } - - // TODO: deprecate in 2.14 or later - /** - * Alias for {@link #assignCurrentValue}, to be deprecated in later - * Jackson 2.x versions (and removed from Jackson 3.0). - * - * @param v Current value to assign for the current input context of this parser - */ - public void setCurrentValue(Object v) { - JsonStreamContext ctxt = getParsingContext(); - if (ctxt != null) { - ctxt.setCurrentValue(v); - } - } - - /* - * /********************************************************** - * /* Buffer handling - * /********************************************************** - */ - - /* - * /*************************************************** - * /* Public API, configuration - * /*************************************************** - */ - - /** - * Method for enabling specified parser feature - * (check {@link Feature} for list of features) - * - * @param f Feature to enable - * - * @return This parser, to allow call chaining - */ - public JsonParser enable(Feature f) { - _features |= f.getMask(); - return this; - } - - /** - * Method for disabling specified feature - * (check {@link Feature} for list of features) - * - * @param f Feature to disable - * - * @return This parser, to allow call chaining - */ - public JsonParser disable(Feature f) { - _features &= ~f.getMask(); - return this; - } - - /** - * Method for enabling or disabling specified feature - * (check {@link Feature} for list of features) - * - * @param f Feature to enable or disable - * @param state Whether to enable feature ({@code true}) or disable ({@code false}) - * - * @return This parser, to allow call chaining - */ - 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. - * - * @param f Feature to check - * - * @return {@code True} if feature is enabled; {@code false} otherwise + * @param f Feature to check + * + * @return {@code True} if feature is enabled; {@code false} otherwise */ public boolean isEnabled(Feature f) { return f.enabledIn(_features); } - /** - * Method for checking whether specified {@link Feature} is enabled. - * - * @param f Feature to check - * - * @return {@code True} if feature is enabled; {@code false} otherwise - * - * @since 2.10 - */ - public boolean isEnabled(StreamReadFeature f) { - return f.mappedFeature().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 - * - * @param mask Bit mask that defines set of features to enable - * - * @return This parser, to allow call chaining - * - * @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 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 - * - * @return This parser, to allow call chaining - * - * @since 2.6 - */ - public JsonParser overrideStdFeatures(int values, int mask) { - int newState = (_features & ~mask) | (values & mask); - return setFeatureMask(newState); - } - - /** - * 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. - *

- * Default implementation will simply throw an exception to indicate that - * the parser 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 - * - * @return This parser, to allow call chaining - * - * @since 2.6 - */ - public JsonParser overrideFormatFeatures(int values, int mask) { - // 08-Oct-2018, tatu: For 2.10 we actually do get `JsonReadFeature`s, although they - // are (for 2.x only, not for 3.x) mapper to legacy settings. So do not throw exception: - // throw new IllegalArgumentException("No FormatFeatures defined for parser of type "+getClass().getName()); - return this; - } - /* * /********************************************************** * /* Public API, traversal @@ -885,28 +588,6 @@ public JsonParser overrideFormatFeatures(int values, int mask) { */ public abstract JsonToken nextToken() throws IOException; - /** - * 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) - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public abstract JsonToken nextValue() throws IOException; - /** * Method that will skip all child tokens of an array or * object token that the parser currently points to, @@ -926,27 +607,67 @@ public JsonParser overrideFormatFeatures(int values, int mask) { * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - public abstract JsonParser skipChildren() throws IOException; + public final 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; + } + // 23-May-2018, tatu: [core#463] Need to consider non-blocking case... + } else if (t == JsonToken.NOT_AVAILABLE) { + // Nothing much we can do except to either return `null` (which seems wrong), + // or, what we actually do, signal error + _reportError("Not enough content available for `skipChildren()`: non-blocking parser? (%s)", + getClass().getName()); + } + } + } /** - * Method that may be used to force full handling of the current token - * so that even if lazy processing is enabled, the whole contents are - * read for possible retrieval. This is usually used to ensure that - * the token end location is available, as well as token contents - * (similar to what calling, say {@link #getTextCharacters()}, would - * achieve). - *

- * Note that for many dataformat implementations this method - * will not do anything; this is the default implementation unless - * overridden by sub-classes. + * Method sub-classes need to implement for verifying that end-of-content + * is acceptable at current input position. * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems + * @throws JsonParseException If end-of-content is not acceptable (for example, + * missing end-object or end-array tokens) + */ + protected final void _handleEOF() throws JsonParseException { + if (!_parsingContext.inRoot()) { + String marker = _parsingContext.inArray() ? "Array" : "Object"; + _reportInvalidEOF(String.format(": expected close marker for %s (start marker at %s)", marker, + _parsingContext.startLocation(_contentReference())), null); + } + } + + /** + * @return If no exception is thrown, {@code -1} which is used as marked for "end-of-input" * - * @since 2.8 + * @throws JsonParseException If check on {@code _handleEOF()} fails; usually because + * the current context is not root context (missing end markers in content) + * + * @since 2.4 */ - public void finishToken() throws IOException { - // nothing + protected final int _eofAsNextChar() throws JsonParseException { + _handleEOF(); + return -1; } /* @@ -968,234 +689,16 @@ public void finishToken() throws IOException { * * @since 2.8 */ - public JsonToken currentToken() { - return getCurrentToken(); + public final JsonToken currentToken() { + return _currToken; } - /** - * Method similar to {@link #getCurrentToken()} but that returns an - * int instead of {@link JsonToken} (enum value). - *

- * 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.8 - * - * @return {@code int} matching one of constants from {@link JsonTokenId}. - */ - public int currentTokenId() { - return getCurrentTokenId(); - } - - // TODO: deprecate in 2.14 or later - /** - * Alias for {@link #currentToken()}, may be deprecated sometime after - * Jackson 2.13 (will be removed from 3.0). - * - * @return Type of the token this parser currently points to, - * if any: null before any tokens have been read, and - */ - public abstract JsonToken getCurrentToken(); - - /** - * Deprecated alias for {@link #currentTokenId()}. - * - * @return {@code int} matching one of constants from {@link JsonTokenId}. - * - * @deprecated Since 2.12 use {@link #currentTokenId} instead - */ - @Deprecated - 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 currentTokenId() == id - * - * but may be more efficiently implemented. - *

- * Note that no traversal or conversion is performed; so in some - * cases calling method like {@link #isExpectedStartArrayToken()} - * is necessary instead. - * - * @param id Token id to match (from (@link JsonTokenId}) - * - * @return {@code True} if the parser current points to specified token - * - * @since 2.5 - */ - public abstract boolean hasTokenId(int id); - - /** - * Method that is functionally equivalent to: - * - * return currentToken() == t - * - * but may be more efficiently implemented. - *

- * Note that no traversal or conversion is performed; so in some - * cases calling method like {@link #isExpectedStartArrayToken()} - * is necessary instead. - * - * @param t Token to match - * - * @return {@code True} if the parser current points to specified token - * - * @since 2.6 - */ - public abstract boolean hasToken(JsonToken t); - - /** - * 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: - *

-     *   currentToken() == 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}); - * {@code false} if not - */ - public boolean isExpectedStartArrayToken() { - return currentToken() == JsonToken.START_ARRAY; - } - - /** - * Similar to {@link #isExpectedStartArrayToken()}, but checks whether stream - * currently points to {@link JsonToken#START_OBJECT}. - * - * @return True if the current token can be considered as a - * start-array marker (such {@link JsonToken#START_OBJECT}); - * {@code false} if not - * - * @since 2.5 - */ - public boolean isExpectedStartObjectToken() { - return currentToken() == JsonToken.START_OBJECT; - } - - /** - * Similar to {@link #isExpectedStartArrayToken()}, but checks whether stream - * currently points to {@link JsonToken#VALUE_NUMBER_INT}. - *

- * The initial use case is for XML backend to efficiently (attempt to) coerce - * textual content into numbers. - * - * @return True if the current token can be considered as a - * start-array marker (such {@link JsonToken#VALUE_NUMBER_INT}); - * {@code false} if not - * - * @since 2.12 - */ - public boolean isExpectedNumberIntToken() { - return currentToken() == JsonToken.VALUE_NUMBER_INT; - } - - /** - * Access for checking whether current token is a numeric value token, but - * one that is of "not-a-number" (NaN) variety (including both "NaN" AND - * positive/negative infinity!): not supported by all formats, - * but often supported for {@link JsonToken#VALUE_NUMBER_FLOAT}. - * NOTE: roughly equivalent to calling !Double.isFinite() - * on value you would get from calling {@link #getDoubleValue()}. - * - * @return {@code True} if the current token is of type {@link JsonToken#VALUE_NUMBER_FLOAT} - * but represents a "Not a Number"; {@code false} for other tokens and regular - * floating-point numbers - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - * - * @since 2.9 - */ - public boolean isNaN() throws IOException { - return false; - } - - /* - * /********************************************************** - * /* 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. - *

- * 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. - * - * @return Last cleared token, if any; {@code null} otherwise - */ - 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 * /********************************************************** */ - // TODO: deprecate in 2.14 or later - /** - * Alias of {@link #currentName()}. - * - * @return Name of the current field in the parsing context - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public abstract String getCurrentName() throws IOException; - /** * Method that can be called to get the name associated with * the current token: for {@link JsonToken#FIELD_NAME}s it will @@ -1204,14 +707,17 @@ public boolean isNaN() throws IOException { * and for others (array values, root-level values) null. * * @return Name of the current field in the parsing context - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - * * @since 2.10 */ - public String currentName() throws IOException { - return getCurrentName(); + public final String currentName() { + // [JACKSON-395]: start markers require information from parent + if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { + JsonReadContext parent = _parsingContext.getParent(); + if (parent != null) { + return parent.getCurrentName(); + } + } + return _parsingContext.getCurrentName(); } /** @@ -1228,239 +734,12 @@ public String currentName() throws IOException { */ public abstract String getText() throws IOException; - /** - * Method to read the textual representation of the current token in chunks and - * pass it to the given Writer. - * Conceptually same as calling: - *

-     *  writer.write(parser.getText());
-     *
- * but should typically be more efficient as longer content does need to - * be combined into a single String to return, and write - * can occur directly from intermediate buffers Jackson uses. - * - * @param writer Writer to write textual content to - * - * @return The number of characters written to the Writer - * - * @throws IOException for low-level read issues or writes using passed - * {@code writer}, or - * {@link JsonParseException} for decoding problems - * - * @since 2.8 - */ - public int getText(Writer writer) throws IOException, UnsupportedOperationException { - String str = getText(); - if (str == null) { - return 0; - } - writer.write(str); - return str.length(); - } - - /** - * 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). - * - * @return Buffer that contains the current textual value (but not necessarily - * at offset 0, and not necessarily until the end of buffer) - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. - * - * @return Numeric value of the current token in its most optimal - * representation - * - * @throws IOException Problem with access: {@link JsonParseException} if - * the current token is not numeric, or if decoding of the value fails - * (invalid format for numbers); plain {@link IOException} if underlying - * content read fails (possible if values are extracted lazily) - */ - public abstract Number getNumberValue() throws IOException; - - /** - * Method similar to {@link #getNumberValue} with the difference that - * for floating-point numbers value returned may be {@link BigDecimal} - * if the underlying format does not store floating-point numbers using - * native representation: for example, textual formats represent numbers - * as Strings (which are 10-based), and conversion to {@link Double} - * is potentially lossy operation. - *

- * Default implementation simply returns {@link #getNumberValue()} - * - * @return Numeric value of the current token using most accurate representation - * - * @throws IOException Problem with access: {@link JsonParseException} if - * the current token is not numeric, or if decoding of the value fails - * (invalid format for numbers); plain {@link IOException} if underlying - * content read fails (possible if values are extracted lazily) - * - * @since 2.12 - */ - public Number getNumberValueExact() throws IOException { - return getNumberValue(); - } - - /** - * 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. - * - * @return Type of current number, if parser points to numeric token; {@code null} otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. - * Note that in addition to "natural" input range of {@code [-128, 127]}, - * this also allows "unsigned 8-bit byte" values {@code [128, 255]}: - * but for this range value will be translated by truncation, leading - * to sign change. - *

- * 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 - * {@code [-128, 255]}, - * a {@link InputCoercionException} - * will be thrown to indicate numeric overflow/underflow. - * - * @return Current number value as {@code byte} (if numeric token within - * range of {@code [-128, 255]}); otherwise exception thrown - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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 new InputCoercionException(this, - String.format("Numeric value (%s) out of range of Java byte", getText()), JsonToken.VALUE_NUMBER_INT, - Byte.TYPE); - } - 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 InputCoercionException} - * will be thrown to indicate numeric overflow/underflow. - * - * @return Current number value as {@code short} (if numeric token within - * Java 16-bit signed {@code short} range); otherwise exception thrown - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public short getShortValue() throws IOException { - int value = getIntValue(); - if (value < MIN_SHORT_I || value > MAX_SHORT_I) { - throw new InputCoercionException(this, - String.format("Numeric value (%s) out of range of Java short", getText()), JsonToken.VALUE_NUMBER_INT, - Short.TYPE); - } - return (short) value; - } - /** * Numeric accessor that can be called when the current * token is of type {@link JsonToken#VALUE_NUMBER_INT} and @@ -1480,7 +759,17 @@ public short getShortValue() throws IOException { * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - public abstract int getIntValue() throws IOException; + public final int getIntValue() throws IOException { + if ((_numTypesValid & NR_INT) == 0) { + if (_numTypesValid == NR_UNKNOWN) { // not parsed at all + return _parseIntValue(); + } + if ((_numTypesValid & NR_INT) == 0) { // wasn't an int natively? + convertNumberToInt(); // let's make it so, if possible + } + } + return _numberInt; + } /** * Numeric accessor that can be called when the current @@ -1501,24 +790,17 @@ public short getShortValue() throws IOException { * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - 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. - * - * @return Current number value as {@link BigInteger} (if numeric token); - * otherwise exception thrown - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public abstract BigInteger getBigIntegerValue() throws IOException; + public final long getLongValue() throws IOException { + if ((_numTypesValid & NR_LONG) == 0) { + if (_numTypesValid == NR_UNKNOWN) { + _parseNumericValue(NR_LONG); + } + if ((_numTypesValid & NR_LONG) == 0) { + convertNumberToLong(); + } + } + return _numberLong; + } /** * Numeric accessor that can be called when the current @@ -1539,7 +821,19 @@ public short getShortValue() throws IOException { * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - public abstract float getFloatValue() throws IOException; + public final float getFloatValue() throws IOException { + double value = getDoubleValue(); + /* + * 22-Jan-2009, tatu: Bounds/range checks would be tricky + * here, so let's not bother even trying... + */ + /* + * if (value < -Float.MAX_VALUE || value > MAX_FLOAT_D) { + * _reportError("Numeric value ("+getText()+") out of range of Java float"); + * } + */ + return (float) value; + } /** * Numeric accessor that can be called when the current @@ -1560,21 +854,17 @@ public short getShortValue() throws IOException { * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - 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. - * - * @return Current number value as {@link BigDecimal} (if numeric token); - * otherwise exception thrown - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public abstract BigDecimal getDecimalValue() throws IOException; + public final double getDoubleValue() throws IOException { + if ((_numTypesValid & NR_DOUBLE) == 0) { + if (_numTypesValid == NR_UNKNOWN) { + _parseNumericValue(NR_DOUBLE); + } + if ((_numTypesValid & NR_DOUBLE) == 0) { + convertNumberToDouble(); + } + } + return _numberDouble; + } /* * /********************************************************** @@ -1597,36 +887,13 @@ public short getShortValue() throws IOException { * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - public boolean getBooleanValue() throws IOException { + public final boolean getBooleanValue() throws IOException { JsonToken t = currentToken(); 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)) - .withRequestPayload(_requestPayload); - } - - /** - * 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). One exception - * is access to binary content (whether via base64 encoding or not) - * which typically is accessible using this method, as well as - * {@link #getBinaryValue()}. - * - * @return Embedded value (usually of "native" type supported by format) - * for the current token, if any; {@code null otherwise} - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public Object getEmbeddedObject() throws IOException { - return null; + throw new JsonParseException(this, String.format("Current token (%s) not of boolean type", t)); } /* @@ -1647,231 +914,22 @@ public Object getEmbeddedObject() throws IOException { * 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 - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. - * - * @return Decoded binary data - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public byte[] getBinaryValue() throws IOException { - return getBinaryValue(Base64Variants.getDefaultVariant()); - } - - /** - * 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} - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - * - * @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 - * Java {@code int} value. - * 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. - * - * @return {@code int} value current token is converted to, if possible; exception thrown - * otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. - * - * @param def Default value to return if conversion to {@code int} is not possible - * - * @return {@code int} value current token is converted to, if possible; {@code def} otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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 a long (including structured type - * markers like start/end Object/Array) - * default value of 0L will be returned; no exceptions are thrown. - * - * @return {@code long} value current token is converted to, if possible; exception thrown - * otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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 a long (including structured type - * markers like start/end Object/Array) - * specified def will be returned; no exceptions are thrown. - * - * @param def Default value to return if conversion to {@code long} is not possible - * - * @return {@code long} value current token is converted to, if possible; {@code def} otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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 floating - * point parsing rules. - *

- * If representation can not be converted to a double (including structured types - * like Objects and Arrays), - * default value of 0.0 will be returned; no exceptions are thrown. - * - * @return {@code double} value current token is converted to, if possible; exception thrown - * otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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 floating - * point parsing rules. - *

- * If representation can not be converted to a double (including structured types - * like Objects and Arrays), - * specified def will be returned; no exceptions are thrown. - * - * @param def Default value to return if conversion to {@code double} is not possible - * - * @return {@code double} value current token is converted to, if possible; {@code def} otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - 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. + * textual content during decoding. + * Decoded binary content, however, will be retained until + * parser is advanced to the next event. * - * @return {@code boolean} value current token is converted to, if possible; exception thrown - * otherwise + * @return Decoded binary data * * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems */ - public boolean getValueAsBoolean() throws IOException { - return getValueAsBoolean(false); - } + public abstract byte[] getBinaryValue() throws IOException; - /** - * 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. - * - * @param def Default value to return if conversion to {@code boolean} is not possible - * - * @return {@code boolean} value current token is converted to, if possible; {@code def} otherwise - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems + /* + * /********************************************************** + * /* Public API, access to token information, coercion/conversion + * /********************************************************** */ - public boolean getValueAsBoolean(boolean def) throws IOException { - return def; - } /** * Method that will try to convert value of current token to a @@ -1902,7 +960,7 @@ public String getValueAsString() throws IOException { * like Objects and Arrays and {@code null} token), specified default value * will be returned; no exceptions are thrown. * - * @param def Default value to return if conversion to {@code String} is not possible + * @param defaultValue Default value to return if conversion to {@code String} is not possible * * @return {@link String} value current token is converted to, if possible; {@code def} otherwise * @@ -1911,204 +969,724 @@ public String getValueAsString() throws IOException { * * @since 2.1 */ - public abstract String getValueAsString(String def) throws IOException; + public String getValueAsString(String defaultValue) throws IOException { + if (_currToken == JsonToken.VALUE_STRING) { + return getText(); + } + if (_currToken == JsonToken.FIELD_NAME) { + return currentName(); + } + if (_currToken == null || _currToken == JsonToken.VALUE_NULL || !_currToken.isScalarValue()) { + return defaultValue; + } + return getText(); + } /* * /********************************************************** - * /* Public API, Native Ids (type, object) + * /* Internal methods * /********************************************************** */ /** - * 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. + * Helper method for constructing {@link JsonParseException}s + * based on current state of the parser * - * @return {@code True} if the format being read supports native Object Ids; - * {@code false} if not + * @param msg Base exception message to construct exception with * - * @since 2.3 + * @return {@link JsonParseException} constructed */ - public boolean canReadObjectId() { - return false; + protected final JsonParseException _constructError(String msg) { + return new JsonParseException(this, msg); } - /** - * 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. - * - * @return {@code True} if the format being read supports native Type Ids; - * {@code false} if not - * - * @since 2.3 + /* + * /********************************************************** + * /* Base64 decoding + * /********************************************************** */ - 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. - * - * @return Native Object id associated with the current token, if any; {@code null} if none + * Helper method that can be used for base64 decoding in cases where + * encoded content has already been read as a String. * + * @param str String to decode + * @param builder Builder used to buffer binary content decoded * @throws IOException for low-level read issues, or * {@link JsonParseException} for decoding problems - * - * @since 2.3 */ - public Object getObjectId() throws IOException { - return null; + protected final void _decodeBase64(String str, ByteArrayBuilder builder) throws IOException { + try { + Base64Variants.getDefaultVariant().decode(str, builder); + } catch (IllegalArgumentException e) { + _reportError(e.getMessage()); + } } + /* + * /********************************************************** + * /* Abstract methods for sub-classes to implement + * /********************************************************** + */ + + protected abstract void _closeInput() throws IOException; + + /* + * /********************************************************** + * /* Low-level reading, other + * /********************************************************** + */ + /** - * 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. - * - * @return Native Type Id associated with the current token, if any; {@code null} if none - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems + * 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). * - * @since 2.3 + * @throws IOException Not thrown by base implementation but could be thrown + * by sub-classes + */ + protected void _releaseBuffers() throws IOException { + _textBuffer.releaseBuffers(); + } + + /* + * /********************************************************** + * /* Internal/package methods: shared/reusable builders + * /********************************************************** + */ + + public final ByteArrayBuilder _getByteArrayBuilder() { + if (_byteArrayBuilder == null) { + _byteArrayBuilder = new ByteArrayBuilder(); + } else { + _byteArrayBuilder.reset(); + } + return _byteArrayBuilder; + } + + /* + * /********************************************************** + * /* Methods from former JsonNumericParserBase + * /********************************************************** */ - public Object getTypeId() throws IOException { - return null; + + // // // Life-cycle of number-parsing + + protected final JsonToken reset(boolean negative, int intLen, int fractLen, int expLen) { + if (fractLen < 1 && expLen < 1) { // integer + return resetInt(negative, intLen); + } + return resetFloat(negative, intLen, fractLen, expLen); + } + + protected final JsonToken resetInt(boolean negative, int intLen) { + _numberNegative = negative; + _intLength = intLen; + _fractLength = 0; + _expLength = 0; + _numTypesValid = NR_UNKNOWN; // to force parsing + return JsonToken.VALUE_NUMBER_INT; + } + + protected final JsonToken resetFloat(boolean negative, int intLen, int fractLen, int expLen) { + _numberNegative = negative; + _intLength = intLen; + _fractLength = fractLen; + _expLength = expLen; + _numTypesValid = NR_UNKNOWN; // to force parsing + return JsonToken.VALUE_NUMBER_FLOAT; + } + + protected final JsonToken resetAsNaN(String valueStr, double value) { + _textBuffer.resetWithString(valueStr); + _numberDouble = value; + _numTypesValid = NR_DOUBLE; + return JsonToken.VALUE_NUMBER_FLOAT; } /* * /********************************************************** - * /* Public API, optional data binding functionality + * /* Conversion from textual to numeric representation * /********************************************************** */ /** - * 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 Boolean}). - * Note: method can only be called if the parser has - * an object codec assigned; this is true for parsers constructed - * by MappingJsonFactory (from "jackson-databind" jar) - * but not for {@link JsonFactory} (unless its setCodec - * method has been explicitly called). - *

- * 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. - * - * @param Nominal type parameter for value type + * Method that will parse actual numeric value out of a syntactically + * valid number value. Type it will parse into depends on whether + * it is a floating point number, as well as its magnitude: smallest + * legal type (of ones available) is used for efficiency. * - * @param valueType Java type to read content as (passed to ObjectCodec that - * deserializes content) + * @param expType Numeric type that we will immediately need, if any; + * mostly necessary to optimize handling of floating point numbers * - * @return Java value read from content + * @throws IOException If there are problems reading content + * @throws JsonParseException If there are problems decoding number value + */ + private void _parseNumericValue(int expType) throws IOException { + // 12-Jun-2020, tatu: Sanity check to prevent more cryptic error for this case. + // (note: could alternatively see if TextBuffer has aggregated contents, avoid + // exception -- but that might be more confusing) + if (_closed) { + _reportError("Internal error: _parseNumericValue called when parser instance closed"); + } + + // Int or float? + if (_currToken == JsonToken.VALUE_NUMBER_INT) { + final int len = _intLength; + // First: optimization for simple int + if (len <= 9) { + _numberInt = _textBuffer.contentsAsInt(_numberNegative); + _numTypesValid = NR_INT; + return; + } + if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls + long l = _textBuffer.contentsAsLong(_numberNegative); + // Might still fit in int, need to check + if (len == 10) { + if (_numberNegative) { + if (l >= MIN_INT_L) { + _numberInt = (int) l; + _numTypesValid = NR_INT; + return; + } + } else { + if (l <= MAX_INT_L) { + _numberInt = (int) l; + _numTypesValid = NR_INT; + return; + } + } + } + _numberLong = l; + _numTypesValid = NR_LONG; + return; + } + _parseSlowInt(expType); + return; + } + if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { + _parseSlowFloat(); + return; + } + _reportError("Current token (%s) not numeric, can not use numeric value accessors", _currToken); + } + + // @since 2.6 + private int _parseIntValue() throws IOException { + // 12-Jun-2020, tatu: Sanity check to prevent more cryptic error for this case. + // (note: could alternatively see if TextBuffer has aggregated contents, avoid + // exception -- but that might be more confusing) + if (_closed) { + _reportError("Internal error: _parseNumericValue called when parser instance closed"); + } + // Inlined variant of: _parseNumericValue(NR_INT) + if (_currToken == JsonToken.VALUE_NUMBER_INT) { + if (_intLength <= 9) { + int i = _textBuffer.contentsAsInt(_numberNegative); + _numberInt = i; + _numTypesValid = NR_INT; + return i; + } + } + // if not optimizable, use more generic + _parseNumericValue(NR_INT); + if ((_numTypesValid & NR_INT) == 0) { + convertNumberToInt(); + } + return _numberInt; + } + + private void _parseSlowFloat() throws IOException { + try { + _numberDouble = _textBuffer.contentsAsDouble(); + _numTypesValid = NR_DOUBLE; + } catch (NumberFormatException nex) { + // Can this ever occur? Due to overflow, maybe? + _wrapError("Malformed numeric value (" + _longNumberDesc(_textBuffer.contentsAsString()) + ")", nex); + } + } + + private void _parseSlowInt(int expType) throws IOException { + String numStr = _textBuffer.contentsAsString(); + try { + int len = _intLength; + char[] buf = _textBuffer.getTextBuffer(); + int offset = _textBuffer.getTextOffset(); + if (_numberNegative) { + ++offset; + } + // Some long cases still... + if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) { + // Probably faster to construct a String, call parse, than to use BigInteger + _numberLong = Long.parseLong(numStr); + _numTypesValid = NR_LONG; + } else { + // 16-Oct-2018, tatu: Need to catch "too big" early due to [jackson-core#488] + if ((expType == NR_INT) || (expType == NR_LONG)) { + _reportTooLongIntegral(expType, numStr); + } + if ((expType == NR_DOUBLE) || (expType == NR_FLOAT)) { + _numberDouble = NumberInput.parseDouble(numStr); + _numTypesValid = NR_DOUBLE; + } else { + // nope, need the heavy guns... (rare case) + _numberBigInt = new BigInteger(numStr); + _numTypesValid = NR_BIGINT; + } + } + } catch (NumberFormatException nex) { + // Can this ever occur? Due to overflow, maybe? + _wrapError("Malformed numeric value (" + _longNumberDesc(numStr) + ")", nex); + } + } + + // @since 2.9.8 + private void _reportTooLongIntegral(int expType, String rawNum) throws IOException { + if (expType == NR_INT) { + reportOverflowInt(rawNum); + } else { + reportOverflowLong(rawNum); + } + } + + /* + * /********************************************************** + * /* Numeric conversions + * /********************************************************** + */ + + private void convertNumberToInt() throws IOException { + // First, converting from long ought to be easy + if ((_numTypesValid & NR_LONG) != 0) { + // Let's verify it's lossless conversion by simple roundtrip + int result = (int) _numberLong; + if (((long) result) != _numberLong) { + reportOverflowInt(getText(), currentToken()); + } + _numberInt = result; + } else if ((_numTypesValid & NR_BIGINT) != 0) { + if (BI_MIN_INT.compareTo(_numberBigInt) > 0 || BI_MAX_INT.compareTo(_numberBigInt) < 0) { + reportOverflowInt(); + } + _numberInt = _numberBigInt.intValue(); + } else if ((_numTypesValid & NR_DOUBLE) != 0) { + // Need to check boundaries + if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) { + reportOverflowInt(); + } + _numberInt = (int) _numberDouble; + } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { + if (BD_MIN_INT.compareTo(_numberBigDecimal) > 0 || BD_MAX_INT.compareTo(_numberBigDecimal) < 0) { + reportOverflowInt(); + } + _numberInt = _numberBigDecimal.intValue(); + } else { + _throwInternal(); + } + _numTypesValid |= NR_INT; + } + + private void convertNumberToLong() throws IOException { + if ((_numTypesValid & NR_INT) != 0) { + _numberLong = _numberInt; + } else if ((_numTypesValid & NR_BIGINT) != 0) { + if (BI_MIN_LONG.compareTo(_numberBigInt) > 0 || BI_MAX_LONG.compareTo(_numberBigInt) < 0) { + reportOverflowLong(); + } + _numberLong = _numberBigInt.longValue(); + } else if ((_numTypesValid & NR_DOUBLE) != 0) { + // Need to check boundaries + if (_numberDouble < MIN_LONG_D || _numberDouble > MAX_LONG_D) { + reportOverflowLong(); + } + _numberLong = (long) _numberDouble; + } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { + if (BD_MIN_LONG.compareTo(_numberBigDecimal) > 0 || BD_MAX_LONG.compareTo(_numberBigDecimal) < 0) { + reportOverflowLong(); + } + _numberLong = _numberBigDecimal.longValue(); + } else { + _throwInternal(); + } + _numTypesValid |= NR_LONG; + } + + private void convertNumberToDouble() { + /* + * 05-Aug-2008, tatus: Important note: this MUST start with + * more accurate representations, since we don't know which + * value is the original one (others get generated when + * requested) + */ + + if ((_numTypesValid & NR_BIGDECIMAL) != 0) { + _numberDouble = _numberBigDecimal.doubleValue(); + } else if ((_numTypesValid & NR_BIGINT) != 0) { + _numberDouble = _numberBigInt.doubleValue(); + } else if ((_numTypesValid & NR_LONG) != 0) { + _numberDouble = (double) _numberLong; + } else if ((_numTypesValid & NR_INT) != 0) { + _numberDouble = _numberInt; + } else { + _throwInternal(); + } + _numTypesValid |= NR_DOUBLE; + } + + /* + * /********************************************************** + * /* Error reporting + * /********************************************************** + */ + + protected final void reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException { + String msg = "Unexpected character (" + _getCharDesc(ch) + ") in numeric value"; + if (comment != null) { + msg += ": " + comment; + } + _reportError(msg); + } + + /** + * Method called to throw an exception for input token that looks like a number + * based on first character(s), but is not valid according to rules of format. + * In case of JSON this also includes invalid forms like positive sign and + * leading zeroes. * - * @throws IOException if there is either an underlying I/O problem or decoding - * issue at format layer + * @throws JsonParseException Exception that describes problem with number validity */ - public T readValueAs(Class valueType) throws IOException { - return _codec().readValue(this, valueType); + protected final void reportInvalidNumber() throws JsonParseException { + _reportError("Invalid numeric value: Leading zeroes not allowed"); } /** - * Method to deserialize JSON content into a Java type, reference - * to which is passed as argument. Type is passed using so-called - * "super type token" - * and specifically needs to be used if the root type is a - * parameterized (generic) container type. - * Note: method can only be called if the parser has - * an object codec assigned; this is true for parsers constructed - * by MappingJsonFactory (defined in 'jackson-databind' bundle) - * but not for {@link JsonFactory} (unless its setCodec - * method has been explicitly called). - *

- * 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. + * Method called to throw an exception for integral (not floating point) input + * token with value outside of Java signed 32-bit range when requested as {@code int}. + * Result will be {@link InputCoercionException} being thrown. * - * @param Nominal type parameter for value type + * @throws JsonParseException Exception that describes problem with number range validity + */ + private void reportOverflowInt() throws IOException { + reportOverflowInt(getText()); + } + + // @since 2.10 + private void reportOverflowInt(String numDesc) throws IOException { + reportOverflowInt(numDesc, currentToken()); + } + + // @since 2.10 + private void reportOverflowInt(String numDesc, JsonToken inputType) throws IOException { + String msg = String.format("Numeric value (%s) out of range of int (%d - %s)", _longIntegerDesc(numDesc), + Integer.MIN_VALUE, Integer.MAX_VALUE); + throw new InputCoercionException(this, msg, inputType, Integer.TYPE); + } + + /** + * Method called to throw an exception for integral (not floating point) input + * token with value outside of Java signed 64-bit range when requested as {@code long}. + * Result will be {@link InputCoercionException} being thrown. * - * @param valueTypeRef Java type to read content as (passed to ObjectCodec that - * deserializes content) + * @throws JsonParseException Exception that describes problem with number range validity + */ + private void reportOverflowLong() throws IOException { + reportOverflowLong(getText()); + } + + // @since 2.10 + private void reportOverflowLong(String numDesc) throws IOException { + String msg = String.format("Numeric value (%s) out of range of long (%d - %s)", _longIntegerDesc(numDesc), + Long.MIN_VALUE, Long.MAX_VALUE); + throw new InputCoercionException(this, msg, _currToken, Long.TYPE); + } + + // @since 2.9.8 + private String _longIntegerDesc(String rawNum) { + int rawLen = rawNum.length(); + if (rawLen < 1000) { + return rawNum; + } + if (rawNum.startsWith("-")) { + rawLen -= 1; + } + return String.format("[Integer with %d digits]", rawLen); + } + + // @since 2.9.8 + private String _longNumberDesc(String rawNum) { + int rawLen = rawNum.length(); + if (rawLen < 1000) { + return rawNum; + } + if (rawNum.startsWith("-")) { + rawLen -= 1; + } + return String.format("[number with %d characters]", rawLen); + } + + protected void _reportUnexpectedChar(int ch, String comment) throws JsonParseException { + if (ch < 0) { // sanity check + _reportInvalidEOF(); + } + String msg = String.format("Unexpected character (%s)", _getCharDesc(ch)); + if (comment != null) { + msg += ": " + comment; + } + _reportError(msg); + } + + protected void _reportInvalidEOF() throws JsonParseException { + _reportInvalidEOF(" in " + _currToken, _currToken); + } + + // @since 2.8 + protected void _reportInvalidEOFInValue(JsonToken type) throws JsonParseException { + String msg; + if (type == JsonToken.VALUE_STRING) { + msg = " in a String value"; + } else if ((type == JsonToken.VALUE_NUMBER_INT) || (type == JsonToken.VALUE_NUMBER_FLOAT)) { + msg = " in a Number value"; + } else { + msg = " in a value"; + } + _reportInvalidEOF(msg, type); + } + + // @since 2.8 + protected void _reportInvalidEOF(String msg, JsonToken currToken) throws JsonParseException { + throw new JsonEOFException(this, currToken, "Unexpected end-of-input" + msg); + } + + 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); + } + + /* + * /********************************************************** + * /* Error reporting, generic + * /********************************************************** + */ + + private 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); + } + + // @since 2.9 + protected final void _reportError(String msg, Object arg) throws JsonParseException { + throw _constructError(String.format(msg, arg)); + } + + // @since 2.9 + protected final void _reportError(Object arg1, Object arg2) throws JsonParseException { + throw _constructError(String.format("Unrecognized token '%s': was expecting %s", arg1, arg2)); + } + + private void _wrapError(String msg, Throwable t) throws JsonParseException { + throw _constructError(msg, t); + } + + private static void _throwInternal() { + throw new RuntimeException("Internal error: this code path should never get executed"); + } + + private JsonParseException _constructError(String msg, Throwable t) { + return new JsonParseException(this, msg, t); + } + + protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException { + JsonReadContext ctxt = getParsingContext(); + _reportError(String.format("Unexpected close marker '%s': expected '%c' (for %s starting at %s)", (char) actCh, + expCh, ctxt.typeDesc(), ctxt.startLocation(_contentReference()))); + } + + protected char _handleUnrecognizedCharacterEscape(char ch) throws JsonProcessingException { + _reportError("Unrecognized character escape " + _getCharDesc(ch)); + return ch; + } + + /** + * Method called to report a problem with unquoted control character.. * - * @return Java value read from content + * @param i Invalid control character + * @param ctxtDesc Addition description of context to use in exception message * - * @throws IOException if there is either an underlying I/O problem or decoding - * issue at format layer + * @throws JsonParseException explaining the problem */ - @SuppressWarnings("unchecked") - public T readValueAs(TypeReference valueTypeRef) throws IOException { - return (T) _codec().readValue(this, valueTypeRef); + protected void _throwUnquotedSpace(int i, String ctxtDesc) throws JsonParseException { + // JACKSON-208; possible to allow unquoted control chars: + if (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 ObjectCodec _codec() { - ObjectCodec c = getCodec(); - if (c == null) { - throw new IllegalStateException("No ObjectCodec defined for parser, needed for deserialization"); + /** + * @return Description to use as "valid JSON values" in an exception message about + * invalid (unrecognized) JSON value: called when parser finds something that + * does not look like a value or separator. + * + * @since 2.10 + */ + @SuppressWarnings("deprecation") + protected String _validJsonValueList() { + if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { + return "(JSON String, Number (or 'NaN'/'Infinity'/'+Infinity'/'-Infinity'), Array, Object or token 'null', 'true' or 'false')"; } - return c; + return "(JSON String, Number, Array, Object or token 'null', 'true' or 'false')"; } /* * /********************************************************** - * /* Internal methods + * /* Base64 handling support * /********************************************************** */ /** - * Helper method for constructing {@link JsonParseException}s - * based on current state of the parser + * Method that sub-classes must implement to support escaped sequences + * in base64-encoded sections. + * Sub-classes that do not need base64 support can leave this as is * - * @param msg Base exception message to construct exception with + * @return Character decoded, if any * - * @return {@link JsonParseException} constructed + * @throws IOException If escape decoding fails */ - protected JsonParseException _constructError(String msg) { - return new JsonParseException(this, msg).withRequestPayload(_requestPayload); + protected char _decodeEscaped() throws IOException { + throw new UnsupportedOperationException(); + } + + protected final int _decodeBase64Escape(Base64Variant b64variant, int ch, int index) throws IOException { + // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars + if (ch != '\\') { + throw reportInvalidBase64Char(ch, index); + } + int unescaped = _decodeEscaped(); + // if white space, skip if first triplet; otherwise errors + if (unescaped <= INT_SPACE) { + if (index == 0) { // whitespace only allowed to be skipped between triplets + return -1; + } + } + // otherwise try to find actual triplet value + int bits = b64variant.decodeBase64Char(unescaped); + if (bits < 0) { + if (bits != Base64Variant.BASE64_VALUE_PADDING) { + throw reportInvalidBase64Char(unescaped, index); + } + } + return bits; + } + + protected final int _decodeBase64Escape(Base64Variant b64variant, char ch, int index) throws IOException { + if (ch != '\\') { + throw reportInvalidBase64Char(ch, index); + } + char unescaped = _decodeEscaped(); + // if white space, skip if first triplet; otherwise errors + if (unescaped <= INT_SPACE) { + if (index == 0) { // whitespace only allowed to be skipped between triplets + return -1; + } + } + // otherwise try to find actual triplet value + int bits = b64variant.decodeBase64Char(unescaped); + if (bits < 0) { + // second check since padding can only be 3rd or 4th byte (index #2 or #3) + if ((bits != Base64Variant.BASE64_VALUE_PADDING) || (index < 2)) { + throw reportInvalidBase64Char(unescaped, index); + } + } + return bits; + } + + protected IllegalArgumentException reportInvalidBase64Char(int ch, int bindex) throws IllegalArgumentException { + return reportInvalidBase64Char(ch, bindex, null); } + /* + * @param bindex Relative index within base64 character unit; between 0 + * and 3 (as unit has exactly 4 characters) + */ + protected IllegalArgumentException reportInvalidBase64Char(int ch, int bindex, String msg) + throws IllegalArgumentException { + String base; + if (ch <= INT_SPACE) { + base = String.format( + "Illegal white space character (code 0x%s) as character #%d of 4-char base64 unit: can only used between units", + Integer.toHexString(ch), (bindex + 1)); + } else if (ch == '=') { + base = "Unexpected padding character ('=') 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 '" + ((char) ch) + "' (code 0x" + Integer.toHexString(ch) + ") in base64 content"; + } + if (msg != null) { + base = base + ": " + msg; + } + return new IllegalArgumentException(base); + } + + // since 2.9.8 + protected void _handleBase64MissingPadding() throws IOException { + _reportError(Base64Variant.missingPaddingMessage()); + } + + /* + * /********************************************************** + * /* Internal/package methods: other + * /********************************************************** + */ + /** - * Helper method to call for operations that are not supported by - * parser implementation. + * Helper method used to encapsulate logic of including (or not) of + * "content reference" when constructing {@link JsonLocation} instances. * - * @since 2.1 + * @return Source reference object, if any; {@code null} if none + * + * @since 2.13 */ - protected void _reportUnsupportedOperation() { - throw new UnsupportedOperationException("Operation not supported by parser of type " + getClass().getName()); + protected ContentReference _contentReference() { + return _ioContext.contentReference(); + } + + protected static int[] growArrayBy(int[] arr, int more) { + if (arr == null) { + return new int[more]; + } + return Arrays.copyOf(arr, arr.length + more); } + /* + * /********************************************************** + * /* Stuff that was abstract and required before 2.8, but that + * /* is not mandatory in 2.8 or above. + * /********************************************************** + */ + + // Can't declare as deprecated, for now, but shouldn't be needed + protected void _finishString() throws IOException { + } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonProcessingException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonProcessingException.java index 1b294ad919a1..f5efe937b1d4 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonProcessingException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonProcessingException.java @@ -27,22 +27,10 @@ protected JsonProcessingException(String msg, JsonLocation loc, Throwable rootCa _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 @@ -54,25 +42,6 @@ public JsonLocation getLocation() { return _location; } - /** - * 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 - */ - @Override - public Object getProcessor() { - return null; - } - /* * /********************************************************************** * /* Methods for sub-classes to use, override @@ -120,7 +89,7 @@ public String getMessage() { if (loc != null) { sb.append('\n'); sb.append(" at "); - sb.append(loc.toString()); + sb.append(loc); } msg = sb.toString(); } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonStreamContext.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonStreamContext.java index 555b85316904..80b487e71250 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonStreamContext.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonStreamContext.java @@ -62,25 +62,6 @@ public abstract class JsonStreamContext { protected JsonStreamContext() { } - /** - * Copy constructor used by sub-classes for creating copies for - * buffering. - * - * @param base Context instance to copy type and index from - * - * @since 2.9 - */ - protected JsonStreamContext(JsonStreamContext base) { - _type = base._type; - _index = base._index; - } - - // @since 2.9 - protected JsonStreamContext(int type, int index) { - _type = type; - _index = index; - } - /* * /********************************************************** * /* Public API, accessors @@ -126,26 +107,6 @@ public final boolean inObject() { return _type == TYPE_OBJECT; } - /** - * @return Type description String - * - * @deprecated Since 2.8 use {@link #typeDesc} instead - */ - @Deprecated // since 2.8 - public final String getTypeDesc() { - switch (_type) { - case TYPE_ROOT: - return "ROOT"; - - case TYPE_ARRAY: - return "ARRAY"; - - case TYPE_OBJECT: - return "OBJECT"; - } - return "?"; - } - /** * Method for accessing simple type description of current context; * either ROOT (for root-level values), OBJECT (for field names and @@ -185,36 +146,6 @@ public final int getCurrentIndex() { */ 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. - *

- * 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}). - * - * @param v Current value to assign to this context - * - * @since 2.5 - */ - public void setCurrentValue(Object v) { - } - /** * Optional method that may be used to access starting location of this context: * for example, in case of JSON `Object` context, offset at which `[` token was @@ -233,24 +164,11 @@ public JsonLocation startLocation(ContentReference srcRef) { return JsonLocation.NA; } - /** - * @param srcRef Source reference needed to construct location instance - * @return Location pointing to the point where the context - * start marker was found (or written); never {@code null}. - * @since 2.9 - * @deprecated Since 2.13 use {@link #startLocation} instead - */ - @Deprecated - public JsonLocation getStartLocation(Object srcRef) { - return JsonLocation.NA; - } - /** * Overridden to provide developer readable "JsonPath" representation * of the context. * * @return Simple developer-readable description this context layer - * (note: NOT constructed with parents, unlike {@link #pathAsPointer}) * * @since 2.9 */ diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonToken.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonToken.java index 3a075034bbdd..178abef8d873 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonToken.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonToken.java @@ -176,18 +176,6 @@ public final String asString() { return _serialized; } - public final char[] asCharArray() { - return _serializedChars; - } - - /** - * @return {@code True} if this token is {@code VALUE_NUMBER_INT} or {@code VALUE_NUMBER_FLOAT}, - * {@code false} otherwise - */ - public final boolean isNumeric() { - return _isNumber; - } - /** * Accessor that is functionally equivalent to: * diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonTokenId.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonTokenId.java index ba4dd7064f0a..e9d3d9e129a7 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonTokenId.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/JsonTokenId.java @@ -17,14 +17,6 @@ public interface JsonTokenId { */ 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}. - */ - int ID_NO_TOKEN = 0; - /** * Id used to represent {@link JsonToken#START_OBJECT} */ diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/ObjectCodec.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/ObjectCodec.java deleted file mode 100644 index 2ffe5a566a73..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/ObjectCodec.java +++ /dev/null @@ -1,148 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/* - * Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - */ - -package com.azure.json.implementation.jackson.core; - -import java.io.IOException; - -import com.azure.json.implementation.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). - *

- * The standard implementation of this class is - * 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 - @Override - public abstract Version version(); - - /* - * /********************************************************** - * /* 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 Boolean}). - *

- * 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. - * - * @param Nominal parameter for target type - * - * @param p Parser to use for decoding content to bind - * @param valueType Java value type to bind content to - * - * @return Value deserialized - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public abstract T readValue(JsonParser p, Class valueType) throws IOException; - - /** - * Method to deserialize JSON content into a Java type, reference - * to which is passed as argument. Type is passed using so-called - * "super type token" - * and specifically needs to be used if the root type is a - * parameterized (generic) container type. - * - * @param Nominal parameter for target type - * - * @param p Parser to use for decoding content to bind - * @param valueTypeRef Java value type to bind content to - * - * @return Value deserialized - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - public abstract T readValue(JsonParser p, TypeReference valueTypeRef) throws IOException; - - /* - * /********************************************************** - * /* API for serialization (Object-to-JSON) - * /********************************************************** - */ - - /** - * Method to serialize given Java Object, using generator - * provided. - * - * @param gen Generator to use for serializing value - * @param value Value to serialize - * - * @throws IOException for low-level write issues, or - * {@link JsonGenerationException} for decoding problems - */ - public abstract void writeValue(JsonGenerator gen, Object value) throws IOException; - - /* - * /********************************************************** - * /* TreeCodec pass-through methods - * /********************************************************** - */ - - /** - * Method for serializing JSON content from given Tree instance, using - * specified generator. - * - * @param gen Generator to use for serializing value - * @param tree Tree to serialize - * - * @throws IOException for low-level write issues, or - * {@link JsonGenerationException} for decoding problems - */ - @Override - public abstract void writeTree(JsonGenerator gen, TreeNode tree) throws IOException; - - /* - * /********************************************************** - * /* Extended tree conversions beyond TreeCodec - * /********************************************************** - */ - - /* - * /********************************************************** - * /* Basic accessors - * /********************************************************** - */ - - /** - * @deprecated Use {@link #getFactory} instead. - * - * @return Underlying {@link JsonFactory} instance - */ - @Deprecated - public JsonFactory getJsonFactory() { - return getFactory(); - } - - /** - * Accessor for finding underlying data format factory - * ({@link JsonFactory}) codec will use for data binding. - * - * @return Underlying {@link JsonFactory} instance - */ - public JsonFactory getFactory() { - return getJsonFactory(); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/SerializableString.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/SerializableString.java deleted file mode 100644 index cce150bc9dfc..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/SerializableString.java +++ /dev/null @@ -1,144 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/* - * Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - */ - -package com.azure.json.implementation.jackson.core; - -/** - * 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.azure.json.implementation.jackson.core.io.SerializedString - */ -public interface SerializableString { - /** - * Returns unquoted String that this object represents (and offers - * serialized forms for) - * - * @return Unquoted String - */ - String getValue(); - - /* - * /********************************************************** - * /* 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. - * - * @return JSON quoted form of the String as {@code char[]} - */ - char[] asQuotedChars(); - - /** - * Returns UTF-8 encoded version of unquoted String. - * Functionally equivalent to (but more efficient than): - *

-     * getValue().getBytes("UTF-8");
-     *
- * - * @return UTF-8 encoded version of String, without any escaping - */ - byte[] asUnquotedUTF8(); - - /** - * Returns UTF-8 encoded version of JSON-quoted String. - * Functionally equivalent to (but more efficient than): - *
-     * new String(asQuotedChars()).getBytes("UTF-8");
-     *
- * - * @return UTF-8 encoded version of JSON-escaped String - */ - 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;
-     *
- * - * @param buffer Buffer to append JSON-escaped String into - * @param offset Offset in {@code buffer} to append String at - * - * @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;
-     *
- * - * @param buffer Buffer to append JSON-escaped String into - * @param offset Offset in {@code buffer} to append String at - * - * @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;
-     *
- * - * @param buffer Buffer to append literal (unescaped) String into - * @param offset Offset in {@code buffer} to append String at - * - * @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;
-     *
- * - * @param buffer Buffer to append literal (unescaped) String into - * @param offset Offset in {@code buffer} to append String at - * - * @return Number of characters appended, if successful, otherwise -1 - */ - int appendUnquoted(char[] buffer, int offset); - - /* - * /********************************************************** - * /* Helper methods for writing out byte sequences - * /********************************************************** - */ - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadCapability.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadCapability.java deleted file mode 100644 index 4c36e0ca7f8c..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadCapability.java +++ /dev/null @@ -1,77 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import com.azure.json.implementation.jackson.core.util.JacksonFeature; - -/** - * Set of on/off capabilities that a {@link JsonParser} for given format - * (or in case of buffering, original format) has. - * Used in some cases to adjust aspects of things like content conversions, - * coercions and validation by format-agnostic functionality. - * Specific or expected usage documented by individual capability entry - * Javadocs. - * - * @since 2.12 - */ -public enum StreamReadCapability implements JacksonFeature { - /** - * Capability that indicates that data format can expose multiple properties - * with same name ("duplicates") within one Object context. - * This is usually not enabled, except for formats like {@code xml} that - * have content model that does not map cleanly to JSON-based token stream. - *

- * Capability may be used for allowing secondary mapping of such duplicates - * in case of using Tree Model (see {@link TreeNode}), or "untyped" databinding - * (mapping content as generic {@link Object}). - *

- * Capability is currently only enabled for XML format backend. - */ - DUPLICATE_PROPERTIES(false), - - /** - * Capability that indicates that data format may in some cases expose Scalar values - * (whether typed or untyped) as Object values. There are additional access methods - * at databind level: this capability may be used to decide whether to attempt to - * use such methods especially in potentially ambiguous cases. - *

- * Capability is currently only enabled for XML format backend. - */ - SCALARS_AS_OBJECTS(false), - - /** - * Capability that indicates that data format only exposed "untyped" scalars: that is, - * instead of Number, Boolean and String types all scalar values are reported as - * text ({@link JsonToken#VALUE_STRING}) - * unless some sort of coercion is implied by caller. - *

- * This capability is true for many textual formats like CSV, Properties and XML. - */ - UNTYPED_SCALARS(false),; - - /** - * Whether feature is enabled or disabled by default. - */ - private final boolean _defaultState; - - private final int _mask; - - StreamReadCapability(boolean defaultState) { - _defaultState = defaultState; - _mask = (1 << ordinal()); - } - - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & _mask) != 0; - } - - @Override - public int getMask() { - return _mask; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadConstraints.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadConstraints.java deleted file mode 100644 index 0f8b158b7556..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadConstraints.java +++ /dev/null @@ -1,161 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -/** - * The constraints to use for streaming reads: used to guard against malicious - * input by preventing processing of "too big" input constructs (values, - * structures). - * Constraints are registered with {@code TokenStreamFactory} (such as - * {@code JsonFactory}); if nothing explicitly specified, default - * constraints are used. - *

- * Currently constrained aspects, with default settings, are: - *

- * - * @since 2.15 - */ -public class StreamReadConstraints implements java.io.Serializable { - private static final long serialVersionUID = 1L; - - /** - * Default setting for maximum depth: see {@link Builder#maxNestingDepth(int)} for details. - */ - public static final int DEFAULT_MAX_DEPTH = 1000; - - /** - * Default setting for maximum document length: - * see {@link Builder#maxDocumentLength} for details. - */ - public static final long DEFAULT_MAX_DOC_LEN = -1L; - - /** - * @since 2.16 - */ - public static final int DEFAULT_MAX_NUM_LEN = 1000; - - /** - * Default setting for maximum string length: see {@link Builder#maxStringLength(int)} - * for details. - *

- * NOTE: Jackson 2.15.0 initially used a lower setting (5_000_000). - */ - public static final int DEFAULT_MAX_STRING_LEN = 20_000_000; - - /** - * Default setting for maximum name length: see {@link Builder#maxNameLength(int)} - * for details. - * - * @since 2.16 - */ - public static final int DEFAULT_MAX_NAME_LEN = 50_000; - - protected final int _maxNestingDepth; - protected final long _maxDocLen; - - protected final int _maxNumLen; - protected final int _maxStringLen; - protected final int _maxNameLen; - - public static final class Builder { - private final long maxDocLen; - private final int maxNestingDepth; - private final int maxNumLen; - private final int maxStringLen; - private final int maxNameLen; - - Builder() { - this(DEFAULT_MAX_DEPTH, DEFAULT_MAX_DOC_LEN, DEFAULT_MAX_NUM_LEN, DEFAULT_MAX_STRING_LEN, - DEFAULT_MAX_NAME_LEN); - } - - Builder(final int maxNestingDepth, final long maxDocLen, final int maxNumLen, final int maxStringLen, - final int maxNameLen) { - this.maxNestingDepth = maxNestingDepth; - this.maxDocLen = maxDocLen; - this.maxNumLen = maxNumLen; - this.maxStringLen = maxStringLen; - this.maxNameLen = maxNameLen; - } - - public StreamReadConstraints build() { - return new StreamReadConstraints(maxNestingDepth, maxDocLen, maxNumLen, maxStringLen, maxNameLen); - } - } - - /* - /********************************************************************** - /* Life-cycle - /********************************************************************** - */ - - @Deprecated // since 2.16 - protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen, final int maxNumLen, - final int maxStringLen) { - this(maxNestingDepth, DEFAULT_MAX_DOC_LEN, maxNumLen, maxStringLen, DEFAULT_MAX_NAME_LEN); - } - - /** - * @param maxNestingDepth Maximum input document nesting to allow - * @param maxDocLen Maximum input document length to allow - * @param maxNumLen Maximum number representation length to allow - * @param maxStringLen Maximum String value length to allow - * @param maxNameLen Maximum Object property name length to allow - * - * @since 2.16 - */ - protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen, final int maxNumLen, - final int maxStringLen, final int maxNameLen) { - _maxNestingDepth = maxNestingDepth; - _maxDocLen = maxDocLen; - _maxNumLen = maxNumLen; - _maxStringLen = maxStringLen; - _maxNameLen = maxNameLen; - } - - public static Builder builder() { - return new Builder(); - } - - /* - /********************************************************************** - /* Accessors - /********************************************************************** - */ - - /* - /********************************************************************** - /* Convenience methods for validation, document limits - /********************************************************************** - */ - - /* - /********************************************************************** - /* Convenience methods for validation, token lengths - /********************************************************************** - */ - - /* - /********************************************************************** - /* Convenience methods for validation, other - /********************************************************************** - */ - - /* - /********************************************************************** - /* Error reporting - /********************************************************************** - */ - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadFeature.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadFeature.java deleted file mode 100644 index 4272e52a080d..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamReadFeature.java +++ /dev/null @@ -1,134 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import java.io.InputStream; -import java.io.Reader; - -import com.azure.json.implementation.jackson.core.util.JacksonFeature; - -/** - * Token reader (parser) features not-specific to any particular format backend. - * Eventual replacement for non-JSON-specific {@link JsonParser.Feature}s. - * - * @since 2.10 - */ -public enum StreamReadFeature implements JacksonFeature // since 2.12 -{ - // // // 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}. - *

- * Feature is enabled by default. - */ - AUTO_CLOSE_SOURCE(JsonParser.Feature.AUTO_CLOSE_SOURCE), - - // // // Validity checks - - /** - * 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. - */ - STRICT_DUPLICATE_DETECTION(JsonParser.Feature.STRICT_DUPLICATE_DETECTION), - - /** - * 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} - */ - IGNORE_UNDEFINED(JsonParser.Feature.IGNORE_UNDEFINED), - - // // // Other - - /** - * Feature that determines whether {@link JsonLocation} instances should be constructed - * with reference to source or not. If source reference is included, its type and contents - * are included when `toString()` method is called (most notably when printing out parse - * exception with that location information). If feature is disabled, no source reference - * is passed and source is only indicated as "UNKNOWN". - *

- * Most common reason for disabling this feature is to avoid leaking - * internal information; this may be done for security reasons. - * Note that even if source reference is included, only parts of contents are usually - * printed, and not the whole contents. Further, many source reference types can not - * necessarily access contents (like streams), so only type is indicated, not contents. - *

- * Feature is enabled by default, meaning that "source reference" information is passed - * and some or all of the source content may be included in {@link JsonLocation} information - * constructed either when requested explicitly, or when needed for an exception. - */ - INCLUDE_SOURCE_IN_LOCATION(JsonParser.Feature.INCLUDE_SOURCE_IN_LOCATION), - - ; - - /** - * Whether feature is enabled or disabled by default. - */ - private final boolean _defaultState; - - private final int _mask; - - /** - * For backwards compatibility we may need to map to one of existing {@link JsonParser.Feature}s; - * if so, this is the feature to enable/disable. - */ - final private JsonParser.Feature _mappedFeature; - - StreamReadFeature(JsonParser.Feature mapTo) { - // only for 2.x, let's map everything to legacy feature: - _mappedFeature = mapTo; - _mask = mapTo.getMask(); - _defaultState = mapTo.enabledByDefault(); - } - - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & _mask) != 0; - } - - @Override - public int getMask() { - return _mask; - } - - public JsonParser.Feature mappedFeature() { - return _mappedFeature; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamWriteCapability.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamWriteCapability.java deleted file mode 100644 index 729ece9045bd..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamWriteCapability.java +++ /dev/null @@ -1,61 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import com.azure.json.implementation.jackson.core.util.JacksonFeature; - -/** - * Set of on/off capabilities that a {@link JsonGenerator} for given format - * (or in case of buffering, original format) has. - * Used in some cases to adjust aspects of things like content conversions and - * coercions by format-agnostic functionality. - * Specific or expected usage documented by individual capability entry Javadocs. - * - * @since 2.12 - */ -public enum StreamWriteCapability implements JacksonFeature { - /** - * Capability that indicates that the data format is able to express binary - * data natively, without using textual encoding like Base64. - *

- * Capability is currently enabled for all binary formats and none of textual - * formats. - */ - CAN_WRITE_BINARY_NATIVELY(false), - - /** - * Capability that indicates that the data format is able to write - * "formatted numbers": that is, output of numbers is done as Strings - * and caller is allowed to pass in logical number values as Strings. - *

- * Capability is currently enabled for most textual formats and none of binary - * formats. - */ - CAN_WRITE_FORMATTED_NUMBERS(false); - - /** - * Whether feature is enabled or disabled by default. - */ - private final boolean _defaultState; - - private final int _mask; - - StreamWriteCapability(boolean defaultState) { - _defaultState = defaultState; - _mask = (1 << ordinal()); - } - - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & _mask) != 0; - } - - @Override - public int getMask() { - return _mask; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamWriteFeature.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamWriteFeature.java deleted file mode 100644 index 41622c45d119..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/StreamWriteFeature.java +++ /dev/null @@ -1,152 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import java.io.OutputStream; -import java.io.Writer; -import java.math.BigDecimal; - -import com.azure.json.implementation.jackson.core.util.JacksonFeature; - -/** - * Token writer (generator) features not-specific to any particular format backend. - * Eventual replacement for non-JSON-specific {@link JsonGenerator.Feature}s. - * - * @since 2.10 - */ -public enum StreamWriteFeature implements JacksonFeature // since 2.12 -{ - // // Low-level I/O / content features - - /** - * Feature that determines whether generator will automatically - * close underlying output target that is NOT owned by the - * generator. - * If disabled, calling application has to separately - * close the underlying {@link OutputStream} and {@link Writer} - * instances used to create the generator. If enabled, generator - * will handle closing, as long as generator itself gets closed: - * this happens when end-of-input is encountered, or generator - * is closed by a call to {@link JsonGenerator#close}. - *

- * Feature is enabled by default. - */ - AUTO_CLOSE_TARGET(JsonGenerator.Feature.AUTO_CLOSE_TARGET), - - /** - * 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 (that is, matching END_ token write - * call is made for all open scopes); if disabled, no additional - * write calls are made. - *

- * Feature is enabled by default. - */ - AUTO_CLOSE_CONTENT(JsonGenerator.Feature.AUTO_CLOSE_JSON_CONTENT), - - /** - * Feature that specifies that calls to {@link JsonGenerator#flush} will cause - * matching flush() 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). - *

- * Feature is enabled by default. - */ - FLUSH_PASSED_TO_STREAM(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM), - - // // Datatype coercion features - - /** - * Feature that determines whether {@link BigDecimal} entries are - * serialized using {@link BigDecimal#toPlainString()} to prevent - * values to be written using scientific notation. - *

- * NOTE: only affects generators that serialize {@link BigDecimal}s - * using textual representation (textual formats but potentially some binary - * formats). - *

- * Feature is disabled by default, so default output mode is used; this generally - * depends on how {@link BigDecimal} has been created. - */ - WRITE_BIGDECIMAL_AS_PLAIN(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN), - - // // 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. - */ - STRICT_DUPLICATE_DETECTION(JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION), - - /** - * 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} - */ - IGNORE_UNKNOWN(JsonGenerator.Feature.IGNORE_UNKNOWN),; - - /** - * Whether feature is enabled or disabled by default. - */ - private final boolean _defaultState; - - private final int _mask; - - /** - * For backwards compatibility we may need to map to one of existing {@link JsonParser.Feature}s; - * if so, this is the feature to enable/disable. - */ - final private JsonGenerator.Feature _mappedFeature; - - StreamWriteFeature(JsonGenerator.Feature mappedTo) { - // only for 2.x, let's map everything to legacy feature: - _mappedFeature = mappedTo; - _mask = mappedTo.getMask(); - _defaultState = mappedTo.enabledByDefault(); - } - - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & _mask) != 0; - } - - @Override - public int getMask() { - return _mask; - } - - public JsonGenerator.Feature mappedFeature() { - return _mappedFeature; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TSFBuilder.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TSFBuilder.java deleted file mode 100644 index 624b689a6d4c..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TSFBuilder.java +++ /dev/null @@ -1,285 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import com.azure.json.implementation.jackson.core.io.InputDecorator; -import com.azure.json.implementation.jackson.core.io.OutputDecorator; -import com.azure.json.implementation.jackson.core.json.JsonReadFeature; -import com.azure.json.implementation.jackson.core.json.JsonWriteFeature; - -/** - * Since 2.10, Builder class is offered for creating token stream factories - * with difference configurations: with 3.x they will be fully immutable. - * - * @since 2.10 - */ -public abstract class TSFBuilder> { - /* - * /********************************************************************** - * /* Constants - * /********************************************************************** - */ - - /** - * 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(); - - /* - * /********************************************************************** - * /* Configured features - * /********************************************************************** - */ - - /** - * Set of {@link JsonFactory.Feature}s enabled, - * as bitmask. - */ - protected int _factoryFeatures; - - /** - * Set of {@link JsonParser.Feature}s enabled, as bitmask. - */ - protected int _streamReadFeatures; - - /** - * Set of {@link JsonGenerator.Feature}s enabled, as bitmask. - */ - protected int _streamWriteFeatures; - - /* - * /********************************************************************** - * /* Other configuration - * /********************************************************************** - */ - - /** - * 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; - - /* - * /********************************************************************** - * /* Construction - * /********************************************************************** - */ - - protected TSFBuilder() { - _factoryFeatures = DEFAULT_FACTORY_FEATURE_FLAGS; - _streamReadFeatures = DEFAULT_PARSER_FEATURE_FLAGS; - _streamWriteFeatures = DEFAULT_GENERATOR_FEATURE_FLAGS; - _inputDecorator = null; - _outputDecorator = null; - } - - // // // Accessors - - // // // Factory features - - public B enable(JsonFactory.Feature f) { - _factoryFeatures |= f.getMask(); - return _this(); - } - - public B disable(JsonFactory.Feature f) { - _factoryFeatures &= ~f.getMask(); - return _this(); - } - - public B configure(JsonFactory.Feature f, boolean state) { - return state ? enable(f) : disable(f); - } - - // // // StreamReadFeatures (replacement of non-json-specific parser features) - - public B enable(StreamReadFeature f) { - _streamReadFeatures |= f.mappedFeature().getMask(); - return _this(); - } - - public B enable(StreamReadFeature first, StreamReadFeature... other) { - _streamReadFeatures |= first.mappedFeature().getMask(); - for (StreamReadFeature f : other) { - _streamReadFeatures |= f.mappedFeature().getMask(); - } - return _this(); - } - - public B disable(StreamReadFeature f) { - _streamReadFeatures &= ~f.mappedFeature().getMask(); - return _this(); - } - - public B disable(StreamReadFeature first, StreamReadFeature... other) { - _streamReadFeatures &= ~first.mappedFeature().getMask(); - for (StreamReadFeature f : other) { - _streamReadFeatures &= ~f.mappedFeature().getMask(); - } - return _this(); - } - - public B configure(StreamReadFeature f, boolean state) { - return state ? enable(f) : disable(f); - } - - // // // StreamWriteFeatures (replacement of non-json-specific generator features) - - public B enable(StreamWriteFeature f) { - _streamWriteFeatures |= f.mappedFeature().getMask(); - return _this(); - } - - public B enable(StreamWriteFeature first, StreamWriteFeature... other) { - _streamWriteFeatures |= first.mappedFeature().getMask(); - for (StreamWriteFeature f : other) { - _streamWriteFeatures |= f.mappedFeature().getMask(); - } - return _this(); - } - - public B disable(StreamWriteFeature f) { - _streamWriteFeatures &= ~f.mappedFeature().getMask(); - return _this(); - } - - public B disable(StreamWriteFeature first, StreamWriteFeature... other) { - _streamWriteFeatures &= ~first.mappedFeature().getMask(); - for (StreamWriteFeature f : other) { - _streamWriteFeatures &= ~f.mappedFeature().getMask(); - } - return _this(); - } - - public B configure(StreamWriteFeature f, boolean state) { - return state ? enable(f) : disable(f); - } - - /* - * 26-Jun-2018, tatu: This should not be needed here, but due to 2.x limitations, - * we do need to include it or require casting. - * Specifically: since `JsonFactory` (and not `TokenStreamFactory`) is base class - * for all backends, it can not expose JSON-specific builder, but this. - * So let's select lesser evil(s). - */ - - // // // JSON-specific, reads - - public B enable(JsonReadFeature f) { - return _failNonJSON(f); - } - - public B enable(JsonReadFeature first, JsonReadFeature... other) { - return _failNonJSON(first); - } - - public B disable(JsonReadFeature f) { - return _failNonJSON(f); - } - - public B disable(JsonReadFeature first, JsonReadFeature... other) { - return _failNonJSON(first); - } - - public B configure(JsonReadFeature f, boolean state) { - return _failNonJSON(f); - } - - private B _failNonJSON(Object feature) { - throw new IllegalArgumentException( - "Feature " + feature.getClass().getName() + "#" + feature + " not supported for non-JSON backend"); - } - - // // // JSON-specific, writes - - public B enable(JsonWriteFeature f) { - return _failNonJSON(f); - } - - public B enable(JsonWriteFeature first, JsonWriteFeature... other) { - return _failNonJSON(first); - } - - public B disable(JsonWriteFeature f) { - return _failNonJSON(f); - } - - public B disable(JsonWriteFeature first, JsonWriteFeature... other) { - return _failNonJSON(first); - } - - public B configure(JsonWriteFeature f, boolean state) { - return _failNonJSON(f); - } - - // // // Other configuration - - public B inputDecorator(InputDecorator dec) { - _inputDecorator = dec; - return _this(); - } - - public B outputDecorator(OutputDecorator dec) { - _outputDecorator = dec; - return _this(); - } - - // // // Other methods - - /** - * Method for constructing actual {@link TokenStreamFactory} instance, given - * configuration. - * - * @return {@link TokenStreamFactory} build based on current configuration - */ - public abstract F build(); - - // silly convenience cast method we need - @SuppressWarnings("unchecked") - protected final B _this() { - return (B) this; - } - - // // // Support for subtypes - - protected void _legacyEnable(JsonParser.Feature f) { - if (f != null) { - _streamReadFeatures |= f.getMask(); - } - } - - protected void _legacyDisable(JsonParser.Feature f) { - if (f != null) { - _streamReadFeatures &= ~f.getMask(); - } - } - - protected void _legacyEnable(JsonGenerator.Feature f) { - if (f != null) { - _streamWriteFeatures |= f.getMask(); - } - } - - protected void _legacyDisable(JsonGenerator.Feature f) { - if (f != null) { - _streamWriteFeatures &= ~f.getMask(); - } - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TokenStreamFactory.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TokenStreamFactory.java deleted file mode 100644 index acce7487474c..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TokenStreamFactory.java +++ /dev/null @@ -1,134 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core; - -import java.io.*; -import java.net.URL; - -/** - * Intermediate base class for actual format-specific factories for constructing - * parsers (reading) and generators (writing). Although full power will only be - * available with Jackson 3, skeletal implementation added in 2.10 to help conversion - * of code for 2.x to 3.x migration of projects depending on Jackson - * - * @since 2.10 - */ -public abstract class TokenStreamFactory implements Versioned, Serializable { - private static final long serialVersionUID = 2; - - /* - * /********************************************************************** - * /* Capability introspection - * /********************************************************************** - */ - - /** - * 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. - *

- * Default implementation returns 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. - * - * @return Whether format supported by this factory - * supports native binary content - */ - public abstract boolean canHandleBinaryNatively(); - - /* - * /********************************************************************** - * /* Format detection functionality - * /********************************************************************** - */ - - /** - * Method that returns short textual id identifying format - * this factory supports. - * - * @return Name of the format handled by parsers, generators this factory creates - */ - public abstract String getFormatName(); - - /* - * /********************************************************************** - * /* Configuration access - * /********************************************************************** - */ - - public abstract boolean isEnabled(JsonParser.Feature f); - - public abstract boolean isEnabled(JsonGenerator.Feature f); - - /* - * /********************************************************************** - * /* Factory methods, parsers - * /********************************************************************** - */ - - public abstract JsonParser createParser(byte[] data) throws IOException; - - public abstract JsonParser createParser(byte[] data, int offset, int len) throws IOException; - - public abstract JsonParser createParser(File f) throws IOException; - - public abstract JsonParser createParser(InputStream in) throws IOException; - - public abstract JsonParser createParser(Reader r) throws IOException; - - public abstract JsonParser createParser(String content) throws IOException; - - public abstract JsonParser createParser(URL url) throws IOException; - - /* - * /********************************************************************** - * /* Factory methods, generators - * /********************************************************************** - */ - - public abstract JsonGenerator createGenerator(OutputStream out) throws IOException; - - public abstract JsonGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException; - - public abstract JsonGenerator createGenerator(Writer w) throws IOException; - - /* - * /********************************************************************** - * /* Internal factory methods, other - * /********************************************************************** - */ - - /** - * Helper methods used for constructing an optimal stream for - * parsers to use, when input is to be read from an URL. - * This helps when reading file content via URL. - * - * @param url Source to read content to parse from - * - * @return InputStream constructed for given {@link URL} - * - * @throws IOException If there is a problem accessing content from specified {@link URL} - */ - protected InputStream _optimizedStreamFromURL(URL url) throws IOException { - if ("file".equals(url.getProtocol())) { - /* - * Can not do this if the path refers - * to a network drive on windows. This fixes the problem; - * might not be needed on all platforms (NFS?), but should not - * matter a lot: performance penalty of extra wrapping is more - * relevant when accessing local file system. - */ - String host = url.getHost(); - if (host == null || host.isEmpty()) { - // [core#48]: Let's try to avoid probs with URL encoded stuff - String path = url.getPath(); - if (path.indexOf('%') < 0) { - return new FileInputStream(url.getPath()); - - } - // otherwise, let's fall through and let URL decoder do its magic - } - } - return url.openStream(); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TreeCodec.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TreeCodec.java deleted file mode 100644 index 37108dd615c1..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TreeCodec.java +++ /dev/null @@ -1,16 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.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 void writeTree(JsonGenerator g, TreeNode tree) throws IOException; - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TreeNode.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TreeNode.java deleted file mode 100644 index ba0426281db6..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/TreeNode.java +++ /dev/null @@ -1,122 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/* - * Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - */ - -package com.azure.json.implementation.jackson.core; - -/** - * Marker interface used to denote JSON Tree nodes, as far as - * the core package knows them (which is very little): mostly - * needed to allow {@link ObjectCodec} to have some level - * of interoperability. - * Most functionality is within JsonNode - * base class in mapper package. - *

- * Note that in Jackson 1.x 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. - *

- * NOTE: starting with Jackson 2.2, there is more functionality - * available via this class, and the intent was that this should - * form actual base for multiple alternative tree representations; - * for example, immutable trees could use different implementation - * than mutable trees. - * - * @since 2.2 - */ -public interface TreeNode { - /* - * /********************************************************** - * /* Minimal introspection methods - * /********************************************************** - */ - - /** - * 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 if this node is an Array node, false - * otherwise. - * Note that if true is returned, {@link #isContainerNode} - * must also return true. - * - * @return {@code True} for Array nodes, {@code false} for everything else - * - * @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. - * - * @return {@code True} for Object nodes, {@code false} for everything else - * - * @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. - * - * @param fieldName Name of the field (of Object node) to access - * - * @return Node that represent value of the specified field, - * if this node is an Object and has value for the specified - * field; {@code 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 - * node.size(), null is returned; no exception is - * thrown for any index. - * - * @param index Index of the Array node element to access - * - * @return Node that represent value of the specified element, - * if this node is an array and has specified element; - * {@code null} otherwise. - * - * @since 2.2 - */ - TreeNode get(int index); -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Version.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Version.java deleted file mode 100644 index 5dc108e31053..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Version.java +++ /dev/null @@ -1,151 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/* - * Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - */ - -package com.azure.json.implementation.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, java.io.Serializable { - private static final long serialVersionUID = 1L; - - private final static Version UNKNOWN_VERSION = new Version(0, 0, 0, null, null, null); - - protected final int _majorVersion; - - protected final int _minorVersion; - - protected final int _patchLevel; - - protected final String _groupId; - - protected final String _artifactId; - - /** - * Additional information for snapshot versions; null for non-snapshot - * (release) versions. - */ - protected final String _snapshotInfo; - - /** - * @param major Major version number - * @param minor Minor version number - * @param patchLevel patch level of version - * @param snapshotInfo Optional additional string qualifier - * - * @since 2.1 - * @deprecated Use variant that takes group and artifact ids - */ - @Deprecated - public Version(int major, int minor, int patchLevel, String snapshotInfo) { - this(major, minor, patchLevel, snapshotInfo, null, null); - } - - public Version(int major, int minor, int patchLevel, String snapshotInfo, String groupId, String artifactId) { - _majorVersion = major; - _minorVersion = minor; - _patchLevel = patchLevel; - _snapshotInfo = snapshotInfo; - _groupId = (groupId == null) ? "" : groupId; - _artifactId = (artifactId == null) ? "" : artifactId; - } - - /** - * Method returns canonical "not known" version, which is used as version - * in cases where actual version information is not known (instead of null). - * - * @return Version instance to use as a placeholder when actual version is not known - * (or not relevant) - */ - public static Version unknownVersion() { - return UNKNOWN_VERSION; - } - - /** - * @return {@code True} if this instance is the one returned by - * call to {@link #unknownVersion()} - * - * @since 2.7 to replace misspelled {@link #isUknownVersion()} - */ - public boolean isUnknownVersion() { - return (this == UNKNOWN_VERSION); - } - - public boolean isSnapshot() { - return (_snapshotInfo != null && !_snapshotInfo.isEmpty()); - } - - /** - * @return {@code True} if this instance is the one returned by - * call to {@link #unknownVersion()} - * - * @deprecated Since 2.7 use correctly spelled method {@link #isUnknownVersion()} - */ - @Deprecated - public boolean isUknownVersion() { - return isUnknownVersion(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(_majorVersion).append('.'); - sb.append(_minorVersion).append('.'); - sb.append(_patchLevel); - if (isSnapshot()) { - sb.append('-').append(_snapshotInfo); - } - return sb.toString(); - } - - @Override - public int hashCode() { - return _artifactId.hashCode() ^ _groupId.hashCode() + _majorVersion - _minorVersion + _patchLevel; - } - - @Override - public boolean equals(Object o) { - if (o == this) - return true; - if (o == null) - return false; - if (o.getClass() != getClass()) - return false; - Version other = (Version) o; - return (other._majorVersion == _majorVersion) - && (other._minorVersion == _minorVersion) - && (other._patchLevel == _patchLevel) - && other._artifactId.equals(_artifactId) - && other._groupId.equals(_groupId); - } - - @Override - public int compareTo(Version other) { - if (other == this) - return 0; - - int diff = _groupId.compareTo(other._groupId); - if (diff == 0) { - diff = _artifactId.compareTo(other._artifactId); - if (diff == 0) { - diff = _majorVersion - other._majorVersion; - if (diff == 0) { - diff = _minorVersion - other._minorVersion; - if (diff == 0) { - diff = _patchLevel - other._patchLevel; - } - } - } - } - return diff; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Versioned.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Versioned.java deleted file mode 100644 index 45efd7d4883f..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/Versioned.java +++ /dev/null @@ -1,27 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/* - * Jackson JSON-processor. - * - * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi - */ - -package com.azure.json.implementation.jackson.core; - -/** - * Interface that those Jackson components that are explicitly versioned will implement. - * Intention is to allow both plug-in components (custom extensions) and applications and - * frameworks that use Jackson to detect exact version of Jackson in use. - * This may be useful for example for ensuring that proper Jackson version is deployed - * (beyond mechanisms that deployment system may have), as well as for possible - * workarounds. - */ -public interface Versioned { - /** - * Method called to detect version of the component that implements this interface; - * returned version should never be null, but may return specific "not available" - * instance (see {@link Version} for details). - * - * @return Version of the component - */ - Version version(); -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/GeneratorBase.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/GeneratorBase.java deleted file mode 100644 index 96e26941e5e2..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/GeneratorBase.java +++ /dev/null @@ -1,498 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.base; - -import com.azure.json.implementation.jackson.core.Base64Variant; -import com.azure.json.implementation.jackson.core.JsonGenerator; -import com.azure.json.implementation.jackson.core.JsonStreamContext; -import com.azure.json.implementation.jackson.core.ObjectCodec; -import com.azure.json.implementation.jackson.core.SerializableString; -import com.azure.json.implementation.jackson.core.TreeNode; -import com.azure.json.implementation.jackson.core.Version; -import com.azure.json.implementation.jackson.core.json.DupDetector; -import com.azure.json.implementation.jackson.core.json.JsonWriteContext; -import com.azure.json.implementation.jackson.core.json.PackageVersion; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigDecimal; - -/** - * This base class implements part of API that a JSON generator exposes - * to applications, adds shared internal methods that sub-classes - * can use and adds some abstract methods sub-classes must implement. - */ -public abstract class GeneratorBase extends JsonGenerator { - public final static int SURR1_FIRST = 0xD800; - public final static int SURR1_LAST = 0xDBFF; - public final static int SURR2_FIRST = 0xDC00; - public final static int SURR2_LAST = 0xDFFF; - - /** - * Set of feature masks related to features that need updates of other - * local configuration or state. - * - * @since 2.5 - */ - @SuppressWarnings("deprecation") - protected final static int DERIVED_FEATURES_MASK = Feature.WRITE_NUMBERS_AS_STRINGS.getMask() - | Feature.ESCAPE_NON_ASCII.getMask() | Feature.STRICT_DUPLICATE_DETECTION.getMask(); - - // // // Constants for validation messages (since 2.6) - - protected final static String WRITE_BINARY = "write a binary value"; - protected final static String WRITE_BOOLEAN = "write a boolean value"; - protected final static String WRITE_NULL = "write a null"; - protected final static String WRITE_NUMBER = "write a number"; - protected final static String WRITE_RAW = "write a raw (unencoded) value"; - protected final static String WRITE_STRING = "write a string"; - - /** - * This value is the limit of scale allowed for serializing {@link BigDecimal} - * in "plain" (non-engineering) notation; intent is to prevent asymmetric - * attack whereupon simple eng-notation with big scale is used to generate - * huge "plain" serialization. See [core#315] for details. - * - * @since 2.7.7 - */ - protected final static int MAX_BIG_DECIMAL_SCALE = 9999; - - /* - * /********************************************************** - * /* Configuration - * /********************************************************** - */ - - protected ObjectCodec _objectCodec; - - /** - * Bit flag composed of bits that indicate which - * {@link Feature}s - * are enabled. - */ - protected int _features; - - /** - * Flag set to indicate that implicit conversion from number - * to JSON String is needed (as per - * {@link com.azure.json.implementation.jackson.core.json.JsonWriteFeature#WRITE_NUMBERS_AS_STRINGS}). - */ - protected boolean _cfgNumbersAsStrings; - - /* - * /********************************************************** - * /* State - * /********************************************************** - */ - - /** - * Object that keeps track of the current contextual state - * of the generator. - */ - protected JsonWriteContext _writeContext; - - /** - * Flag that indicates whether generator is closed or not. Gets - * set when it is closed by an explicit call - * ({@link #close}). - */ - protected boolean _closed; - - /* - * /********************************************************** - * /* Life-cycle - * /********************************************************** - */ - - @SuppressWarnings("deprecation") - protected GeneratorBase(int features, ObjectCodec codec) { - super(); - _features = features; - _objectCodec = codec; - DupDetector dups - = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features) ? DupDetector.rootDetector(this) : null; - _writeContext = JsonWriteContext.createRootContext(dups); - _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(features); - } - - /** - * Implemented with standard version number detection algorithm, typically using - * a simple generated class, with information extracted from Maven project file - * during build. - * - * @return Version number of the generator (version of the jar that contains - * generator implementation class) - */ - @Override - public Version version() { - return PackageVersion.VERSION; - } - - @Override - public Object getCurrentValue() { - return _writeContext.getCurrentValue(); - } - - @Override - public void setCurrentValue(Object v) { - if (_writeContext != null) { - _writeContext.setCurrentValue(v); - } - } - - /* - * /********************************************************** - * /* Configuration - * /********************************************************** - */ - - @Override - public final boolean isEnabled(Feature f) { - return (_features & f.getMask()) != 0; - } - - @Override - public int getFeatureMask() { - return _features; - } - - // public JsonGenerator configure(Feature f, boolean state) { } - - @SuppressWarnings("deprecation") - @Override - public JsonGenerator enable(Feature f) { - final int mask = f.getMask(); - _features |= mask; - if ((mask & DERIVED_FEATURES_MASK) != 0) { - // why not switch? Requires addition of a generated class, alas - if (f == Feature.WRITE_NUMBERS_AS_STRINGS) { - _cfgNumbersAsStrings = true; - } else if (f == Feature.ESCAPE_NON_ASCII) { - setHighestNonEscapedChar(127); - } else if (f == Feature.STRICT_DUPLICATE_DETECTION) { - if (_writeContext.getDupDetector() == null) { // but only if disabled currently - _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this)); - } - } - } - return this; - } - - @SuppressWarnings("deprecation") - @Override - public JsonGenerator disable(Feature f) { - final int mask = f.getMask(); - _features &= ~mask; - if ((mask & DERIVED_FEATURES_MASK) != 0) { - if (f == Feature.WRITE_NUMBERS_AS_STRINGS) { - _cfgNumbersAsStrings = false; - } else if (f == Feature.ESCAPE_NON_ASCII) { - setHighestNonEscapedChar(0); - } else if (f == Feature.STRICT_DUPLICATE_DETECTION) { - _writeContext = _writeContext.withDupDetector(null); - } - } - return this; - } - - @Override - @Deprecated - public JsonGenerator setFeatureMask(int newMask) { - int changed = newMask ^ _features; - _features = newMask; - if (changed != 0) { - _checkStdFeatureChanges(newMask, changed); - } - return this; - } - - @Override // since 2.7 - public JsonGenerator overrideStdFeatures(int values, int mask) { - int oldState = _features; - int newState = (oldState & ~mask) | (values & mask); - int changed = oldState ^ newState; - if (changed != 0) { - _features = newState; - _checkStdFeatureChanges(newState, changed); - } - return this; - } - - /** - * Helper method called to verify changes to standard features. - * - * @param newFeatureFlags Bitflag of standard features after they were changed - * @param changedFeatures Bitflag of standard features for which setting - * did change - * - * @since 2.7 - */ - @SuppressWarnings("deprecation") - protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures) { - if ((changedFeatures & DERIVED_FEATURES_MASK) == 0) { - return; - } - _cfgNumbersAsStrings = Feature.WRITE_NUMBERS_AS_STRINGS.enabledIn(newFeatureFlags); - if (Feature.ESCAPE_NON_ASCII.enabledIn(changedFeatures)) { - if (Feature.ESCAPE_NON_ASCII.enabledIn(newFeatureFlags)) { - setHighestNonEscapedChar(127); - } else { - setHighestNonEscapedChar(0); - } - } - if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(changedFeatures)) { - if (Feature.STRICT_DUPLICATE_DETECTION.enabledIn(newFeatureFlags)) { // enabling - if (_writeContext.getDupDetector() == null) { // but only if disabled currently - _writeContext = _writeContext.withDupDetector(DupDetector.rootDetector(this)); - } - } else { // disabling - _writeContext = _writeContext.withDupDetector(null); - } - } - } - - @Override - public JsonGenerator setCodec(ObjectCodec oc) { - _objectCodec = oc; - return this; - } - - @Override - public ObjectCodec getCodec() { - return _objectCodec; - } - - /* - * /********************************************************** - * /* Public API, accessors - * /********************************************************** - */ - - /** - * Note: type was co-variant until Jackson 2.7; reverted back to - * base type in 2.8 to allow for overriding by subtypes that use - * custom context type. - */ - @Override - public JsonStreamContext getOutputContext() { - return _writeContext; - } - - /* - * /********************************************************** - * /* Public API, write methods, structural - * /********************************************************** - */ - - // public void writeStartArray() throws IOException - // public void writeEndArray() throws IOException - // public void writeStartObject() throws IOException - // public void writeEndObject() throws IOException - - @Override // since 2.8 - public void writeStartObject(Object forValue) throws IOException { - writeStartObject(); - if (forValue != null) { - setCurrentValue(forValue); - } - } - - /* - * /********************************************************** - * /* Public API, write methods, textual - * /********************************************************** - */ - - @Override - public void writeFieldName(SerializableString name) throws IOException { - writeFieldName(name.getValue()); - } - - // public abstract void writeString(String text) throws IOException; - - // public abstract void writeString(char[] text, int offset, int len) throws IOException; - - // public abstract void writeString(Reader reader, int len) throws IOException; - - // public abstract void writeRaw(String text) throws IOException,; - - // public abstract void writeRaw(char[] text, int offset, int len) throws IOException; - - @Override - public void writeString(SerializableString text) throws IOException { - writeString(text.getValue()); - } - - @Override - public void writeRawValue(String text) throws IOException { - _verifyValueWrite("write raw value"); - writeRaw(text); - } - - @Override - public void writeRawValue(String text, int offset, int len) throws IOException { - _verifyValueWrite("write raw value"); - writeRaw(text, offset, len); - } - - @Override - public void writeRawValue(char[] text, int offset, int len) throws IOException { - _verifyValueWrite("write raw value"); - writeRaw(text, offset, len); - } - - @Override - public void writeRawValue(SerializableString text) throws IOException { - _verifyValueWrite("write raw value"); - writeRaw(text); - } - - @Override - public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException { - // Let's implement this as "unsupported" to make it easier to add new parser impls - _reportUnsupportedOperation(); - return 0; - } - - /* - * /********************************************************** - * /* Public API, write methods, primitive - * /********************************************************** - */ - - // Not implemented at this level, added as placeholders - - /* - * public abstract void writeNumber(int i) - * public abstract void writeNumber(long l) - * public abstract void writeNumber(double d) - * public abstract void writeNumber(float f) - * public abstract void writeNumber(BigDecimal dec) - * public abstract void writeBoolean(boolean state) - * public abstract void writeNull() - */ - - /* - * /********************************************************** - * /* Public API, write methods, POJOs, trees - * /********************************************************** - */ - - @Override - public void writeObject(Object value) throws IOException { - if (value == null) { - // important: call method that does check value write: - writeNull(); - } else { - /* - * 02-Mar-2009, tatu: we are NOT to call _verifyValueWrite here, - * because that will be done when codec actually serializes - * contained POJO. If we did call it it would advance state - * causing exception later on - */ - if (_objectCodec != null) { - _objectCodec.writeValue(this, value); - return; - } - _writeSimpleObject(value); - } - } - - @Override - public void writeTree(TreeNode rootNode) throws IOException { - // As with 'writeObject()', we are not check if write would work - if (rootNode == null) { - writeNull(); - } else { - if (_objectCodec == null) { - throw new IllegalStateException("No ObjectCodec defined"); - } - _objectCodec.writeValue(this, rootNode); - } - } - - /* - * /********************************************************** - * /* Public API, low-level output handling - * /********************************************************** - */ - - @Override - public abstract void flush() throws IOException; - - @Override - public void close() throws IOException { - _closed = true; - } - - @Override - public boolean isClosed() { - return _closed; - } - - /* - * /********************************************************** - * /* Package methods for this, sub-classes - * /********************************************************** - */ - - /** - * Method called to release any buffers generator may be holding, - * once generator is being closed. - */ - protected abstract void _releaseBuffers(); - - /** - * Method called before trying to write a value (scalar or structured), - * to verify that this is legal in current output state, as well as to - * output separators if and as necessary. - * - * @param typeMsg Additional message used for generating exception message - * if value output is NOT legal in current generator output state. - * - * @throws IOException if there is either an underlying I/O problem or encoding - * issue at format layer - */ - protected abstract void _verifyValueWrite(String typeMsg) throws IOException; - - /** - * Helper method used to serialize a {@link BigDecimal} as a String, - * for serialization, taking into account configuration settings - * - * @param value BigDecimal value to convert to String - * - * @return String representation of {@code value} - * - * @throws IOException if there is a problem serializing value as String - * - * @since 2.7.7 - */ - protected String _asString(BigDecimal value) throws IOException { - if (Feature.WRITE_BIGDECIMAL_AS_PLAIN.enabledIn(_features)) { - // 24-Aug-2016, tatu: [core#315] prevent possible DoS vector - int scale = value.scale(); - if ((scale < -MAX_BIG_DECIMAL_SCALE) || (scale > MAX_BIG_DECIMAL_SCALE)) { - _reportError(String.format( - "Attempt to write plain `java.math.BigDecimal` (see JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) with illegal scale (%d): needs to be between [-%d, %d]", - scale, MAX_BIG_DECIMAL_SCALE, MAX_BIG_DECIMAL_SCALE)); - } - return value.toPlainString(); - } - return value.toString(); - } - - /* - * /********************************************************** - * /* UTF-8 related helper method(s) - * /********************************************************** - */ - - // @since 2.5 - protected final int _decodeSurrogate(int surr1, int surr2) throws IOException { - // First is known to be valid, but how about the other? - if (surr2 < SURR2_FIRST || surr2 > SURR2_LAST) { - String msg = String.format("Incomplete surrogate pair: first char 0x%04X, second 0x%04X", surr1, surr2); - _reportError(msg); - } - return 0x10000 + ((surr1 - SURR1_FIRST) << 10) + (surr2 - SURR2_FIRST); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/ParserBase.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/ParserBase.java deleted file mode 100644 index 2f6ddcc0f947..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/ParserBase.java +++ /dev/null @@ -1,1292 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.base; - -import java.io.*; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Arrays; - -import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.io.IOContext; -import com.azure.json.implementation.jackson.core.io.ContentReference; -import com.azure.json.implementation.jackson.core.io.NumberInput; -import com.azure.json.implementation.jackson.core.json.DupDetector; -import com.azure.json.implementation.jackson.core.json.JsonReadContext; -import com.azure.json.implementation.jackson.core.json.PackageVersion; -import com.azure.json.implementation.jackson.core.util.ByteArrayBuilder; -import com.azure.json.implementation.jackson.core.util.JacksonFeatureSet; -import com.azure.json.implementation.jackson.core.util.TextBuffer; - -/** - * Intermediate base class used by all Jackson {@link JsonParser} - * implementations. Contains most common things that are independent - * of actual underlying input source. - */ -public abstract class ParserBase extends ParserMinimalBase { - // JSON capabilities are the same as defaults - // @since 2.12 - protected final static JacksonFeatureSet JSON_READ_CAPABILITIES = DEFAULT_READ_CAPABILITIES; - - /* - * /********************************************************** - * /* Generic I/O state - * /********************************************************** - */ - - /** - * I/O context for this reader. It handles buffer allocation - * for the reader. - */ - final protected IOContext _ioContext; - - /** - * Flag that indicates whether parser is closed or not. Gets - * set when parser is either closed by explicit call - * ({@link #close}) or when end-of-input is reached. - */ - protected boolean _closed; - - /* - * /********************************************************** - * /* Current input data - * /********************************************************** - */ - - // Note: type of actual buffer depends on sub-class, can't include - - /** - * Pointer to next available character in buffer - */ - protected int _inputPtr; - - /** - * Index of character after last available one in the buffer. - */ - protected int _inputEnd; - - /* - * /********************************************************** - * /* Current input location information - * /********************************************************** - */ - - /** - * Number of characters/bytes that were contained in previous blocks - * (blocks that were already processed prior to the current buffer). - */ - protected long _currInputProcessed; - - /** - * Current row location of current point in input buffer, starting - * from 1, if available. - */ - protected int _currInputRow = 1; - - /** - * Current index of the first character of the current row in input - * buffer. Needed to calculate column position, if necessary; benefit - * of not having column itself is that this only has to be updated - * once per line. - */ - protected int _currInputRowStart; - - /* - * /********************************************************** - * /* Information about starting location of event - * /* Reader is pointing to; updated on-demand - * /********************************************************** - */ - - // // // Location info at point when current token was started - - /** - * Total number of bytes/characters read before start of current token. - * For big (gigabyte-sized) sizes are possible, needs to be long, - * unlike pointers and sizes related to in-memory buffers. - */ - protected long _tokenInputTotal; - - /** - * Input row on which current token starts, 1-based - */ - protected int _tokenInputRow = 1; - - /** - * Column on input row that current token starts; 0-based (although - * in the end it'll be converted to 1-based) - */ - protected int _tokenInputCol; - - /* - * /********************************************************** - * /* Parsing state - * /********************************************************** - */ - - /** - * Information about parser context, context in which - * the next token is to be parsed (root, array, object). - */ - protected JsonReadContext _parsingContext; - - /** - * Secondary token related to the next token after current one; - * used if its type is known. This may be value token that - * follows FIELD_NAME, for example. - */ - protected JsonToken _nextToken; - - /* - * /********************************************************** - * /* Buffer(s) for local name(s) and text content - * /********************************************************** - */ - - /** - * Buffer that contains contents of String values, including - * field names if necessary (name split across boundary, - * contains escape sequence, or access needed to char array) - */ - protected final TextBuffer _textBuffer; - - /** - * Temporary buffer that is needed if field name is accessed - * using {@link #getTextCharacters} method (instead of String - * returning alternatives) - */ - protected char[] _nameCopyBuffer; - - /** - * Flag set to indicate whether the field name is available - * from the name copy buffer or not (in addition to its String - * representation being available via read context) - */ - protected boolean _nameCopied; - - /** - * ByteArrayBuilder is needed if 'getBinaryValue' is called. If so, - * we better reuse it for remainder of content. - */ - protected ByteArrayBuilder _byteArrayBuilder; - - /** - * We will hold on to decoded binary data, for duration of - * current event, so that multiple calls to - * {@link #getBinaryValue} will not need to decode data more - * than once. - */ - protected byte[] _binaryValue; - - // Numeric value holders: multiple fields used for - // for efficiency - - /** - * Bitfield that indicates which numeric representations - * have been calculated for the current type - */ - protected int _numTypesValid = NR_UNKNOWN; - - // First primitives - - protected int _numberInt; - - protected long _numberLong; - - protected double _numberDouble; - - // And then object types - - protected BigInteger _numberBigInt; - - protected BigDecimal _numberBigDecimal; - - // And then other information about value itself - - /** - * Flag that indicates whether numeric value has a negative - * value. That is, whether its textual representation starts - * with minus character. - */ - protected boolean _numberNegative; - - /** - * Length of integer part of the number, in characters - */ - protected int _intLength; - - /** - * Length of the fractional part (not including decimal - * point or exponent), in characters. - * Not used for pure integer values. - */ - protected int _fractLength; - - /** - * Length of the exponent part of the number, if any, not - * including 'e' marker or sign, just digits. - * Not used for pure integer values. - */ - protected int _expLength; - - /* - * /********************************************************** - * /* Life-cycle - * /********************************************************** - */ - - protected ParserBase(IOContext ctxt, int features) { - super(features); - _ioContext = ctxt; - _textBuffer = ctxt.constructTextBuffer(); - DupDetector dups - = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features) ? DupDetector.rootDetector(this) : null; - _parsingContext = JsonReadContext.createRootContext(dups); - } - - @Override - public Version version() { - return PackageVersion.VERSION; - } - - @Override - public Object getCurrentValue() { - return _parsingContext.getCurrentValue(); - } - - @Override - public void setCurrentValue(Object v) { - _parsingContext.setCurrentValue(v); - } - - /* - * /********************************************************** - * /* Overrides for Feature handling - * /********************************************************** - */ - - @Override - public JsonParser enable(Feature f) { - _features |= f.getMask(); - if (f == Feature.STRICT_DUPLICATE_DETECTION) { // enabling dup detection? - if (_parsingContext.getDupDetector() == null) { // but only if disabled currently - _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this)); - } - } - return this; - } - - @Override - public JsonParser disable(Feature f) { - _features &= ~f.getMask(); - if (f == Feature.STRICT_DUPLICATE_DETECTION) { - _parsingContext = _parsingContext.withDupDetector(null); - } - return this; - } - - @Override - @Deprecated - public JsonParser setFeatureMask(int newMask) { - int changes = (_features ^ newMask); - if (changes != 0) { - _features = newMask; - _checkStdFeatureChanges(newMask, changes); - } - return this; - } - - @Override // since 2.7 - public JsonParser overrideStdFeatures(int values, int mask) { - int oldState = _features; - int newState = (oldState & ~mask) | (values & mask); - int changed = oldState ^ newState; - if (changed != 0) { - _features = newState; - _checkStdFeatureChanges(newState, changed); - } - return this; - } - - /** - * Helper method called to verify changes to standard features. - * - * @param newFeatureFlags Bitflag of standard features after they were changed - * @param changedFeatures Bitflag of standard features for which setting - * did change - * - * @since 2.7 - */ - protected void _checkStdFeatureChanges(int newFeatureFlags, int changedFeatures) { - int f = Feature.STRICT_DUPLICATE_DETECTION.getMask(); - - if ((changedFeatures & f) != 0) { - if ((newFeatureFlags & f) != 0) { - if (_parsingContext.getDupDetector() == null) { - _parsingContext = _parsingContext.withDupDetector(DupDetector.rootDetector(this)); - } else { // disabling - _parsingContext = _parsingContext.withDupDetector(null); - } - } - } - } - - /* - * /********************************************************** - * /* JsonParser impl - * /********************************************************** - */ - - /** - * Method that can be called to get the name associated with - * the current event. - */ - @Override - public String getCurrentName() throws IOException { - // [JACKSON-395]: start markers require information from parent - if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { - JsonReadContext parent = _parsingContext.getParent(); - if (parent != null) { - return parent.getCurrentName(); - } - } - return _parsingContext.getCurrentName(); - } - - @Override - public void overrideCurrentName(String name) { - // Simple, but need to look for START_OBJECT/ARRAY's "off-by-one" thing: - JsonReadContext ctxt = _parsingContext; - if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { - ctxt = ctxt.getParent(); - } - // 24-Sep-2013, tatu: Unfortunate, but since we did not expose exceptions, - // need to wrap this here - try { - ctxt.setCurrentName(name); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } - - @Override - public void close() throws IOException { - if (!_closed) { - // 19-Jan-2018, tatu: as per [core#440] need to ensure no more data assumed available - _inputPtr = Math.max(_inputPtr, _inputEnd); - _closed = true; - try { - _closeInput(); - } finally { - // as per [JACKSON-324], do in finally block - // Also, internal buffer(s) can now be released as well - _releaseBuffers(); - } - } - } - - @Override - public boolean isClosed() { - return _closed; - } - - @Override - public JsonReadContext getParsingContext() { - return _parsingContext; - } - - /** - * Method that return the starting location of the current - * token; that is, position of the first character from input - * that starts the current token. - */ - @Override - public JsonLocation getTokenLocation() { - return new JsonLocation(_contentReference(), -1L, getTokenCharacterOffset(), // bytes, chars - getTokenLineNr(), getTokenColumnNr()); - } - - /** - * Method that returns location of the last processed character; - * usually for error reporting purposes - */ - @Override - public JsonLocation getCurrentLocation() { - int col = _inputPtr - _currInputRowStart + 1; // 1-based - return new JsonLocation(_contentReference(), -1L, _currInputProcessed + _inputPtr, // bytes, chars - _currInputRow, col); - } - - /* - * /********************************************************** - * /* Public API, access to token information, text and similar - * /********************************************************** - */ - - @Override - public boolean hasTextCharacters() { - if (_currToken == JsonToken.VALUE_STRING) { - return true; - } // usually true - if (_currToken == JsonToken.FIELD_NAME) { - return _nameCopied; - } - return false; - } - - @SuppressWarnings("resource") - @Override // since 2.7 - public byte[] getBinaryValue(Base64Variant variant) throws IOException { - if (_binaryValue == null) { - if (_currToken != JsonToken.VALUE_STRING) { - _reportError("Current token (" + _currToken + ") not VALUE_STRING, can not access as binary"); - } - ByteArrayBuilder builder = _getByteArrayBuilder(); - _decodeBase64(getText(), builder, variant); - _binaryValue = builder.toByteArray(); - } - return _binaryValue; - } - - /* - * /********************************************************** - * /* Public low-level accessors - * /********************************************************** - */ - - public long getTokenCharacterOffset() { - return _tokenInputTotal; - } - - public int getTokenLineNr() { - return _tokenInputRow; - } - - public int getTokenColumnNr() { - // note: value of -1 means "not available"; otherwise convert from 0-based to 1-based - int col = _tokenInputCol; - return (col < 0) ? col : (col + 1); - } - - /* - * /********************************************************** - * /* Abstract methods for sub-classes to implement - * /********************************************************** - */ - - protected abstract void _closeInput() throws IOException; - - /* - * /********************************************************** - * /* Low-level reading, other - * /********************************************************** - */ - - /** - * 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). - * - * @throws IOException Not thrown by base implementation but could be thrown - * by sub-classes - */ - protected void _releaseBuffers() throws IOException { - _textBuffer.releaseBuffers(); - char[] buf = _nameCopyBuffer; - if (buf != null) { - _nameCopyBuffer = null; - _ioContext.releaseNameCopyBuffer(buf); - } - } - - /** - * Method called when an EOF is encountered between tokens. - * If so, it may be a legitimate EOF, but only iff there - * is no open non-root context. - */ - @Override - protected void _handleEOF() throws JsonParseException { - if (!_parsingContext.inRoot()) { - String marker = _parsingContext.inArray() ? "Array" : "Object"; - _reportInvalidEOF(String.format(": expected close marker for %s (start marker at %s)", marker, - _parsingContext.startLocation(_contentReference())), null); - } - } - - /** - * @return If no exception is thrown, {@code -1} which is used as marked for "end-of-input" - * - * @throws JsonParseException If check on {@code _handleEOF()} fails; usually because - * the current context is not root context (missing end markers in content) - * - * @since 2.4 - */ - protected final int _eofAsNextChar() throws JsonParseException { - _handleEOF(); - return -1; - } - - /* - * /********************************************************** - * /* Internal/package methods: shared/reusable builders - * /********************************************************** - */ - - public ByteArrayBuilder _getByteArrayBuilder() { - if (_byteArrayBuilder == null) { - _byteArrayBuilder = new ByteArrayBuilder(); - } else { - _byteArrayBuilder.reset(); - } - return _byteArrayBuilder; - } - - /* - * /********************************************************** - * /* Methods from former JsonNumericParserBase - * /********************************************************** - */ - - // // // Life-cycle of number-parsing - - protected final JsonToken reset(boolean negative, int intLen, int fractLen, int expLen) { - if (fractLen < 1 && expLen < 1) { // integer - return resetInt(negative, intLen); - } - return resetFloat(negative, intLen, fractLen, expLen); - } - - protected final JsonToken resetInt(boolean negative, int intLen) { - _numberNegative = negative; - _intLength = intLen; - _fractLength = 0; - _expLength = 0; - _numTypesValid = NR_UNKNOWN; // to force parsing - return JsonToken.VALUE_NUMBER_INT; - } - - protected final JsonToken resetFloat(boolean negative, int intLen, int fractLen, int expLen) { - _numberNegative = negative; - _intLength = intLen; - _fractLength = fractLen; - _expLength = expLen; - _numTypesValid = NR_UNKNOWN; // to force parsing - return JsonToken.VALUE_NUMBER_FLOAT; - } - - protected final JsonToken resetAsNaN(String valueStr, double value) { - _textBuffer.resetWithString(valueStr); - _numberDouble = value; - _numTypesValid = NR_DOUBLE; - return JsonToken.VALUE_NUMBER_FLOAT; - } - - @Override - public boolean isNaN() { - if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { - if ((_numTypesValid & NR_DOUBLE) != 0) { - // 10-Mar-2017, tatu: Alas, `Double.isFinite(d)` only added in JDK 8 - double d = _numberDouble; - return Double.isNaN(d) || Double.isInfinite(d); - } - } - return false; - } - - /* - * /********************************************************** - * /* Numeric accessors of public API - * /********************************************************** - */ - - @Override - public Number getNumberValue() throws IOException { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_UNKNOWN); // will also check event type - } - // Separate types for int types - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - if ((_numTypesValid & NR_INT) != 0) { - return _numberInt; - } - if ((_numTypesValid & NR_LONG) != 0) { - return _numberLong; - } - if ((_numTypesValid & NR_BIGINT) != 0) { - return _numberBigInt; - } - _throwInternal(); - } - - // And then floating point types. But here optimal type - // needs to be big decimal, to avoid losing any data? - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - return _numberBigDecimal; - } - if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check - _throwInternal(); - } - return _numberDouble; - } - - // NOTE: mostly copied from above - @Override - public Number getNumberValueExact() throws IOException { - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_UNKNOWN); - } - if ((_numTypesValid & NR_INT) != 0) { - return _numberInt; - } - if ((_numTypesValid & NR_LONG) != 0) { - return _numberLong; - } - if ((_numTypesValid & NR_BIGINT) != 0) { - return _numberBigInt; - } - _throwInternal(); - } - // 09-Jul-2020, tatu: [databind#2644] requires we will retain accuracy, so: - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_BIGDECIMAL); - } - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - return _numberBigDecimal; - } - if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check - _throwInternal(); - } - return _numberDouble; - } - - @Override - public NumberType getNumberType() throws IOException { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_UNKNOWN); // will also check event type - } - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - if ((_numTypesValid & NR_INT) != 0) { - return NumberType.INT; - } - if ((_numTypesValid & NR_LONG) != 0) { - return NumberType.LONG; - } - return NumberType.BIG_INTEGER; - } - - /* - * And then floating point types. Here optimal type - * needs to be big decimal, to avoid losing any data? - * However... using BD is slow, so let's allow returning - * double as type if no explicit call has been made to access - * data as BD? - */ - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - return NumberType.BIG_DECIMAL; - } - return NumberType.DOUBLE; - } - - @Override - public int getIntValue() throws IOException { - if ((_numTypesValid & NR_INT) == 0) { - if (_numTypesValid == NR_UNKNOWN) { // not parsed at all - return _parseIntValue(); - } - if ((_numTypesValid & NR_INT) == 0) { // wasn't an int natively? - convertNumberToInt(); // let's make it so, if possible - } - } - return _numberInt; - } - - @Override - public long getLongValue() throws IOException { - if ((_numTypesValid & NR_LONG) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_LONG); - } - if ((_numTypesValid & NR_LONG) == 0) { - convertNumberToLong(); - } - } - return _numberLong; - } - - @Override - public BigInteger getBigIntegerValue() throws IOException { - if ((_numTypesValid & NR_BIGINT) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_BIGINT); - } - if ((_numTypesValid & NR_BIGINT) == 0) { - convertNumberToBigInteger(); - } - } - return _numberBigInt; - } - - @Override - public float getFloatValue() throws IOException { - double value = getDoubleValue(); - /* - * 22-Jan-2009, tatu: Bounds/range checks would be tricky - * here, so let's not bother even trying... - */ - /* - * if (value < -Float.MAX_VALUE || value > MAX_FLOAT_D) { - * _reportError("Numeric value ("+getText()+") out of range of Java float"); - * } - */ - return (float) value; - } - - @Override - public double getDoubleValue() throws IOException { - if ((_numTypesValid & NR_DOUBLE) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_DOUBLE); - } - if ((_numTypesValid & NR_DOUBLE) == 0) { - convertNumberToDouble(); - } - } - return _numberDouble; - } - - @Override - public BigDecimal getDecimalValue() throws IOException { - if ((_numTypesValid & NR_BIGDECIMAL) == 0) { - if (_numTypesValid == NR_UNKNOWN) { - _parseNumericValue(NR_BIGDECIMAL); - } - if ((_numTypesValid & NR_BIGDECIMAL) == 0) { - convertNumberToBigDecimal(); - } - } - return _numberBigDecimal; - } - - /* - * /********************************************************** - * /* Conversion from textual to numeric representation - * /********************************************************** - */ - - /** - * Method that will parse actual numeric value out of a syntactically - * valid number value. Type it will parse into depends on whether - * it is a floating point number, as well as its magnitude: smallest - * legal type (of ones available) is used for efficiency. - * - * @param expType Numeric type that we will immediately need, if any; - * mostly necessary to optimize handling of floating point numbers - * - * @throws IOException If there are problems reading content - * @throws JsonParseException If there are problems decoding number value - */ - protected void _parseNumericValue(int expType) throws IOException { - // 12-Jun-2020, tatu: Sanity check to prevent more cryptic error for this case. - // (note: could alternatively see if TextBuffer has aggregated contents, avoid - // exception -- but that might be more confusing) - if (_closed) { - _reportError("Internal error: _parseNumericValue called when parser instance closed"); - } - - // Int or float? - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - final int len = _intLength; - // First: optimization for simple int - if (len <= 9) { - _numberInt = _textBuffer.contentsAsInt(_numberNegative); - _numTypesValid = NR_INT; - return; - } - if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls - long l = _textBuffer.contentsAsLong(_numberNegative); - // Might still fit in int, need to check - if (len == 10) { - if (_numberNegative) { - if (l >= MIN_INT_L) { - _numberInt = (int) l; - _numTypesValid = NR_INT; - return; - } - } else { - if (l <= MAX_INT_L) { - _numberInt = (int) l; - _numTypesValid = NR_INT; - return; - } - } - } - _numberLong = l; - _numTypesValid = NR_LONG; - return; - } - _parseSlowInt(expType); - return; - } - if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) { - _parseSlowFloat(expType); - return; - } - _reportError("Current token (%s) not numeric, can not use numeric value accessors", _currToken); - } - - // @since 2.6 - protected int _parseIntValue() throws IOException { - // 12-Jun-2020, tatu: Sanity check to prevent more cryptic error for this case. - // (note: could alternatively see if TextBuffer has aggregated contents, avoid - // exception -- but that might be more confusing) - if (_closed) { - _reportError("Internal error: _parseNumericValue called when parser instance closed"); - } - // Inlined variant of: _parseNumericValue(NR_INT) - if (_currToken == JsonToken.VALUE_NUMBER_INT) { - if (_intLength <= 9) { - int i = _textBuffer.contentsAsInt(_numberNegative); - _numberInt = i; - _numTypesValid = NR_INT; - return i; - } - } - // if not optimizable, use more generic - _parseNumericValue(NR_INT); - if ((_numTypesValid & NR_INT) == 0) { - convertNumberToInt(); - } - return _numberInt; - } - - private void _parseSlowFloat(int expType) throws IOException { - /* - * Nope: floating point. Here we need to be careful to get - * optimal parsing strategy: choice is between accurate but - * slow (BigDecimal) and lossy but fast (Double). For now - * let's only use BD when explicitly requested -- it can - * still be constructed correctly at any point since we do - * retain textual representation - */ - try { - if (expType == NR_BIGDECIMAL) { - _numberBigDecimal = _textBuffer.contentsAsDecimal(); - _numTypesValid = NR_BIGDECIMAL; - } else { - // Otherwise double has to do - _numberDouble = _textBuffer.contentsAsDouble(); - _numTypesValid = NR_DOUBLE; - } - } catch (NumberFormatException nex) { - // Can this ever occur? Due to overflow, maybe? - _wrapError("Malformed numeric value (" + _longNumberDesc(_textBuffer.contentsAsString()) + ")", nex); - } - } - - private void _parseSlowInt(int expType) throws IOException { - String numStr = _textBuffer.contentsAsString(); - try { - int len = _intLength; - char[] buf = _textBuffer.getTextBuffer(); - int offset = _textBuffer.getTextOffset(); - if (_numberNegative) { - ++offset; - } - // Some long cases still... - if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) { - // Probably faster to construct a String, call parse, than to use BigInteger - _numberLong = Long.parseLong(numStr); - _numTypesValid = NR_LONG; - } else { - // 16-Oct-2018, tatu: Need to catch "too big" early due to [jackson-core#488] - if ((expType == NR_INT) || (expType == NR_LONG)) { - _reportTooLongIntegral(expType, numStr); - } - if ((expType == NR_DOUBLE) || (expType == NR_FLOAT)) { - _numberDouble = NumberInput.parseDouble(numStr); - _numTypesValid = NR_DOUBLE; - } else { - // nope, need the heavy guns... (rare case) - _numberBigInt = new BigInteger(numStr); - _numTypesValid = NR_BIGINT; - } - } - } catch (NumberFormatException nex) { - // Can this ever occur? Due to overflow, maybe? - _wrapError("Malformed numeric value (" + _longNumberDesc(numStr) + ")", nex); - } - } - - // @since 2.9.8 - protected void _reportTooLongIntegral(int expType, String rawNum) throws IOException { - if (expType == NR_INT) { - reportOverflowInt(rawNum); - } else { - reportOverflowLong(rawNum); - } - } - - /* - * /********************************************************** - * /* Numeric conversions - * /********************************************************** - */ - - protected void convertNumberToInt() throws IOException { - // First, converting from long ought to be easy - if ((_numTypesValid & NR_LONG) != 0) { - // Let's verify it's lossless conversion by simple roundtrip - int result = (int) _numberLong; - if (((long) result) != _numberLong) { - reportOverflowInt(getText(), currentToken()); - } - _numberInt = result; - } else if ((_numTypesValid & NR_BIGINT) != 0) { - if (BI_MIN_INT.compareTo(_numberBigInt) > 0 || BI_MAX_INT.compareTo(_numberBigInt) < 0) { - reportOverflowInt(); - } - _numberInt = _numberBigInt.intValue(); - } else if ((_numTypesValid & NR_DOUBLE) != 0) { - // Need to check boundaries - if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) { - reportOverflowInt(); - } - _numberInt = (int) _numberDouble; - } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - if (BD_MIN_INT.compareTo(_numberBigDecimal) > 0 || BD_MAX_INT.compareTo(_numberBigDecimal) < 0) { - reportOverflowInt(); - } - _numberInt = _numberBigDecimal.intValue(); - } else { - _throwInternal(); - } - _numTypesValid |= NR_INT; - } - - protected void convertNumberToLong() throws IOException { - if ((_numTypesValid & NR_INT) != 0) { - _numberLong = _numberInt; - } else if ((_numTypesValid & NR_BIGINT) != 0) { - if (BI_MIN_LONG.compareTo(_numberBigInt) > 0 || BI_MAX_LONG.compareTo(_numberBigInt) < 0) { - reportOverflowLong(); - } - _numberLong = _numberBigInt.longValue(); - } else if ((_numTypesValid & NR_DOUBLE) != 0) { - // Need to check boundaries - if (_numberDouble < MIN_LONG_D || _numberDouble > MAX_LONG_D) { - reportOverflowLong(); - } - _numberLong = (long) _numberDouble; - } else if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - if (BD_MIN_LONG.compareTo(_numberBigDecimal) > 0 || BD_MAX_LONG.compareTo(_numberBigDecimal) < 0) { - reportOverflowLong(); - } - _numberLong = _numberBigDecimal.longValue(); - } else { - _throwInternal(); - } - _numTypesValid |= NR_LONG; - } - - protected void convertNumberToBigInteger() { - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - // here it'll just get truncated, no exceptions thrown - _numberBigInt = _numberBigDecimal.toBigInteger(); - } else if ((_numTypesValid & NR_LONG) != 0) { - _numberBigInt = BigInteger.valueOf(_numberLong); - } else if ((_numTypesValid & NR_INT) != 0) { - _numberBigInt = BigInteger.valueOf(_numberInt); - } else if ((_numTypesValid & NR_DOUBLE) != 0) { - _numberBigInt = BigDecimal.valueOf(_numberDouble).toBigInteger(); - } else { - _throwInternal(); - } - _numTypesValid |= NR_BIGINT; - } - - protected void convertNumberToDouble() { - /* - * 05-Aug-2008, tatus: Important note: this MUST start with - * more accurate representations, since we don't know which - * value is the original one (others get generated when - * requested) - */ - - if ((_numTypesValid & NR_BIGDECIMAL) != 0) { - _numberDouble = _numberBigDecimal.doubleValue(); - } else if ((_numTypesValid & NR_BIGINT) != 0) { - _numberDouble = _numberBigInt.doubleValue(); - } else if ((_numTypesValid & NR_LONG) != 0) { - _numberDouble = (double) _numberLong; - } else if ((_numTypesValid & NR_INT) != 0) { - _numberDouble = _numberInt; - } else { - _throwInternal(); - } - _numTypesValid |= NR_DOUBLE; - } - - protected void convertNumberToBigDecimal() throws IOException { - /* - * 05-Aug-2008, tatus: Important note: this MUST start with - * more accurate representations, since we don't know which - * value is the original one (others get generated when - * requested) - */ - - if ((_numTypesValid & NR_DOUBLE) != 0) { - /* - * Let's actually parse from String representation, to avoid - * rounding errors that non-decimal floating operations could incur - */ - _numberBigDecimal = NumberInput.parseBigDecimal(getText()); - } else if ((_numTypesValid & NR_BIGINT) != 0) { - _numberBigDecimal = new BigDecimal(_numberBigInt); - } else if ((_numTypesValid & NR_LONG) != 0) { - _numberBigDecimal = BigDecimal.valueOf(_numberLong); - } else if ((_numTypesValid & NR_INT) != 0) { - _numberBigDecimal = BigDecimal.valueOf(_numberInt); - } else { - _throwInternal(); - } - _numTypesValid |= NR_BIGDECIMAL; - } - - /* - * /********************************************************** - * /* Internal/package methods: Error reporting - * /********************************************************** - */ - - protected void _reportMismatchedEndMarker(int actCh, char expCh) throws JsonParseException { - JsonReadContext ctxt = getParsingContext(); - _reportError(String.format("Unexpected close marker '%s': expected '%c' (for %s starting at %s)", (char) actCh, - expCh, ctxt.typeDesc(), ctxt.startLocation(_contentReference()))); - } - - @SuppressWarnings("deprecation") - 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; - } - - /** - * Method called to report a problem with unquoted control character. - * Note: it is possible to suppress some instances of - * exception by enabling - * {@link com.azure.json.implementation.jackson.core.json.JsonReadFeature#ALLOW_UNESCAPED_CONTROL_CHARS}. - * - * @param i Invalid control character - * @param ctxtDesc Addition description of context to use in exception message - * - * @throws JsonParseException explaining the problem - */ - @SuppressWarnings("deprecation") - 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); - } - } - - /** - * @return Description to use as "valid tokens" in an exception message about - * invalid (unrecognized) JSON token: called when parser finds something that - * looks like unquoted textual token - * - * @since 2.10 - */ - protected String _validJsonTokenList() { - return _validJsonValueList(); - } - - /** - * @return Description to use as "valid JSON values" in an exception message about - * invalid (unrecognized) JSON value: called when parser finds something that - * does not look like a value or separator. - * - * @since 2.10 - */ - @SuppressWarnings("deprecation") - protected String _validJsonValueList() { - if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) { - return "(JSON String, Number (or 'NaN'/'Infinity'/'+Infinity'/'-Infinity'), Array, Object or token 'null', 'true' or 'false')"; - } - return "(JSON String, Number, Array, Object or token 'null', 'true' or 'false')"; - } - - /* - * /********************************************************** - * /* Base64 handling support - * /********************************************************** - */ - - /** - * Method that sub-classes must implement to support escaped sequences - * in base64-encoded sections. - * Sub-classes that do not need base64 support can leave this as is - * - * @return Character decoded, if any - * - * @throws IOException If escape decoding fails - */ - protected char _decodeEscaped() throws IOException { - throw new UnsupportedOperationException(); - } - - protected final int _decodeBase64Escape(Base64Variant b64variant, int ch, int index) throws IOException { - // 17-May-2011, tatu: As per [JACKSON-xxx], need to handle escaped chars - if (ch != '\\') { - throw reportInvalidBase64Char(b64variant, ch, index); - } - int unescaped = _decodeEscaped(); - // if white space, skip if first triplet; otherwise errors - if (unescaped <= INT_SPACE) { - if (index == 0) { // whitespace only allowed to be skipped between triplets - return -1; - } - } - // otherwise try to find actual triplet value - int bits = b64variant.decodeBase64Char(unescaped); - if (bits < 0) { - if (bits != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidBase64Char(b64variant, unescaped, index); - } - } - return bits; - } - - protected final int _decodeBase64Escape(Base64Variant b64variant, char ch, int index) throws IOException { - if (ch != '\\') { - throw reportInvalidBase64Char(b64variant, ch, index); - } - char unescaped = _decodeEscaped(); - // if white space, skip if first triplet; otherwise errors - if (unescaped <= INT_SPACE) { - if (index == 0) { // whitespace only allowed to be skipped between triplets - return -1; - } - } - // otherwise try to find actual triplet value - int bits = b64variant.decodeBase64Char(unescaped); - if (bits < 0) { - // second check since padding can only be 3rd or 4th byte (index #2 or #3) - if ((bits != Base64Variant.BASE64_VALUE_PADDING) || (index < 2)) { - throw reportInvalidBase64Char(b64variant, unescaped, index); - } - } - return bits; - } - - protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex) - throws IllegalArgumentException { - return reportInvalidBase64Char(b64variant, ch, bindex, null); - } - - /* - * @param bindex Relative index within base64 character unit; between 0 - * and 3 (as unit has exactly 4 characters) - */ - protected IllegalArgumentException reportInvalidBase64Char(Base64Variant b64variant, int ch, int bindex, String msg) - throws IllegalArgumentException { - String base; - if (ch <= INT_SPACE) { - base = String.format( - "Illegal white space character (code 0x%s) as character #%d of 4-char base64 unit: can only used between units", - Integer.toHexString(ch), (bindex + 1)); - } else if (b64variant.usesPaddingChar(ch)) { - base = "Unexpected padding character ('" + b64variant.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 '" + ((char) ch) + "' (code 0x" + Integer.toHexString(ch) + ") in base64 content"; - } - if (msg != null) { - base = base + ": " + msg; - } - return new IllegalArgumentException(base); - } - - // since 2.9.8 - protected void _handleBase64MissingPadding(Base64Variant b64variant) throws IOException { - _reportError(b64variant.missingPaddingMessage()); - } - - /* - * /********************************************************** - * /* Internal/package methods: other - * /********************************************************** - */ - - /** - * @return Source reference - * @since 2.9 - * @deprecated Since 2.13, use {@link #_contentReference()} instead. - */ - @Deprecated - protected Object _getSourceReference() { - if (Feature.INCLUDE_SOURCE_IN_LOCATION.enabledIn(_features)) { - return _ioContext.contentReference().getRawContent(); - } - return null; - } - - /** - * Helper method used to encapsulate logic of including (or not) of - * "content reference" when constructing {@link JsonLocation} instances. - * - * @return Source reference object, if any; {@code null} if none - * - * @since 2.13 - */ - protected ContentReference _contentReference() { - if (Feature.INCLUDE_SOURCE_IN_LOCATION.enabledIn(_features)) { - return _ioContext.contentReference(); - } - return ContentReference.unknown(); - } - - protected static int[] growArrayBy(int[] arr, int more) { - if (arr == null) { - return new int[more]; - } - return Arrays.copyOf(arr, arr.length + more); - } - - /* - * /********************************************************** - * /* Stuff that was abstract and required before 2.8, but that - * /* is not mandatory in 2.8 or above. - * /********************************************************** - */ - - @Deprecated // since 2.8 - protected void loadMoreGuaranteed() throws IOException { - if (!loadMore()) { - _reportInvalidEOF(); - } - } - - @Deprecated // since 2.8 - protected boolean loadMore() { - return false; - } - - // Can't declare as deprecated, for now, but shouldn't be needed - protected void _finishString() throws IOException { - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/ParserMinimalBase.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/ParserMinimalBase.java deleted file mode 100644 index 61b9b2ef1646..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/ParserMinimalBase.java +++ /dev/null @@ -1,821 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.base; - -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; - -import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.exc.InputCoercionException; -import com.azure.json.implementation.jackson.core.io.JsonEOFException; -import com.azure.json.implementation.jackson.core.io.NumberInput; -import com.azure.json.implementation.jackson.core.util.ByteArrayBuilder; -import com.azure.json.implementation.jackson.core.util.VersionUtil; - -import static com.azure.json.implementation.jackson.core.JsonTokenId.*; - -/** - * Intermediate base class used by all Jackson {@link JsonParser} - * implementations, but does not add any additional fields that depend - * on particular method of obtaining input. - *

- * 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; - - protected final static int INT_RBRACKET = ']'; - protected final static int INT_RCURLY = '}'; - protected final static int INT_QUOTE = '"'; - protected final static int INT_APOS = '\''; - protected final static int INT_BACKSLASH = '\\'; - protected final static int INT_SLASH = '/'; - protected final static int INT_ASTERISK = '*'; - protected final static int INT_COLON = ':'; - protected final static int INT_COMMA = ','; - protected final static int INT_HASH = '#'; - - // Number chars - protected final static int INT_0 = '0'; - protected final static int INT_9 = '9'; - protected final static int INT_MINUS = '-'; - protected final static int INT_PLUS = '+'; - - protected final static int INT_PERIOD = '.'; - protected final static int INT_e = 'e'; - protected final static int INT_E = 'E'; - - protected final static char CHAR_NULL = '\0'; - - /** - * @since 2.9 - */ - protected final static byte[] NO_BYTES = new byte[0]; - - /* - * /********************************************************** - * /* Constants and fields of former 'JsonNumericParserBase' - * /********************************************************** - */ - - protected final static int NR_UNKNOWN = 0; - - // First, integer types - - protected final static int NR_INT = 0x0001; - protected final static int NR_LONG = 0x0002; - protected final static int NR_BIGINT = 0x0004; - - // And then floating point types - - protected final static int NR_DOUBLE = 0x008; - protected final static int NR_BIGDECIMAL = 0x0010; - - /** - * NOTE! Not used by JSON implementation but used by many of binary codecs - * - * @since 2.9 - */ - protected final static int NR_FLOAT = 0x020; - - // Also, we need some numeric constants - - protected final static BigInteger BI_MIN_INT = BigInteger.valueOf(Integer.MIN_VALUE); - protected final static BigInteger BI_MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); - - protected final static BigInteger BI_MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE); - protected final static BigInteger BI_MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); - - protected final static BigDecimal BD_MIN_LONG = new BigDecimal(BI_MIN_LONG); - protected final static BigDecimal BD_MAX_LONG = new BigDecimal(BI_MAX_LONG); - - protected final static BigDecimal BD_MIN_INT = new BigDecimal(BI_MIN_INT); - protected final static BigDecimal BD_MAX_INT = new BigDecimal(BI_MAX_INT); - - protected final static long MIN_INT_L = Integer.MIN_VALUE; - protected final static long MAX_INT_L = Integer.MAX_VALUE; - - // These are not very accurate, but have to do... (for bounds checks) - - protected final static double MIN_LONG_D = (double) Long.MIN_VALUE; - protected final static double MAX_LONG_D = (double) Long.MAX_VALUE; - - protected final static double MIN_INT_D = Integer.MIN_VALUE; - protected final static double MAX_INT_D = Integer.MAX_VALUE; - - /* - * /********************************************************** - * /* Misc other constants - * /********************************************************** - */ - - /** - * Maximum number of characters to include in token reported - * as part of error messages. - * - * @since 2.9 - */ - protected final static int MAX_ERROR_TOKEN_LENGTH = 256; - - /* - * /********************************************************** - * /* Minimal generally useful 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; - - /* - * /********************************************************** - * /* Life-cycle - * /********************************************************** - */ - - 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 currentToken() { - return _currToken; - } - - @Override - public int currentTokenId() { - final JsonToken t = _currToken; - return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id(); - } - - @Override - public JsonToken getCurrentToken() { - return _currToken; - } - - @Deprecated - @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 boolean isExpectedNumberIntToken() { - return _currToken == JsonToken.VALUE_NUMBER_INT; - } - - @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; - } - // 23-May-2018, tatu: [core#463] Need to consider non-blocking case... - } else if (t == JsonToken.NOT_AVAILABLE) { - // Nothing much we can do except to either return `null` (which seems wrong), - // or, what we actually do, signal error - _reportError("Not enough content available for `skipChildren()`: non-blocking parser? (%s)", - getClass().getName()); - } - } - } - - /** - * Method sub-classes need to implement for verifying that end-of-content - * is acceptable at current input position. - * - * @throws JsonParseException If end-of-content is not acceptable (for example, - * missing end-object or end-array tokens) - */ - 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 = 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 = 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 = 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 { - // sub-classes tend to override so... - 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. - * - * @param str String to decode - * @param builder Builder used to buffer binary content decoded - * @param b64variant Base64 variant expected in content - * - * @throws IOException for low-level read issues, or - * {@link JsonParseException} for decoding problems - */ - protected void _decodeBase64(String str, ByteArrayBuilder builder, Base64Variant b64variant) throws IOException { - 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. - *

- * Default implementation accepts exact string {@code "null"} and nothing else - * - * @param value String value to check - * - * @return True if given value contains "null equivalent" String value (for - * content this parser handles). - * - * @since 2.3 - */ - protected boolean _hasTextualNull(String value) { - return "null".equals(value); - } - - /* - * /********************************************************** - * /* Error reporting - * /********************************************************** - */ - - protected void reportUnexpectedNumberChar(int ch, String comment) throws JsonParseException { - String msg = String.format("Unexpected character (%s) in numeric value", _getCharDesc(ch)); - if (comment != null) { - msg += ": " + comment; - } - _reportError(msg); - } - - /** - * Method called to throw an exception for input token that looks like a number - * based on first character(s), but is not valid according to rules of format. - * In case of JSON this also includes invalid forms like positive sign and - * leading zeroes. - * - * @param msg Base exception message to use - * - * @throws JsonParseException Exception that describes problem with number validity - */ - protected void reportInvalidNumber(String msg) throws JsonParseException { - _reportError("Invalid numeric value: " + msg); - } - - /** - * Method called to throw an exception for integral (not floating point) input - * token with value outside of Java signed 32-bit range when requested as {@code int}. - * Result will be {@link InputCoercionException} being thrown. - * - * @throws JsonParseException Exception that describes problem with number range validity - */ - protected void reportOverflowInt() throws IOException { - reportOverflowInt(getText()); - } - - // @since 2.10 - protected void reportOverflowInt(String numDesc) throws IOException { - reportOverflowInt(numDesc, currentToken()); - } - - // @since 2.10 - protected void reportOverflowInt(String numDesc, JsonToken inputType) throws IOException { - _reportInputCoercion(String.format("Numeric value (%s) out of range of int (%d - %s)", - _longIntegerDesc(numDesc), Integer.MIN_VALUE, Integer.MAX_VALUE), inputType, Integer.TYPE); - } - - /** - * Method called to throw an exception for integral (not floating point) input - * token with value outside of Java signed 64-bit range when requested as {@code long}. - * Result will be {@link InputCoercionException} being thrown. - * - * @throws JsonParseException Exception that describes problem with number range validity - */ - protected void reportOverflowLong() throws IOException { - reportOverflowLong(getText()); - } - - // @since 2.10 - protected void reportOverflowLong(String numDesc) throws IOException { - reportOverflowLong(numDesc, currentToken()); - } - - // @since 2.10 - protected void reportOverflowLong(String numDesc, JsonToken inputType) throws IOException { - _reportInputCoercion(String.format("Numeric value (%s) out of range of long (%d - %s)", - _longIntegerDesc(numDesc), Long.MIN_VALUE, Long.MAX_VALUE), inputType, Long.TYPE); - } - - // @since 2.10 - protected void _reportInputCoercion(String msg, JsonToken inputType, Class targetType) - throws InputCoercionException { - throw new InputCoercionException(this, msg, inputType, targetType); - } - - // @since 2.9.8 - protected String _longIntegerDesc(String rawNum) { - int rawLen = rawNum.length(); - if (rawLen < 1000) { - return rawNum; - } - if (rawNum.startsWith("-")) { - rawLen -= 1; - } - return String.format("[Integer with %d digits]", rawLen); - } - - // @since 2.9.8 - protected String _longNumberDesc(String rawNum) { - int rawLen = rawNum.length(); - if (rawLen < 1000) { - return rawNum; - } - if (rawNum.startsWith("-")) { - rawLen -= 1; - } - return String.format("[number with %d characters]", rawLen); - } - - protected void _reportUnexpectedChar(int ch, String comment) throws JsonParseException { - if (ch < 0) { // sanity check - _reportInvalidEOF(); - } - String msg = String.format("Unexpected character (%s)", _getCharDesc(ch)); - if (comment != null) { - msg += ": " + comment; - } - _reportError(msg); - } - - protected void _reportInvalidEOF() throws JsonParseException { - _reportInvalidEOF(" in " + _currToken, _currToken); - } - - // @since 2.8 - protected void _reportInvalidEOFInValue(JsonToken type) throws JsonParseException { - String msg; - if (type == JsonToken.VALUE_STRING) { - msg = " in a String value"; - } else if ((type == JsonToken.VALUE_NUMBER_INT) || (type == JsonToken.VALUE_NUMBER_FLOAT)) { - msg = " in a Number value"; - } else { - msg = " in a value"; - } - _reportInvalidEOF(msg, type); - } - - // @since 2.8 - protected void _reportInvalidEOF(String msg, JsonToken currToken) throws JsonParseException { - throw new JsonEOFException(this, currToken, "Unexpected end-of-input" + msg); - } - - /** - * @deprecated Since 2.8 use {@link #_reportInvalidEOF(String, JsonToken)} instead - * - * @throws JsonParseException Exception that describes problem with end-of-content within value - */ - @Deprecated // since 2.8 - protected void _reportInvalidEOFInValue() throws JsonParseException { - _reportInvalidEOF(" in a value"); - } - - /** - * @param msg Addition message snippet to append to base exception message - * @deprecated Since 2.8 use {@link #_reportInvalidEOF(String, JsonToken)} instead - * - * @throws JsonParseException Exception that describes problem with end-of-content within value - */ - @Deprecated // since 2.8 - protected void _reportInvalidEOF(String msg) throws JsonParseException { - throw new JsonEOFException(this, null, "Unexpected end-of-input" + msg); - } - - 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); - } - - /* - * /********************************************************** - * /* Error reporting, generic - * /********************************************************** - */ - - protected 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); - } - - // @since 2.9 - protected final void _reportError(String msg, Object arg) throws JsonParseException { - throw _constructError(String.format(msg, arg)); - } - - // @since 2.9 - protected final void _reportError(String msg, Object arg1, Object arg2) throws JsonParseException { - throw _constructError(String.format(msg, arg1, arg2)); - } - - 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); - } - - @Deprecated // since 2.11 - 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; - } - - @Deprecated // since 2.11 - protected static String _ascii(byte[] b) { - return new String(b, StandardCharsets.US_ASCII); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/package-info.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/package-info.java deleted file mode 100644 index 4236b0042bd5..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/base/package-info.java +++ /dev/null @@ -1,10 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/** - * 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.azure.json.implementation.jackson.core.JsonParser} or - * {@link com.azure.json.implementation.jackson.core.JsonGenerator}. - */ -package com.azure.json.implementation.jackson.core.base; diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/InputCoercionException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/InputCoercionException.java index 910ccdf9e2a6..7b904740c54e 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/InputCoercionException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/InputCoercionException.java @@ -2,7 +2,6 @@ package com.azure.json.implementation.jackson.core.exc; import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.util.RequestPayload; /** * Exception type for read-side problems that are not direct decoding ("parsing") @@ -27,9 +26,7 @@ public class InputCoercionException extends StreamReadException { protected final Class _targetType; /** - * Constructor that uses current parsing location as location, and - * sets processor (accessible via {@link #getProcessor()}) to - * specified parser. + * Constructor that uses current parsing location as location. * * @param p Parser in use at the point where failure occurred * @param msg Exception mesage to use @@ -42,10 +39,4 @@ public InputCoercionException(JsonParser p, String msg, JsonToken inputType, Cla _targetType = targetType; } - @Override - public InputCoercionException withRequestPayload(RequestPayload p) { - _requestPayload = p; - return this; - } - } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamReadException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamReadException.java index 98234814df6a..0b86ef397a5b 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamReadException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamReadException.java @@ -2,7 +2,6 @@ package com.azure.json.implementation.jackson.core.exc; import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.util.RequestPayload; /** * Intermediate base class for all read-side streaming processing problems, including @@ -17,79 +16,13 @@ public abstract class StreamReadException extends JsonProcessingException { protected transient JsonParser _processor; - /** - * Optional payload that can be assigned to pass along for error reporting - * or handling purposes. Core streaming parser implementations DO NOT - * initialize this; it is up to using applications and frameworks to - * populate it. - */ - protected RequestPayload _requestPayload; - protected StreamReadException(JsonParser p, String msg) { - super(msg, (p == null) ? null : p.getCurrentLocation()); + super(msg, (p == null) ? null : p.currentLocation()); _processor = p; } protected StreamReadException(JsonParser p, String msg, Throwable root) { - super(msg, (p == null) ? null : p.getCurrentLocation(), root); - _processor = p; - } - - protected StreamReadException(JsonParser p, String msg, JsonLocation loc) { - super(msg, loc, null); + super(msg, (p == null) ? null : p.currentLocation(), root); _processor = p; } - - protected StreamReadException(String msg, JsonLocation loc, Throwable rootCause) { - super(msg, loc, rootCause); - } - - /** - * Fluent method that may be used to assign payload to this exception, - * to let recipient access it for diagnostics purposes. - *

- * NOTE: `this` instance is modified and no new instance is constructed. - * - * @param payload Payload to assign to this exception - * - * @return This exception instance to allow call chaining - */ - public abstract StreamReadException withRequestPayload(RequestPayload payload); - - @Override - public JsonParser getProcessor() { - return _processor; - } - - /** - * Method that may be called to find payload that was being parsed, if - * one was specified for parser that threw this Exception. - * - * @return request body, if payload was specified; `null` otherwise - */ - public RequestPayload getRequestPayload() { - return _requestPayload; - } - - /** - * The method returns the String representation of the request payload if - * one was specified for parser that threw this Exception. - * - * @return request body as String, if payload was specified; `null` otherwise - */ - public String getRequestPayloadAsString() { - return (_requestPayload != null) ? _requestPayload.toString() : null; - } - - /** - * Overriding the getMessage() to include the request body - */ - @Override - public String getMessage() { - String msg = super.getMessage(); - if (_requestPayload != null) { - msg += "\nRequest payload : " + _requestPayload; - } - return msg; - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamWriteException.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamWriteException.java index d86aaa6e0170..3a01bd3853e7 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamWriteException.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/exc/StreamWriteException.java @@ -16,23 +16,8 @@ public abstract class StreamWriteException extends JsonProcessingException { protected transient JsonGenerator _processor; - protected StreamWriteException(Throwable rootCause, JsonGenerator g) { - super(rootCause); - _processor = g; - } - protected StreamWriteException(String msg, JsonGenerator g) { - super(msg, (JsonLocation) null); - _processor = g; - } - - protected StreamWriteException(String msg, Throwable rootCause, JsonGenerator g) { - super(msg, null, rootCause); + super(msg, null); _processor = g; } - - @Override - public JsonGenerator getProcessor() { - return _processor; - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/BigDecimalParser.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/BigDecimalParser.java deleted file mode 100644 index 29cf62cba750..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/BigDecimalParser.java +++ /dev/null @@ -1,182 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.io; - -import java.math.BigDecimal; -import java.util.Arrays; - -// Based on a great idea of Eric Obermühlner to use a tree of smaller BigDecimals for parsing -// really big numbers with O(n^1.5) complexity instead of O(n^2) when using the constructor -// for a decimal representation from JDK 8/11: -// -// https://github.com/eobermuhlner/big-math/commit/7a5419aac8b2adba2aa700ccf00197f97b2ad89f - -/** - * Helper class used to implement more optimized parsing of {@link BigDecimal} for REALLY - * big values (over 500 characters) - *

- * Based on ideas from this - * this - * git commit. - * - * @since 2.13 - */ -public final class BigDecimalParser { - private final char[] chars; - - BigDecimalParser(char[] chars) { - this.chars = chars; - } - - public static BigDecimal parse(String valueStr) { - return parse(valueStr.toCharArray()); - } - - public static BigDecimal parse(char[] chars, int off, int len) { - if (off > 0 || len != chars.length) { - chars = Arrays.copyOfRange(chars, off, off + len); - } - return parse(chars); - } - - public static BigDecimal parse(char[] chars) { - final int len = chars.length; - try { - if (len < 500) { - return new BigDecimal(chars); - } - return new BigDecimalParser(chars).parseBigDecimal(len / 10); - } catch (NumberFormatException e) { - String desc = e.getMessage(); - // 05-Feb-2021, tatu: Alas, JDK mostly has null message so: - if (desc == null) { - desc = "Not a valid number representation"; - } - throw new NumberFormatException("Value \"" + new String(chars) - + "\" can not be represented as `java.math.BigDecimal`, reason: " + desc); - } - } - - private BigDecimal parseBigDecimal(final int splitLen) { - boolean numHasSign = false; - boolean expHasSign = false; - boolean neg = false; - int numIdx = 0; - int expIdx = -1; - int dotIdx = -1; - int scale = 0; - final int len = chars.length; - - for (int i = 0; i < len; i++) { - char c = chars[i]; - switch (c) { - case '+': - if (expIdx >= 0) { - if (expHasSign) { - throw new NumberFormatException("Multiple signs in exponent"); - } - expHasSign = true; - } else { - if (numHasSign) { - throw new NumberFormatException("Multiple signs in number"); - } - numHasSign = true; - numIdx = i + 1; - } - break; - - case '-': - if (expIdx >= 0) { - if (expHasSign) { - throw new NumberFormatException("Multiple signs in exponent"); - } - expHasSign = true; - } else { - if (numHasSign) { - throw new NumberFormatException("Multiple signs in number"); - } - numHasSign = true; - neg = true; - numIdx = i + 1; - } - break; - - case 'e': - case 'E': - if (expIdx >= 0) { - throw new NumberFormatException("Multiple exponent markers"); - } - expIdx = i; - break; - - case '.': - if (dotIdx >= 0) { - throw new NumberFormatException("Multiple decimal points"); - } - dotIdx = i; - break; - - default: - if (dotIdx >= 0 && expIdx == -1) { - scale++; - } - } - } - - int numEndIdx; - int exp = 0; - if (expIdx >= 0) { - numEndIdx = expIdx; - String expStr = new String(chars, expIdx + 1, len - expIdx - 1); - exp = Integer.parseInt(expStr); - scale = adjustScale(scale, exp); - } else { - numEndIdx = len; - } - - BigDecimal res; - - if (dotIdx >= 0) { - int leftLen = dotIdx - numIdx; - BigDecimal left = toBigDecimalRec(numIdx, leftLen, exp, splitLen); - - int rightLen = numEndIdx - dotIdx - 1; - BigDecimal right = toBigDecimalRec(dotIdx + 1, rightLen, exp - rightLen, splitLen); - - res = left.add(right); - } else { - res = toBigDecimalRec(numIdx, numEndIdx - numIdx, exp, splitLen); - } - - if (scale != 0) { - res = res.setScale(scale); - } - - if (neg) { - res = res.negate(); - } - - return res; - } - - private int adjustScale(int scale, long exp) { - long adjScale = scale - exp; - if (adjScale > Integer.MAX_VALUE || adjScale < Integer.MIN_VALUE) { - throw new NumberFormatException( - "Scale out of range: " + adjScale + " while adjusting scale " + scale + " to exponent " + exp); - } - - return (int) adjScale; - } - - private BigDecimal toBigDecimalRec(int off, int len, int scale, int splitLen) { - if (len > splitLen) { - int mid = len / 2; - BigDecimal left = toBigDecimalRec(off, mid, scale + len - mid, splitLen); - BigDecimal right = toBigDecimalRec(off + mid, len - mid, scale, splitLen); - - return left.add(right); - } - - return len == 0 ? BigDecimal.ZERO : new BigDecimal(chars, off, len).movePointRight(scale); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharTypes.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharTypes.java index 1c53e5f5bd2a..c276b1ec3d0c 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharTypes.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharTypes.java @@ -65,49 +65,6 @@ public final class CharTypes { 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. @@ -127,30 +84,6 @@ public final class CharTypes { 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. @@ -161,7 +94,7 @@ public final class CharTypes { // 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; + table[i] = -1; } // Others (and some within that range too) have explicit shorter sequences table['"'] = '"'; @@ -202,14 +135,6 @@ public static int[] getInputCodeUtf8() { return sInputCodesUTF8; } - public static int[] getInputCodeLatin1JsNames() { - return sInputCodesJsNames; - } - - public static int[] getInputCodeUtf8JsNames() { - return sInputCodesUtf8JsNames; - } - public static int[] getInputCodeComment() { return sInputCodesComment; } @@ -227,24 +152,6 @@ public static int[] get7BitOutputEscapes() { return sOutputEscapes128; } - /** - * Alternative to {@link #get7BitOutputEscapes()} when a non-standard quote character - * is used. - * - * @param quoteChar Character used for quoting textual values and property names; - * usually double-quote but sometimes changed to single-quote (apostrophe) - * - * @return 128-entry {@code int[]} that contains escape definitions - * - * @since 2.10 - */ - public static int[] get7BitOutputEscapes(int quoteChar) { - if (quoteChar == '"') { - return sOutputEscapes128; - } - return AltEscapes.instance.escapesFor(quoteChar); - } - public static int charToHex(int ch) { // 08-Nov-2019, tatu: As per [core#540] and [core#578], changed to // force masking here so caller need not do that. @@ -305,29 +212,4 @@ public static byte[] copyHexBytes() { return HB.clone(); } - /** - * Helper used for lazy initialization of alternative escape (quoting) - * table, used for escaping content that uses non-standard quote - * character (usually apostrophe). - * - * @since 2.10 - */ - private static class AltEscapes { - public final static AltEscapes instance = new AltEscapes(); - - private final int[][] _altEscapes = new int[128][]; - - public int[] escapesFor(int quoteChar) { - int[] esc = _altEscapes[quoteChar]; - if (esc == null) { - esc = Arrays.copyOf(sOutputEscapes128, 128); - // Only add escape setting if character does not already have it - if (esc[quoteChar] == 0) { - esc[quoteChar] = CharacterEscapes.ESCAPE_STANDARD; - } - _altEscapes[quoteChar] = esc; - } - return esc; - } - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharacterEscapes.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharacterEscapes.java deleted file mode 100644 index 85c1cef16ba2..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/CharacterEscapes.java +++ /dev/null @@ -1,57 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.io; - -import com.azure.json.implementation.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 - * 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 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. - * - * @param ch Character to look escape sequence for - * - * @return Escape sequence to use for the character, if any; {@code null} if not - */ - public abstract SerializableString getEscapeSequence(int ch); - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/ContentReference.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/ContentReference.java index fecc802fa589..bd63badf7090 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/ContentReference.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/ContentReference.java @@ -97,36 +97,8 @@ public static ContentReference unknown() { return UNKNOWN_CONTENT; } - public static ContentReference construct(boolean isContentTextual, Object rawContent) { - return new ContentReference(isContentTextual, rawContent); - } - - public static ContentReference construct(boolean isContentTextual, Object rawContent, int offset, int length) { - return new ContentReference(isContentTextual, rawContent, offset, length); - } - - /** - * Factory method for legacy code to use for constructing instances to - * content about which only minimal amount of information is available. - * Assumed not to contain textual content (no snippet displayed). - * - * @param isContentTextual Is raw content assumed to have textual content - * ({@code true}) or binary ({@code false}) - * @param rawContent Underlying raw content access - * - * @return Instance with minimal information about content (basically just - * raw content reference without offsets - */ - public static ContentReference rawReference(boolean isContentTextual, Object rawContent) { - // Just to avoid russian-doll-nesting, let's: - if (rawContent instanceof ContentReference) { - return (ContentReference) rawContent; - } - return new ContentReference(isContentTextual, rawContent); - } - - public static ContentReference rawReference(Object rawContent) { - return rawReference(false, rawContent); + public static ContentReference construct(Object rawContent) { + return new ContentReference(true, rawContent); } /* diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/IOContext.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/IOContext.java index cce147feede3..c48641a623ba 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/IOContext.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/IOContext.java @@ -26,14 +26,6 @@ public class IOContext { */ protected final ContentReference _contentReference; - /** - * Old, deprecated "raw" reference to input source. - * - * @deprecated Since 2.13, use {@link #_contentReference} instead - */ - @Deprecated - protected final Object _sourceRef; - /** * Encoding used by the underlying stream, if known. */ @@ -72,12 +64,6 @@ public class IOContext { */ 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 @@ -118,15 +104,9 @@ public class IOContext { public IOContext(BufferRecycler br, ContentReference contentRef, boolean managedResource) { _bufferRecycler = br; _contentReference = contentRef; - _sourceRef = contentRef.getRawContent(); _managedResource = managedResource; } - @Deprecated // since 2.13 - public IOContext(BufferRecycler br, Object rawContent, boolean managedResource) { - this(br, ContentReference.rawReference(rawContent), managedResource); - } - public void setEncoding(JsonEncoding enc) { _encoding = enc; } @@ -157,15 +137,6 @@ public ContentReference contentReference() { return _contentReference; } - /** - * @deprecated Since 2.13, use {@link #contentReference()} instead - * @return "Raw" source reference - */ - @Deprecated - public Object getSourceReference() { - return _sourceRef; - } - /* * /********************************************************************** * /* Public API, buffer management @@ -202,19 +173,6 @@ public byte[] allocWriteEncodingBuffer() { return (_writeEncodingBuffer = _bufferRecycler.allocByteBuffer(BufferRecycler.BYTE_WRITE_ENCODING_BUFFER)); } - /** - * Method for recycling or allocation byte buffer of "base 64 encode/decode" type. - *

- * Note: the method can only be called once during its life cycle. - * This is to protect against accidental sharing. - * - * @return Allocated or recycled byte buffer - */ - 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)); @@ -231,11 +189,6 @@ public char[] allocConcatBuffer() { 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. @@ -262,14 +215,6 @@ public void releaseWriteEncodingBuffer(byte[] 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); diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/InputDecorator.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/InputDecorator.java deleted file mode 100644 index fb31bdc375d4..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/InputDecorator.java +++ /dev/null @@ -1,72 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.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 Serializable // since 2.1 -{ - private static final long serialVersionUID = 1L; - - /** - * Method called by {@link com.azure.json.implementation.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' - * - * @throws IOException if construction of {@link InputStream} fails - */ - public abstract InputStream decorate(IOContext ctxt, InputStream in) throws IOException; - - /** - * Method called by {@link com.azure.json.implementation.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 - * - * @throws IOException if construction of {@link InputStream} fails - */ - public abstract InputStream decorate(IOContext ctxt, byte[] src, int offset, int length) throws IOException; - - /** - * Method called by {@link com.azure.json.implementation.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}) - * - * @throws IOException if construction of {@link Reader} fails - */ - public abstract Reader decorate(IOContext ctxt, Reader r) throws IOException; -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/JsonStringEncoder.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/JsonStringEncoder.java index 0c29eebc2241..f394a9bb991b 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/JsonStringEncoder.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/JsonStringEncoder.java @@ -4,7 +4,6 @@ import java.util.Arrays; import com.azure.json.implementation.jackson.core.util.ByteArrayBuilder; -import com.azure.json.implementation.jackson.core.util.TextBuffer; /** * Helper class used for efficient encoding of JSON String values (including @@ -34,8 +33,6 @@ public final class JsonStringEncoder { // to estimate ok initial encoding buffer, switch to segmented for // possible (but rare) big content - final static int MIN_CHAR_BUFFER_SIZE = 16; - final static int MAX_CHAR_BUFFER_SIZE = 32000; // use segments beyond final static int MIN_BYTE_BUFFER_SIZE = 24; final static int MAX_BYTE_BUFFER_SIZE = 32000; // use segments beyond @@ -67,74 +64,6 @@ public static JsonStringEncoder getInstance() { * /********************************************************************** */ - /** - * Method that will escape text contents using JSON standard escaping, - * and return results as a character array. - * - * @param input Value String to process - * - * @return JSON-escaped String matching {@code input} - */ - public char[] quoteAsString(String input) { - final int inputLen = input.length(); - char[] outputBuffer = new char[_initialCharBufSize(inputLen)]; - final int[] escCodes = CharTypes.get7BitOutputEscapes(); - final int escCodeCount = escCodes.length; - int inPtr = 0; - TextBuffer textBuffer = null; - int outPtr = 0; - char[] qbuf = null; - - outer: while (inPtr < inputLen) { - while (true) { - char c = input.charAt(inPtr); - if (c < escCodeCount && escCodes[c] != 0) { - break; - } - if (outPtr >= outputBuffer.length) { - if (textBuffer == null) { - textBuffer = TextBuffer.fromInitial(outputBuffer); - } - outputBuffer = textBuffer.finishCurrentSegment(); - outPtr = 0; - } - outputBuffer[outPtr++] = c; - if (++inPtr >= inputLen) { - break outer; - } - } - // something to escape; 2 or 6-char variant? - if (qbuf == null) { - qbuf = _qbuf(); - } - char d = input.charAt(inPtr++); - int escCode = escCodes[d]; - int length = (escCode < 0) ? _appendNumeric(d, qbuf) : _appendNamed(escCode, qbuf); - if ((outPtr + length) > outputBuffer.length) { - int first = outputBuffer.length - outPtr; - if (first > 0) { - System.arraycopy(qbuf, 0, outputBuffer, outPtr, first); - } - if (textBuffer == null) { - textBuffer = TextBuffer.fromInitial(outputBuffer); - } - outputBuffer = textBuffer.finishCurrentSegment(); - int second = length - first; - System.arraycopy(qbuf, first, outputBuffer, 0, second); - outPtr = second; - } else { - System.arraycopy(qbuf, 0, outputBuffer, outPtr, length); - outPtr += length; - } - } - - if (textBuffer == null) { - return Arrays.copyOfRange(outputBuffer, 0, outPtr); - } - textBuffer.setCurrentLength(outPtr); - return textBuffer.contentsAsArray(); - } - /** * Method that will quote text contents using JSON standard quoting, * and append results to a supplied {@link StringBuilder}. @@ -279,104 +208,6 @@ public byte[] quoteAsUTF8(String text) { return bb.completeAndCoalesce(outputPtr); } - /** - * Will encode given String as UTF-8 (without any escaping) and return - * the resulting byte array. - * - * @param text Value {@link String} to process - * - * @return UTF-8 encoded bytes of {@code text} (without any escaping) - */ - @SuppressWarnings("resource") - public byte[] encodeAsUTF8(String text) { - int inputPtr = 0; - int inputEnd = text.length(); - int outputPtr = 0; - byte[] outputBuffer = new byte[_initialByteBufSize(inputEnd)]; - int outputEnd = outputBuffer.length; - ByteArrayBuilder bb = null; - - main_loop: while (inputPtr < inputEnd) { - int c = text.charAt(inputPtr++); - - // first tight loop for ascii - while (c <= 0x7F) { - if (outputPtr >= outputEnd) { - if (bb == null) { - bb = ByteArrayBuilder.fromInitial(outputBuffer, outputPtr); - } - outputBuffer = bb.finishCurrentSegment(); - outputEnd = outputBuffer.length; - outputPtr = 0; - } - outputBuffer[outputPtr++] = (byte) c; - if (inputPtr >= inputEnd) { - break main_loop; - } - c = text.charAt(inputPtr++); - } - - // then multi-byte... - if (bb == null) { - bb = ByteArrayBuilder.fromInitial(outputBuffer, outputPtr); - } - if (outputPtr >= outputEnd) { - outputBuffer = bb.finishCurrentSegment(); - outputEnd = outputBuffer.length; - outputPtr = 0; - } - if (c < 0x800) { // 2-byte - outputBuffer[outputPtr++] = (byte) (0xc0 | (c >> 6)); - } else { // 3 or 4 bytes - // Surrogates? - if (c < SURR1_FIRST || c > SURR2_LAST) { // nope - outputBuffer[outputPtr++] = (byte) (0xe0 | (c >> 12)); - if (outputPtr >= outputEnd) { - outputBuffer = bb.finishCurrentSegment(); - outputEnd = outputBuffer.length; - outputPtr = 0; - } - outputBuffer[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - } else { // yes, surrogate pair - if (c > SURR1_LAST) { // must be from first range - _illegal(c); - } - // and if so, followed by another from next range - if (inputPtr >= inputEnd) { - _illegal(c); - } - c = _convert(c, text.charAt(inputPtr++)); - if (c > 0x10FFFF) { // illegal, as per RFC 4627 - _illegal(c); - } - outputBuffer[outputPtr++] = (byte) (0xf0 | (c >> 18)); - if (outputPtr >= outputEnd) { - outputBuffer = bb.finishCurrentSegment(); - outputEnd = outputBuffer.length; - outputPtr = 0; - } - outputBuffer[outputPtr++] = (byte) (0x80 | ((c >> 12) & 0x3f)); - if (outputPtr >= outputEnd) { - outputBuffer = bb.finishCurrentSegment(); - outputEnd = outputBuffer.length; - outputPtr = 0; - } - outputBuffer[outputPtr++] = (byte) (0x80 | ((c >> 6) & 0x3f)); - } - } - if (outputPtr >= outputEnd) { - outputBuffer = bb.finishCurrentSegment(); - outputEnd = outputBuffer.length; - outputPtr = 0; - } - outputBuffer[outputPtr++] = (byte) (0x80 | (c & 0x3f)); - } - if (bb == null) { - return Arrays.copyOfRange(outputBuffer, 0, outputPtr); - } - return bb.completeAndCoalesce(outputPtr); - } - /* * /********************************************************************** * /* Internal methods @@ -439,14 +270,6 @@ private static void _illegal(int c) { throw new IllegalArgumentException(UTF8Writer.illegalSurrogateDesc(c)); } - // non-private for unit test access - static int _initialCharBufSize(int strLen) { - // char->char won't expand but we need to give some room for escaping - // like 1/8 (12.5% expansion) but cap addition to something modest - final int estimated = Math.max(MIN_CHAR_BUFFER_SIZE, strLen + Math.min(6 + (strLen >> 3), 1000)); - return Math.min(estimated, MAX_CHAR_BUFFER_SIZE); - } - // non-private for unit test access static int _initialByteBufSize(int strLen) { // char->byte for UTF-8 can expand size by x3 itself, and escaping diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberInput.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberInput.java index 229371c3d590..c7f58cba49c6 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberInput.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberInput.java @@ -1,8 +1,6 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.io; -import java.math.BigDecimal; - @SuppressWarnings("fallthrough") public final class NumberInput { /** @@ -180,96 +178,6 @@ public static boolean inLongRange(char[] ch, int off, int len, boolean negative) 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; - // skip leading sign, if any - final char sign = s.charAt(0); - if (sign == '+') { // for plus, actually physically remove - s = s.substring(1); - len = s.length(); - } else if (sign == '-') { // minus, just skip for checks, must retain - i = 1; - } - 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; - // skip leading sign, if any - final char sign = s.charAt(0); - if (sign == '+') { // for plus, actually physically remove - s = s.substring(1); - len = s.length(); - } else if (sign == '-') { // minus, just skip for checks, must retain - i = 1; - } - 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? /* @@ -281,16 +189,4 @@ public static double parseDouble(String s) throws NumberFormatException { } return Double.parseDouble(s); } - - public static BigDecimal parseBigDecimal(String s) throws NumberFormatException { - return BigDecimalParser.parse(s); - } - - public static BigDecimal parseBigDecimal(char[] ch, int off, int len) throws NumberFormatException { - return BigDecimalParser.parse(ch, off, len); - } - - public static BigDecimal parseBigDecimal(char[] ch) throws NumberFormatException { - return BigDecimalParser.parse(ch); - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberOutput.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberOutput.java index 7e4331e7d0d8..5f93f3ae3050 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberOutput.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/NumberOutput.java @@ -292,8 +292,7 @@ public static String toString(float v) { * Since 2.10 */ public static boolean notFinite(double value) { - // before Java 8 need separate checks - return Double.isNaN(value) || Double.isInfinite(value); + return !Double.isFinite(value); } /** @@ -307,8 +306,7 @@ public static boolean notFinite(double value) { * Since 2.10 */ public static boolean notFinite(float value) { - // before Java 8 need separate checks - return Float.isNaN(value) || Float.isInfinite(value); + return !Float.isFinite(value); } /* diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/OutputDecorator.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/OutputDecorator.java deleted file mode 100644 index a3cf4f0a75a5..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/OutputDecorator.java +++ /dev/null @@ -1,43 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.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 Serializable // since 2.1 -{ - /** - * Method called by {@link com.azure.json.implementation.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 - * - * @throws IOException if construction of decorated {@link OutputStream} fails - */ - public abstract OutputStream decorate(IOContext ctxt, OutputStream out) throws IOException; - - /** - * Method called by {@link com.azure.json.implementation.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 - * - * @throws IOException if construction of decorated {@link Writer} fails - */ - public abstract Writer decorate(IOContext ctxt, Writer w) throws IOException; -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/SegmentedStringWriter.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/SegmentedStringWriter.java deleted file mode 100644 index 93be86bc8663..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/SegmentedStringWriter.java +++ /dev/null @@ -1,90 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.io; - -import java.io.*; - -import com.azure.json.implementation.jackson.core.util.BufferRecycler; -import com.azure.json.implementation.jackson.core.util.TextBuffer; - -/** - * Efficient alternative to {@link StringWriter}, based on using segmented - * internal buffer. Initial input buffer is also recyclable. - *

- * 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 - * JsonGenerator. - */ -public final class SegmentedStringWriter extends Writer { - final private 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 - * /********************************************************** - */ - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/SerializedString.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/SerializedString.java deleted file mode 100644 index bf830aa8516c..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/io/SerializedString.java +++ /dev/null @@ -1,218 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.io; - -import java.io.*; - -import com.azure.json.implementation.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. - *

- * 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, Serializable { - private static final long serialVersionUID = 1L; - - private static final JsonStringEncoder JSON_ENCODER = JsonStringEncoder.getInstance(); - - 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; - } - - /** - * Accessor for accessing value that has been quoted (escaped) using JSON - * quoting rules (using backslash-prefixed codes) into a char array. - */ - @Override - public final char[] asQuotedChars() { - char[] result = _quotedChars; - if (result == null) { - _quotedChars = result = JSON_ENCODER.quoteAsString(_value); - } - return result; - } - - /** - * Accessor for accessing value that has been quoted (escaped) using JSON - * quoting rules (using backslash-prefixed codes), and encoded using - * UTF-8 encoding into a byte array. - */ - @Override - public final byte[] asQuotedUTF8() { - byte[] result = _quotedUTF8Ref; - if (result == null) { - _quotedUTF8Ref = result = JSON_ENCODER.quoteAsUTF8(_value); - } - return result; - } - - /** - * Accessor for accessing value as is (without JSON quoting (ecaping)) - * encoded as UTF-8 byte array. - */ - @Override - public final byte[] asUnquotedUTF8() { - byte[] result = _unquotedUTF8Ref; - if (result == null) { - _unquotedUTF8Ref = result = JSON_ENCODER.encodeAsUTF8(_value); - } - return result; - } - - /* - * /********************************************************** - * /* Additional 2.0 methods for appending/writing contents - * /********************************************************** - */ - - @Override - public int appendQuoted(char[] buffer, int offset) { - char[] result = _quotedChars; - if (result == null) { - _quotedChars = result = JSON_ENCODER.quoteAsString(_value); - } - final int length = result.length; - if ((offset + length) > buffer.length) { - return -1; - } - System.arraycopy(result, 0, buffer, offset, length); - return length; - } - - @Override - public int appendQuotedUTF8(byte[] buffer, int offset) { - byte[] result = _quotedUTF8Ref; - if (result == null) { - _quotedUTF8Ref = result = JSON_ENCODER.quoteAsUTF8(_value); - } - 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 appendUnquotedUTF8(byte[] buffer, int offset) { - byte[] result = _unquotedUTF8Ref; - if (result == null) { - _unquotedUTF8Ref = result = JSON_ENCODER.encodeAsUTF8(_value); - } - final int length = result.length; - if ((offset + length) > buffer.length) { - return -1; - } - System.arraycopy(result, 0, buffer, offset, 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); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ByteSourceJsonBootstrapper.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ByteSourceJsonBootstrapper.java index 102b221a9c69..cd34220d3342 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ByteSourceJsonBootstrapper.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ByteSourceJsonBootstrapper.java @@ -2,9 +2,7 @@ package com.azure.json.implementation.jackson.core.json; import com.azure.json.implementation.jackson.core.JsonEncoding; -import com.azure.json.implementation.jackson.core.JsonFactory; import com.azure.json.implementation.jackson.core.JsonParser; -import com.azure.json.implementation.jackson.core.ObjectCodec; import com.azure.json.implementation.jackson.core.io.IOContext; import com.azure.json.implementation.jackson.core.io.MergedStream; import com.azure.json.implementation.jackson.core.io.UTF32Reader; @@ -55,21 +53,6 @@ public final class ByteSourceJsonBootstrapper { */ 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. - */ - // private int _inputProcessed; - /* * /********************************************************** * /* Data gathered @@ -225,8 +208,8 @@ public Reader constructReader() throws IOException { throw new RuntimeException("Internal error"); // should never get here } - public JsonParser constructParser(int parserFeatures, ObjectCodec codec, ByteQuadsCanonicalizer rootByteSymbols, - CharsToNameCanonicalizer rootCharSymbols, int factoryFeatures) throws IOException { + public JsonParser constructParser(int parserFeatures, ByteQuadsCanonicalizer rootByteSymbols, + CharsToNameCanonicalizer rootCharSymbols) throws IOException { int prevInputPtr = _inputPtr; JsonEncoding enc = detectEncoding(); int bytesProcessed = _inputPtr - prevInputPtr; @@ -236,22 +219,13 @@ public JsonParser constructParser(int parserFeatures, ObjectCodec codec, ByteQua * and without canonicalization, byte-based approach is not performant; 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, bytesProcessed, _bufferRecyclable); - } + ByteQuadsCanonicalizer can = rootByteSymbols.makeChild(); + return new UTF8StreamJsonParser(_context, parserFeatures, _in, can, _inputBuffer, _inputPtr, _inputEnd, + bytesProcessed, _bufferRecyclable); } - return new ReaderBasedJsonParser(_context, parserFeatures, constructReader(), codec, - rootCharSymbols.makeChild(factoryFeatures)); + return new ReaderBasedJsonParser(_context, parserFeatures, constructReader(), rootCharSymbols.makeChild()); } - /* - * /********************************************************** - * /* Encoding detection for data format auto-detection - * /********************************************************** - */ - /* * /********************************************************** * /* Internal methods, parsing diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/DupDetector.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/DupDetector.java deleted file mode 100644 index 3c59b44b4a2f..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/DupDetector.java +++ /dev/null @@ -1,99 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.json; - -import java.util.*; - -import com.azure.json.implementation.jackson.core.*; - -/** - * Helper class used if - * {@link 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 _seen; - - private DupDetector(Object src) { - _source = src; - } - - public static DupDetector rootDetector(JsonParser p) { - return new DupDetector(p); - } - - public static DupDetector rootDetector(JsonGenerator g) { - return new DupDetector(g); - } - - public DupDetector child() { - return new DupDetector(_source); - } - - public void reset() { - _firstName = null; - _secondName = null; - _seen = null; - } - - /** - * @return Source object (parser / generator) used to construct this detector - * - * @since 2.7 - */ - public Object getSource() { - return _source; - } - - /** - * Method called to check whether a newly encountered property name would - * be a duplicate within this context, and if not, update the state to remember - * having seen the property name for checking more property names - * - * @param name Property seen - * - * @return {@code True} if the property had already been seen before in this context - * - */ - public boolean isDup(String name) { - if (_firstName == null) { - _firstName = name; - return false; - } - if (name.equals(_firstName)) { - return true; - } - if (_secondName == null) { - _secondName = name; - return false; - } - if (name.equals(_secondName)) { - return true; - } - if (_seen == null) { - _seen = new HashSet<>(16); // 16 is default, seems reasonable - _seen.add(_firstName); - _seen.add(_secondName); - } - return !_seen.add(name); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonGeneratorImpl.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonGeneratorImpl.java deleted file mode 100644 index 3cd36e6ab7ac..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonGeneratorImpl.java +++ /dev/null @@ -1,221 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.json; - -import com.azure.json.implementation.jackson.core.JsonGenerator; -import com.azure.json.implementation.jackson.core.ObjectCodec; -import com.azure.json.implementation.jackson.core.SerializableString; -import com.azure.json.implementation.jackson.core.StreamWriteCapability; -import com.azure.json.implementation.jackson.core.Version; -import com.azure.json.implementation.jackson.core.base.GeneratorBase; -import com.azure.json.implementation.jackson.core.io.CharTypes; -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; -import com.azure.json.implementation.jackson.core.io.IOContext; -import com.azure.json.implementation.jackson.core.io.SerializedString; -import com.azure.json.implementation.jackson.core.util.JacksonFeatureSet; -import com.azure.json.implementation.jackson.core.util.VersionUtil; - -import java.io.IOException; - -/** - * Intermediate base class shared by JSON-backed generators - * like {@link UTF8JsonGenerator} and {@link WriterBasedJsonGenerator}. - * - * @since 2.1 - */ -public abstract class JsonGeneratorImpl extends GeneratorBase { - /* - * /********************************************************** - * /* Constants - * /********************************************************** - */ - - /** - * This is the default set of escape codes, over 7-bit ASCII range - * (first 128 character codes), used for single-byte UTF-8 characters. - */ - protected final static int[] sOutputEscapes = CharTypes.get7BitOutputEscapes(); - - /** - * Default capabilities for JSON generator implementations which do not - * different from "general textual" defaults - * - * @since 2.12 - */ - protected final static JacksonFeatureSet JSON_WRITE_CAPABILITIES - = DEFAULT_TEXTUAL_WRITE_CAPABILITIES; - - /* - * /********************************************************** - * /* Configuration, basic I/O - * /********************************************************** - */ - - protected final IOContext _ioContext; - - /* - * /********************************************************** - * /* Configuration, output escaping - * /********************************************************** - */ - - /** - * Currently active set of output escape code definitions (whether - * and how to escape or not) for 7-bit ASCII range (first 128 - * character codes). Defined separately to make potentially - * customizable - */ - protected int[] _outputEscapes = sOutputEscapes; - - /** - * Value between 128 (0x80) and 65535 (0xFFFF) that indicates highest - * Unicode code point that will not need escaping; or 0 to indicate - * that all characters can be represented without escaping. - * Typically used to force escaping of some portion of character set; - * for example to always escape non-ASCII characters (if value was 127). - *

- * 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 = new SerializedString(" "); - - /** - * Flag that is set if quoting is not to be added around - * JSON Object property names. - * - * @since 2.7 - */ - protected boolean _cfgUnqNames; - - /* - * /********************************************************** - * /* Life-cycle - * /********************************************************** - */ - - @SuppressWarnings("deprecation") - 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); - } - - /* - * /********************************************************** - * /* Versioned - * /********************************************************** - */ - - @Override - public Version version() { - return VersionUtil.versionFor(getClass()); - } - - /* - * /********************************************************** - * /* Overridden configuration methods - * /********************************************************** - */ - - @SuppressWarnings("deprecation") - @Override - public JsonGenerator enable(Feature f) { - super.enable(f); - if (f == Feature.QUOTE_FIELD_NAMES) { - _cfgUnqNames = false; - } - return this; - } - - @SuppressWarnings("deprecation") - @Override - public JsonGenerator disable(Feature f) { - super.disable(f); - if (f == Feature.QUOTE_FIELD_NAMES) { - _cfgUnqNames = true; - } - return this; - } - - @SuppressWarnings("deprecation") - @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 = Math.max(charCode, 0); - 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; - } - - @Override - public JacksonFeatureSet getWriteCapabilities() { - return JSON_WRITE_CAPABILITIES; - } - - /* - * /********************************************************** - * /* Shared helper methods - * /********************************************************** - */ - - protected void _reportCantWriteValueExpectName(String typeMsg) throws IOException { - _reportError( - String.format("Can not %s, expecting field name (context: %s)", typeMsg, _writeContext.typeDesc())); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonParserBase.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonParserBase.java deleted file mode 100644 index dd7bb8a0cbba..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonParserBase.java +++ /dev/null @@ -1,115 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.json; - -import com.azure.json.implementation.jackson.core.JsonLocation; -import com.azure.json.implementation.jackson.core.ObjectCodec; -import com.azure.json.implementation.jackson.core.StreamReadCapability; -import com.azure.json.implementation.jackson.core.base.ParserBase; -import com.azure.json.implementation.jackson.core.io.CharTypes; -import com.azure.json.implementation.jackson.core.io.IOContext; -import com.azure.json.implementation.jackson.core.util.JacksonFeatureSet; - -/** - * Another intermediate base class, only used by actual JSON-backed parser - * implementations. - * - * @since 2.17 - */ -public abstract class JsonParserBase extends ParserBase { - @SuppressWarnings("deprecation") - protected final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask(); - @SuppressWarnings("deprecation") - protected final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask(); - @SuppressWarnings("deprecation") - protected final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask(); - @SuppressWarnings("deprecation") - protected final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask(); - protected final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask(); - protected final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask(); - protected final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask(); - protected final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask(); - - // 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[] INPUT_CODES_LATIN1 = CharTypes.getInputCodeLatin1(); - - // This is the main input-code lookup table, fetched eagerly - protected final static int[] INPUT_CODES_UTF8 = CharTypes.getInputCodeUtf8(); - - /* - /********************************************************** - /* Configuration - /********************************************************** - */ - - /** - * Codec used for data binding when (if) requested; typically full - * ObjectMapper, but that abstract is not part of core - * package. - */ - protected ObjectCodec _objectCodec; - - /* - /********************************************************************** - /* Life-cycle - /********************************************************************** - */ - - protected JsonParserBase(IOContext ioCtxt, int features, ObjectCodec codec) { - super(ioCtxt, features); - _objectCodec = codec; - } - - @Override - public ObjectCodec getCodec() { - return _objectCodec; - } - - @Override - public void setCodec(ObjectCodec c) { - _objectCodec = c; - } - - /* - /********************************************************************** - /* Capability introspection - /********************************************************************** - */ - - @Override - public final JacksonFeatureSet getReadCapabilities() { - return JSON_READ_CAPABILITIES; - } - - /* - /********************************************************************** - /* Overrides - /********************************************************************** - */ - - /* - /********************************************************************** - /* Location handling - /********************************************************************** - */ - - // First: override some methods as abstract to force definition by subclasses - - @Override - public abstract JsonLocation currentLocation(); - - @Override - public abstract JsonLocation currentTokenLocation(); - - @Deprecated // since 2.17 - @Override - public final JsonLocation getCurrentLocation() { - return currentLocation(); - } - - @Deprecated // since 2.17 - @Override - public final JsonLocation getTokenLocation() { - return currentTokenLocation(); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadContext.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadContext.java index d626bd2d3330..25d70ae3f570 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadContext.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadContext.java @@ -1,7 +1,9 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.json; -import com.azure.json.implementation.jackson.core.*; +import com.azure.json.implementation.jackson.core.JsonLocation; +import com.azure.json.implementation.jackson.core.JsonStreamContext; +import com.azure.json.implementation.jackson.core.JsonToken; import com.azure.json.implementation.jackson.core.io.ContentReference; /** @@ -17,10 +19,6 @@ public final class JsonReadContext extends JsonStreamContext { */ private final JsonReadContext _parent; - // // // Optional duplicate detection - - private DupDetector _dups; - /* * /********************************************************** * /* Simple instance reuse slots; speeds up things a bit (10-15%) @@ -39,11 +37,6 @@ public final class JsonReadContext extends JsonStreamContext { private String _currentName; - /** - * @since 2.5 - */ - private Object _currentValue; - private int _lineNr; private int _columnNr; @@ -53,10 +46,9 @@ public final class JsonReadContext extends JsonStreamContext { * /********************************************************** */ - public JsonReadContext(JsonReadContext parent, DupDetector dups, int type, int lineNr, int colNr) { + public JsonReadContext(JsonReadContext parent, int type, int lineNr, int colNr) { super(); _parent = parent; - _dups = dups; _type = type; _lineNr = lineNr; _columnNr = colNr; @@ -82,31 +74,6 @@ public void reset(int type, int lineNr, int colNr) { _lineNr = lineNr; _columnNr = colNr; _currentName = null; - _currentValue = null; - if (_dups != null) { - _dups.reset(); - } - } - - /* - * public void trackDups(JsonParser p) { - * _dups = DupDetector.rootDetector(p); - * } - */ - - public JsonReadContext withDupDetector(DupDetector dups) { - _dups = dups; - return this; - } - - @Override - public Object getCurrentValue() { - return _currentValue; - } - - @Override - public void setCurrentValue(Object v) { - _currentValue = v; } /* @@ -115,15 +82,14 @@ public void setCurrentValue(Object v) { * /********************************************************** */ - public static JsonReadContext createRootContext(DupDetector dups) { - return new JsonReadContext(null, dups, TYPE_ROOT, 1, 0); + public static JsonReadContext createRootContext() { + return new JsonReadContext(null, 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); + _child = ctxt = new JsonReadContext(this, TYPE_ARRAY, lineNr, colNr); } else { ctxt.reset(TYPE_ARRAY, lineNr, colNr); } @@ -133,8 +99,7 @@ public JsonReadContext createChildArrayContext(int lineNr, int colNr) { 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); + _child = ctxt = new JsonReadContext(this, TYPE_OBJECT, lineNr, colNr); return ctxt; } ctxt.reset(TYPE_OBJECT, lineNr, colNr); @@ -164,12 +129,6 @@ public JsonLocation startLocation(ContentReference srcRef) { return new JsonLocation(srcRef, totalChars, _lineNr, _columnNr); } - @Override - @Deprecated // since 2.13 - public JsonLocation getStartLocation(Object rawSrc) { - return startLocation(ContentReference.rawReference(rawSrc)); - } - /* * /********************************************************** * /* Extended API @@ -178,7 +137,6 @@ public JsonLocation getStartLocation(Object rawSrc) { /** * 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 @@ -189,15 +147,10 @@ public JsonLocation getStartLocation(Object rawSrc) { * @since 2.7 */ public JsonReadContext clearAndGetParent() { - _currentValue = null; // could also clear the current name, but seems cheap enough to leave? return _parent; } - public DupDetector getDupDetector() { - return _dups; - } - /* * /********************************************************** * /* State changes @@ -214,18 +167,7 @@ public boolean expectComma() { return (_type != TYPE_ROOT && ix > 0); } - public void setCurrentName(String name) throws JsonProcessingException { + public void setCurrentName(String name) { _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 JsonParser) ? ((JsonParser) src) : null), - "Duplicate field '" + name + "'"); - } } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadFeature.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadFeature.java index bb5ddf9875be..ed34f4396dbb 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadFeature.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonReadFeature.java @@ -9,7 +9,7 @@ * * @since 2.10 */ -public enum JsonReadFeature implements FormatFeature { +public enum JsonReadFeature { // // // Support for non-standard data format constructs: comments /** @@ -24,102 +24,10 @@ public enum JsonReadFeature implements FormatFeature { * disabled by default for parsers and must be * explicitly enabled. */ - ALLOW_JAVA_COMMENTS(false, JsonParser.Feature.ALLOW_COMMENTS), - - /** - * 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, JsonParser.Feature.ALLOW_YAML_COMMENTS), - - // // // Support for non-standard data format constructs: quoting/escaping - - /** - * 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. - *

- * 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, JsonParser.Feature.ALLOW_SINGLE_QUOTES), - - /** - * 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, JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES), - - /** - * Feature that determines whether parser will allow - * JSON Strings to contain unescaped 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. - */ - @SuppressWarnings("deprecation") - ALLOW_UNESCAPED_CONTROL_CHARS(false, JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS), - - /** - * 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. - */ - @SuppressWarnings("deprecation") - ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false, JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER), + ALLOW_JAVA_COMMENTS(JsonParser.Feature.ALLOW_COMMENTS), // // // Support for non-standard data format constructs: number representations - /** - * 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. - */ - @SuppressWarnings("deprecation") - ALLOW_LEADING_ZEROS_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS), - - /** - * Feature that determines whether parser will allow - * JSON decimal numbers to start with a decimal point - * (like: .123). If enabled, no exception is thrown, and the number - * is parsed as though a leading 0 had been present. - *

- * Since JSON specification does not allow leading decimal, - * this is a non-standard feature, and as such disabled by default. - * - * @since 2.11 - */ - @SuppressWarnings("deprecation") - ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS), - /** * Feature that allows parser to recognize set of * "Not-a-Number" (NaN) tokens as legal floating number @@ -139,51 +47,7 @@ public enum JsonReadFeature implements FormatFeature { * this is a non-standard feature, and as such disabled by default. */ @SuppressWarnings("deprecation") - ALLOW_NON_NUMERIC_NUMBERS(false, JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS), - - // // // Support for non-standard data format constructs: array/value separators - - /** - * Feature allows the support for "missing" values in a JSON array: missing - * value meaning sequence of two commas, without value in-between but only - * optional white space. - * Enabling this feature will expose "missing" values as {@link JsonToken#VALUE_NULL} - * tokens, which typically become Java nulls in arrays and {@link java.util.Collection} - * in data-binding. - *

- * For example, enabling this feature will represent a JSON array ["value1",,"value3",] - * as ["value1", null, "value3", null] - *

- * Since the JSON specification does not allow missing values this is a non-compliant JSON - * feature and is disabled by default. - */ - @SuppressWarnings("deprecation") - ALLOW_MISSING_VALUES(false, JsonParser.Feature.ALLOW_MISSING_VALUES), - - /** - * Feature that determines whether {@link JsonParser} will allow for a single trailing - * comma following the final value (in an Array) or member (in an Object). These commas - * will simply be ignored. - *

- * For example, when this feature is enabled, [true,true,] is equivalent to - * [true, true] and {"a": true,} is equivalent to - * {"a": true}. - *

- * When combined with ALLOW_MISSING_VALUES, this feature takes priority, and - * the final trailing comma in an array declaration does not imply a missing - * (null) value. For example, when both ALLOW_MISSING_VALUES - * and ALLOW_TRAILING_COMMA are enabled, [true,true,] is - * equivalent to [true, true], and [true,true,,] is equivalent to - * [true, true, null]. - *

- * Since the JSON specification does not permit trailing commas, this is a non-standard - * feature, and as such disabled by default. - */ - @SuppressWarnings("deprecation") - ALLOW_TRAILING_COMMA(false, JsonParser.Feature.ALLOW_TRAILING_COMMA),; - - final private boolean _defaultState; - final private int _mask; + ALLOW_NON_NUMERIC_NUMBERS(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS); /** * For backwards compatibility we may need to map to one of existing {@link JsonParser.Feature}s; @@ -191,27 +55,10 @@ public enum JsonReadFeature implements FormatFeature { */ final private JsonParser.Feature _mappedFeature; - JsonReadFeature(boolean defaultState, JsonParser.Feature mapTo) { - _defaultState = defaultState; - _mask = (1 << ordinal()); + JsonReadFeature(JsonParser.Feature mapTo) { _mappedFeature = mapTo; } - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public int getMask() { - return _mask; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & _mask) != 0; - } - public JsonParser.Feature mappedFeature() { return _mappedFeature; } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteContext.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteContext.java index 3c5392493c73..51fc415e51bd 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteContext.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteContext.java @@ -1,7 +1,8 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.json; -import com.azure.json.implementation.jackson.core.*; +import com.azure.json.implementation.jackson.core.JsonStreamContext; +import com.azure.json.implementation.jackson.core.JsonToken; /** * Extension of {@link JsonStreamContext}, which implements @@ -23,10 +24,6 @@ public class JsonWriteContext extends JsonStreamContext { */ protected final JsonWriteContext _parent; - // // // Optional duplicate detection - - protected DupDetector _dups; - /* * /********************************************************** * /* Simple instance reuse slots; speed up things a bit (10-15%) @@ -65,24 +62,13 @@ public class JsonWriteContext extends JsonStreamContext { * /********************************************************** */ - protected JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups) { + protected JsonWriteContext(int type, JsonWriteContext parent) { super(); _type = type; _parent = parent; - _dups = dups; _index = -1; } - /* @since 2.10 */ - protected JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups, Object currValue) { - super(); - _type = type; - _parent = parent; - _dups = dups; - _index = -1; - _currentValue = currValue; - } - /** * Internal method to allow instance reuse: DO NOT USE unless you absolutely * know what you are doing. @@ -102,9 +88,6 @@ public JsonWriteContext reset(int type) { _currentName = null; _gotName = false; _currentValue = null; - if (_dups != null) { - _dups.reset(); - } return this; } @@ -130,85 +113,37 @@ public JsonWriteContext reset(int type, Object currValue) { _currentName = null; _gotName = false; _currentValue = currValue; - 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 - * - * @return Context instance created - */ - @Deprecated public static JsonWriteContext createRootContext() { - return createRootContext(null); - } - - public static JsonWriteContext createRootContext(DupDetector dd) { - return new JsonWriteContext(TYPE_ROOT, null, dd); + return new JsonWriteContext(TYPE_ROOT, null); } public JsonWriteContext createChildArrayContext() { JsonWriteContext ctxt = _child; if (ctxt == null) { - _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this, (_dups == null) ? null : _dups.child()); + _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this); return ctxt; } return ctxt.reset(TYPE_ARRAY); } - /* @since 2.10 */ - public JsonWriteContext createChildArrayContext(Object currValue) { - JsonWriteContext ctxt = _child; - if (ctxt == null) { - _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this, (_dups == null) ? null : _dups.child(), currValue); - return ctxt; - } - return ctxt.reset(TYPE_ARRAY, currValue); - } - public JsonWriteContext createChildObjectContext() { JsonWriteContext ctxt = _child; if (ctxt == null) { - _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this, (_dups == null) ? null : _dups.child()); + _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this); return ctxt; } return ctxt.reset(TYPE_OBJECT); } - /* @since 2.10 */ - public JsonWriteContext createChildObjectContext(Object currValue) { - JsonWriteContext ctxt = _child; - if (ctxt == null) { - _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this, (_dups == null) ? null : _dups.child(), currValue); - return ctxt; - } - return ctxt.reset(TYPE_OBJECT, currValue); - } - @Override public final JsonWriteContext getParent() { return _parent; @@ -221,7 +156,6 @@ public final String getCurrentName() { /** * 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 @@ -237,10 +171,6 @@ public JsonWriteContext clearAndGetParent() { return _parent; } - public DupDetector getDupDetector() { - return _dups; - } - /** * Method that writer is to call before it writes a name of Object property. * @@ -248,28 +178,16 @@ public DupDetector getDupDetector() { * * @return Index of the field entry (0-based) * - * @throws JsonProcessingException if duplicate check restriction is violated */ - public int writeFieldName(String name) throws JsonProcessingException { + public int writeFieldName(String name) { if ((_type != TYPE_OBJECT) || _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 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) { diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteFeature.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteFeature.java index 67cc21bee333..4150680e19d9 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteFeature.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/JsonWriteFeature.java @@ -8,23 +8,11 @@ * * @since 2.10 */ -public enum JsonWriteFeature implements FormatFeature { +public enum JsonWriteFeature { // // // Support for non-standard data format constructs: comments // // Quoting/ecsaping-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). - */ - @SuppressWarnings("deprecation") - QUOTE_FIELD_NAMES(true, JsonGenerator.Feature.QUOTE_FIELD_NAMES), - /** * Feature that determines whether "NaN" ("not a number", that is, not * real number) float/double values are output as JSON strings. @@ -38,65 +26,7 @@ public enum JsonWriteFeature implements FormatFeature { * Feature is enabled by default. */ @SuppressWarnings("deprecation") - WRITE_NAN_AS_STRINGS(true, JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS), - - /** - * Feature that forces all regular number values to be written as JSON Strings, - * instead of as JSON Numbers. - * Default state is 'false', meaning that Java numbers are to - * be serialized using basic numeric representation but - * if enabled all such numeric values are instead written out as - * JSON Strings instead. - *

- * 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. - */ - @SuppressWarnings("deprecation") - WRITE_NUMBERS_AS_STRINGS(false, JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS), - - /** - * 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). - *

- * Feature is disabled by default. - */ - @SuppressWarnings("deprecation") - ESCAPE_NON_ASCII(false, JsonGenerator.Feature.ESCAPE_NON_ASCII), - - // 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. - */ - // ESCAPE_UTF8_SURROGATES(false, JsonGenerator.Feature.ESCAPE_UTF8_SURROGATES), - - ; - - final private boolean _defaultState; - final private int _mask; + WRITE_NAN_AS_STRINGS(JsonGenerator.Feature.QUOTE_NON_NUMERIC_NUMBERS); /** * For backwards compatibility we may need to map to one of existing {@link JsonGenerator.Feature}s; @@ -104,27 +34,10 @@ public enum JsonWriteFeature implements FormatFeature { */ final private JsonGenerator.Feature _mappedFeature; - JsonWriteFeature(boolean defaultState, JsonGenerator.Feature mapTo) { - _defaultState = defaultState; - _mask = (1 << ordinal()); + JsonWriteFeature(JsonGenerator.Feature mapTo) { _mappedFeature = mapTo; } - @Override - public boolean enabledByDefault() { - return _defaultState; - } - - @Override - public int getMask() { - return _mask; - } - - @Override - public boolean enabledIn(int flags) { - return (flags & _mask) != 0; - } - public JsonGenerator.Feature mappedFeature() { return _mappedFeature; } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/PackageVersion.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/PackageVersion.java deleted file mode 100644 index c8c02c7de068..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/PackageVersion.java +++ /dev/null @@ -1,21 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.json; - -import com.azure.json.implementation.jackson.core.Version; -import com.azure.json.implementation.jackson.core.Versioned; -import com.azure.json.implementation.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("2.13.2", "com.azure.json.implementation.jackson.core", "jackson-core"); - - @Override - public Version version() { - return VERSION; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/PackageVersion.java.in b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/PackageVersion.java.in deleted file mode 100644 index 3c8fbcf7264a..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/PackageVersion.java.in +++ /dev/null @@ -1,21 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -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; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ReaderBasedJsonParser.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ReaderBasedJsonParser.java index 045c797f9b47..137f14406927 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ReaderBasedJsonParser.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/ReaderBasedJsonParser.java @@ -1,16 +1,24 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.json; -import java.io.*; - -import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.base.ParserBase; +import com.azure.json.implementation.jackson.core.Base64Variant; +import com.azure.json.implementation.jackson.core.Base64Variants; +import com.azure.json.implementation.jackson.core.JsonParseException; +import com.azure.json.implementation.jackson.core.JsonParser; +import com.azure.json.implementation.jackson.core.JsonToken; import com.azure.json.implementation.jackson.core.io.CharTypes; import com.azure.json.implementation.jackson.core.io.IOContext; import com.azure.json.implementation.jackson.core.sym.CharsToNameCanonicalizer; -import com.azure.json.implementation.jackson.core.util.*; +import com.azure.json.implementation.jackson.core.util.ByteArrayBuilder; +import com.azure.json.implementation.jackson.core.util.TextBuffer; + +import java.io.IOException; +import java.io.Reader; -import static com.azure.json.implementation.jackson.core.JsonTokenId.*; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_FIELD_NAME; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NUMBER_FLOAT; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NUMBER_INT; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_STRING; /** * This is a concrete implementation of {@link JsonParser}, which is @@ -18,23 +26,12 @@ * conversion tasks. */ @SuppressWarnings("fallthrough") -public class ReaderBasedJsonParser extends ParserBase { - @SuppressWarnings("deprecation") - private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask(); - - @SuppressWarnings("deprecation") - private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask(); +public class ReaderBasedJsonParser extends JsonParser { @SuppressWarnings("deprecation") private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask(); - @SuppressWarnings("deprecation") - private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask(); - private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask(); - private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask(); - private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask(); - private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask(); // Latin1 encoding is not supported, but we do use 8-bit subset for // pre-processing task, to simplify first pass, keep it fast. @@ -74,8 +71,6 @@ public class ReaderBasedJsonParser extends ParserBase { * /********************************************************** */ - protected ObjectCodec _objectCodec; - final protected CharsToNameCanonicalizer _symbols; final protected int _hashSeed; @@ -127,7 +122,6 @@ public class ReaderBasedJsonParser extends ParserBase { * @param ctxt I/O context to use * @param features Standard stream read features enabled * @param r Reader used for reading actual content, if any; {@code null} if none - * @param codec {@code ObjectCodec} to delegate object deserialization to * @param st Name canonicalizer to use * @param inputBuffer Input buffer to read initial content from (before Reader) * @param start Pointer in {@code inputBuffer} that has the first content character to decode @@ -137,11 +131,10 @@ public class ReaderBasedJsonParser extends ParserBase { * * @since 2.4 */ - public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r, ObjectCodec codec, CharsToNameCanonicalizer st, + public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r, CharsToNameCanonicalizer st, char[] inputBuffer, int start, int end, boolean bufferRecyclable) { super(ctxt, features); _reader = r; - _objectCodec = codec; _inputBuffer = inputBuffer; _inputPtr = start; _inputEnd = end; @@ -160,17 +153,14 @@ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r, ObjectCodec * @param ctxt I/O context to use * @param features Standard stream read features enabled * @param r Reader used for reading actual content, if any; {@code null} if none - * @param codec {@code ObjectCodec} to delegate object deserialization to * @param st Name canonicalizer to use */ - public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r, ObjectCodec codec, - CharsToNameCanonicalizer st) { + public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r, CharsToNameCanonicalizer st) { super(ctxt, features); _reader = r; _inputBuffer = ctxt.allocTokenBuffer(); _inputPtr = 0; _inputEnd = 0; - _objectCodec = codec; _symbols = st; _hashSeed = st.hashSeed(); _bufferRecyclable = true; @@ -182,26 +172,6 @@ public ReaderBasedJsonParser(IOContext ctxt, int features, Reader r, ObjectCodec * /********************************************************** */ - @Override - public ObjectCodec getCodec() { - return _objectCodec; - } - - @Override - public void setCodec(ObjectCodec c) { - _objectCodec = c; - } - - @Override // @since 2.12 - public JacksonFeatureSet getReadCapabilities() { - return JSON_READ_CAPABILITIES; - } - - @Override - public Object getInputSource() { - return _reader; - } - @Deprecated // since 2.8 protected char getNextChar(String eofMsg) throws IOException { return getNextChar(eofMsg, null); @@ -227,7 +197,7 @@ protected void _closeInput() throws IOException { * means that buffer recycling won't work correctly. */ if (_reader != null) { - if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) { + if (_ioContext.isResourceManaged()) { _reader.close(); } _reader = null; @@ -319,32 +289,6 @@ public final String getText() throws IOException { return _getText2(_currToken); } - @Override // since 2.8 - public int getText(Writer writer) throws IOException { - JsonToken t = _currToken; - if (t == JsonToken.VALUE_STRING) { - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - return _textBuffer.contentsToWriter(writer); - } - if (t == JsonToken.FIELD_NAME) { - String n = _parsingContext.getCurrentName(); - writer.write(n); - return n.length(); - } - if (t != null) { - if (t.isNumeric()) { - return _textBuffer.contentsToWriter(writer); - } - char[] ch = t.asCharArray(); - writer.write(ch); - return ch.length; - } - return 0; - } - // // // Let's override default impls for improved performance // @since 2.1 @@ -358,7 +302,7 @@ public final String getValueAsString() throws IOException { return _textBuffer.contentsAsString(); } if (_currToken == JsonToken.FIELD_NAME) { - return getCurrentName(); + return currentName(); } return super.getValueAsString(null); } @@ -374,7 +318,7 @@ public final String getValueAsString(String defValue) throws IOException { return _textBuffer.contentsAsString(); } if (_currToken == JsonToken.FIELD_NAME) { - return getCurrentName(); + return currentName(); } return super.getValueAsString(defValue); } @@ -399,90 +343,8 @@ protected final String _getText2(JsonToken t) { } @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 { + public byte[] getBinaryValue() throws IOException { + Base64Variant b64variant = Base64Variants.getDefaultVariant(); if ((_currToken == JsonToken.VALUE_EMBEDDED_OBJECT) && (_binaryValue != null)) { return _binaryValue; } @@ -507,167 +369,13 @@ public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { if (_binaryValue == null) { @SuppressWarnings("resource") ByteArrayBuilder builder = _getByteArrayBuilder(); - _decodeBase64(getText(), builder, b64variant); + _decodeBase64(getText(), builder); _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 == '"') { - decodedData >>= 4; - buffer[outputPtr++] = (byte) decodedData; - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } - 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)) { - if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) { - 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 == '"') { - decodedData >>= 2; - buffer[outputPtr++] = (byte) (decodedData >> 8); - buffer[outputPtr++] = (byte) decodedData; - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } - 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 @@ -713,14 +421,6 @@ public final JsonToken nextToken() throws IOException { // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { i = _skipComma(i); - - // Was that a trailing comma? - if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) { - if ((i == INT_RBRACKET) || (i == INT_RCURLY)) { - _closeScope(i); - return _currToken; - } - } } /* @@ -836,20 +536,6 @@ private JsonToken _nextAfterName() { return (_currToken = t); } - @Override - public void finishToken() throws IOException { - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - } - - /* - * /********************************************************** - * /* Public API, nextXxx() overrides - * /********************************************************** - */ - /* * /********************************************************** * /* Internal methods, number parsing @@ -858,11 +544,7 @@ public void finishToken() throws IOException { // @since 2.11, [core#611] protected final JsonToken _parseFloatThatStartsWithPeriod() throws IOException { - // [core#611]: allow optionally leading decimal point - if (!isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { - return _handleOddValue('.'); - } - return _parseFloat(INT_PERIOD, _inputPtr - 1, _inputPtr, false, 0); + return _handleOddValue('.'); } /** @@ -1214,23 +896,7 @@ private char _verifyNLZ2() throws IOException { if (ch < '0' || ch > '9') { return '0'; } - if ((_features & FEAT_MASK_LEADING_ZEROS) == 0) { - 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; - } - } - } + reportInvalidNumber(); return ch; } @@ -1318,10 +984,10 @@ protected final String _parseName() throws IOException { } int start = _inputPtr; _inputPtr = ptr; - return _parseName2(start, hash, INT_QUOTE); + return _parseName2(start, hash); } - private String _parseName2(int startPtr, int hash, int endChar) throws IOException { + private String _parseName2(int startPtr, int hash) throws IOException { _textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr)); /* @@ -1347,8 +1013,8 @@ private String _parseName2(int startPtr, int hash, int endChar) throws IOExcepti * For now let's assume it does not. */ c = _decodeEscaped(); - } else if (i <= endChar) { - if (i == endChar) { + } else if (i <= INT_QUOTE) { + if (i == INT_QUOTE) { break; } if (i < INT_SPACE) { @@ -1390,85 +1056,8 @@ private String _parseName2(int startPtr, int hash, int endChar) throws IOExcepti * {@link JsonParseException} for decoding problems (invalid name) */ protected String _handleOddName(int i) throws IOException { - // [JACKSON-173]: allow single quotes - if (i == '\'' && (_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) { - return _parseAposName(); - } - // [JACKSON-69]: allow unquoted names if feature enabled: - if ((_features & FEAT_MASK_ALLOW_UNQUOTED_NAMES) == 0) { - _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, '\''); + _reportUnexpectedChar(i, "was expecting double-quote to start field name"); + return null; } /** @@ -1486,15 +1075,6 @@ protected JsonToken _handleOddValue(int i) throws IOException { // Most likely an error, unless we are to allow single-quote-strings switch (i) { case '\'': - /* - * Allow single quotes? Unlike with regular Strings, we'll eagerly parse - * contents; this so that there'sno 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 ((_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) { - return _handleApos(); - } break; case ']': @@ -1508,13 +1088,6 @@ protected JsonToken _handleOddValue(int i) throws IOException { } // fall through case ',': - // 11-May-2020, tatu: [core#616] No commas in root level - if (!_parsingContext.inRoot()) { - if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) { - --_inputPtr; - return JsonToken.VALUE_NULL; - } - } break; case 'N': @@ -1544,95 +1117,13 @@ protected JsonToken _handleOddValue(int i) throws IOException { } // [core#77] Try to decode most likely token if (Character.isJavaIdentifierStart(i)) { - _reportInvalidToken("" + ((char) i), _validJsonTokenList()); + _reportInvalidToken("" + ((char) i), _validJsonValueList()); } // but if it doesn't look like a token: _reportUnexpectedChar(i, "expected a valid value " + _validJsonValueList()); 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", JsonToken.VALUE_STRING); - } - } - char c = _inputBuffer[_inputPtr++]; - int i = 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 = 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 { /* @@ -1834,11 +1325,6 @@ private int _skipColon2(boolean gotColon) throws IOException { _skipComment(); continue; } - if (i == INT_HASH) { - if (_skipYAMLComment()) { - continue; - } - } if (gotColon) { return i; } @@ -1899,11 +1385,6 @@ private int _skipAfterComma2() throws IOException { _skipComment(); continue; } - if (i == INT_HASH) { - if (_skipYAMLComment()) { - continue; - } - } return i; } if (i < INT_SPACE) { @@ -1983,11 +1464,6 @@ private int _skipWSOrEnd2() throws IOException { _skipComment(); continue; } - if (i == INT_HASH) { - if (_skipYAMLComment()) { - continue; - } - } return i; } else if (i != INT_SPACE) { if (i == INT_LF) { @@ -2051,14 +1527,6 @@ private void _skipCComment() throws IOException { _reportInvalidEOF(" in a comment", null); } - private boolean _skipYAMLComment() throws IOException { - if ((_features & FEAT_MASK_ALLOW_YAML_COMMENTS) == 0) { - return false; - } - _skipLine(); - return true; - } - private void _skipLine() throws IOException { // Ok: need to find EOF or linefeed while ((_inputPtr < _inputEnd) || _loadMore()) { @@ -2299,10 +1767,8 @@ protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException { if (ch == '"') { decodedData >>= 4; builder.append(decodedData); - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } + --_inputPtr; // to keep parser state bit more consistent + _handleBase64MissingPadding(); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 2); @@ -2313,10 +1779,9 @@ protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException { _loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++]; - if (!b64variant.usesPaddingChar(ch)) { + if (ch != '=') { if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidBase64Char(b64variant, ch, 3, - "expected padding character '" + b64variant.getPaddingChar() + "'"); + throw reportInvalidBase64Char(ch, 3, "expected padding character '='"); } } // Got 12 bits, only need 8, need to shift @@ -2340,10 +1805,8 @@ protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException { if (ch == '"') { decodedData >>= 2; builder.appendTwoBytes(decodedData); - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } + --_inputPtr; // to keep parser state bit more consistent + _handleBase64MissingPadding(); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 3); @@ -2372,15 +1835,6 @@ protected byte[] _decodeBase64(Base64Variant b64variant) throws IOException { * /********************************************************** */ - @Override - public JsonLocation getTokenLocation() { - if (_currToken == JsonToken.FIELD_NAME) { - long total = _currInputProcessed + (_nameStartOffset - 1); - return new JsonLocation(_contentReference(), -1L, total, _nameStartRow, _nameStartCol); - } - return new JsonLocation(_contentReference(), -1L, _tokenInputTotal - 1, _tokenInputRow, _tokenInputCol); - } - // @since 2.7 private void _updateLocation() { int ptr = _inputPtr; @@ -2404,7 +1858,7 @@ private void _updateNameLocation() { */ protected void _reportInvalidToken(String matchedPart) throws IOException { - _reportInvalidToken(matchedPart, _validJsonTokenList()); + _reportInvalidToken(matchedPart, _validJsonValueList()); } protected void _reportInvalidToken(String matchedPart, String msg) throws IOException { @@ -2426,7 +1880,7 @@ protected void _reportInvalidToken(String matchedPart, String msg) throws IOExce break; } } - _reportError("Unrecognized token '%s': was expecting %s", sb, msg); + _reportError(sb, msg); } /* diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8JsonGenerator.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8JsonGenerator.java index 855ccb11c20a..9a3051e6d514 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8JsonGenerator.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8JsonGenerator.java @@ -2,23 +2,16 @@ package com.azure.json.implementation.jackson.core.json; import com.azure.json.implementation.jackson.core.Base64Variant; -import com.azure.json.implementation.jackson.core.JsonFactory; +import com.azure.json.implementation.jackson.core.JsonGenerator; import com.azure.json.implementation.jackson.core.JsonStreamContext; -import com.azure.json.implementation.jackson.core.ObjectCodec; -import com.azure.json.implementation.jackson.core.SerializableString; import com.azure.json.implementation.jackson.core.io.CharTypes; -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; import com.azure.json.implementation.jackson.core.io.IOContext; import com.azure.json.implementation.jackson.core.io.NumberOutput; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.io.Reader; -import java.math.BigDecimal; -import java.math.BigInteger; -public class UTF8JsonGenerator extends JsonGeneratorImpl { +public class UTF8JsonGenerator extends JsonGenerator { private final static byte BYTE_u = (byte) 'u'; private final static byte BYTE_0 = (byte) '0'; @@ -32,9 +25,6 @@ public class UTF8JsonGenerator extends JsonGeneratorImpl { private final static byte BYTE_COMMA = (byte) ','; private final static byte BYTE_COLON = (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' }; @@ -58,7 +48,7 @@ public class UTF8JsonGenerator extends JsonGeneratorImpl { * * @since 2.8 */ - protected byte _quoteChar; + protected final byte _quoteChar; /* * /********************************************************** @@ -115,13 +105,10 @@ public class UTF8JsonGenerator extends JsonGeneratorImpl { // @since 2.10 @SuppressWarnings("deprecation") - public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out, char quoteChar) { - super(ctxt, features, codec); + public UTF8JsonGenerator(IOContext ctxt, int features, OutputStream out) { + super(ctxt, features); _outputStream = out; - _quoteChar = (byte) quoteChar; - if (quoteChar != '"') { // since 2.10 - _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar); - } + _quoteChar = (byte) '"'; _bufferRecyclable = true; _outputBuffer = ctxt.allocWriteEncodingBuffer(); @@ -135,60 +122,6 @@ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, Output _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); - } - } - - // @since 2.10 - public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out, char quoteChar, - byte[] outputBuffer, int outputOffset, boolean bufferRecyclable) { - - super(ctxt, features, codec); - _outputStream = out; - _quoteChar = (byte) quoteChar; - if (quoteChar != '"') { // since 2.10 - _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar); - } - - _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; - } - - @Deprecated // since 2.10 - public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out) { - this(ctxt, features, codec, out, JsonFactory.DEFAULT_QUOTE_CHAR); - } - - @Deprecated // since 2.10 - public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, OutputStream out, byte[] outputBuffer, - int outputOffset, boolean bufferRecyclable) { - this(ctxt, features, codec, out, JsonFactory.DEFAULT_QUOTE_CHAR, outputBuffer, outputOffset, bufferRecyclable); - } - - /* - * /********************************************************** - * /* 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; } /* @@ -209,18 +142,10 @@ public void writeFieldName(String name) throws IOException { } _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); + _writeStringSegments(name); return; } if (_outputTail >= _outputEnd) { @@ -243,47 +168,6 @@ public void writeFieldName(String name) throws IOException { _outputBuffer[_outputTail++] = _quoteChar; } - @Override - public void writeFieldName(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) { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = BYTE_COMMA; - } - if (_cfgUnqNames) { - _writeUnq(name); - return; - } - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - 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++] = _quoteChar; - } - - private 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 @@ -300,26 +184,6 @@ public final void writeStartArray() throws IOException { _outputBuffer[_outputTail++] = BYTE_LBRACKET; } - @Override // since 2.12 - public final void writeStartArray(Object currentValue) throws IOException { - _verifyValueWrite("start an array"); - _writeContext = _writeContext.createChildArrayContext(currentValue); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = BYTE_LBRACKET; - } - - @Override // since 2.12 - public void writeStartArray(Object currentValue, int size) throws IOException { - _verifyValueWrite("start an array"); - _writeContext = _writeContext.createChildArrayContext(currentValue); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = BYTE_LBRACKET; - } - @Override public final void writeEndArray() throws IOException { if (!_writeContext.inArray()) { @@ -342,16 +206,6 @@ public final void writeStartObject() throws IOException { _outputBuffer[_outputTail++] = BYTE_LCURLY; } - @Override // since 2.8 - public void writeStartObject(Object forValue) throws IOException { - _verifyValueWrite("start an object"); - _writeContext = _writeContext.createChildObjectContext(forValue); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '{'; - } - @Override public final void writeEndObject() throws IOException { if (!_writeContext.inObject()) { @@ -380,7 +234,7 @@ public void writeString(String text) throws IOException { // 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); + _writeStringSegments(text); return; } if ((_outputTail + len) >= _outputEnd) { @@ -394,124 +248,6 @@ public void writeString(String text) throws IOException { _outputBuffer[_outputTail++] = _quoteChar; } - @Override - public void writeString(Reader reader, int len) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (reader == null) { - _reportError("null reader"); - return; // just to block warnings by lgtm.com - } - - int toRead = (len >= 0) ? len : Integer.MAX_VALUE; - final char[] buf = _charBuffer; - - // Add leading quote - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - - // read - while (toRead > 0) { - int toReadNow = Math.min(toRead, buf.length); - int numRead = reader.read(buf, 0, toReadNow); - if (numRead <= 0) { - break; - } - if ((_outputTail + len) >= _outputEnd) { - _flushBuffer(); - } - _writeStringSegments(buf, 0, numRead); - // decrease tracker - toRead -= numRead; - } - - // Add trailing quote - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - - if (toRead > 0 && len >= 0) { - _reportError("Didn't read enough from reader"); - } - } - - @Override - public void writeString(char[] text, int offset, int len) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - // 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++] = _quoteChar; - } - - @Override - public final void writeString(SerializableString text) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - int len = text.appendQuotedUTF8(_outputBuffer, _outputTail); - if (len < 0) { - _writeBytes(text.asQuotedUTF8()); - } else { - _outputTail += len; - } - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - @Override - public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - _writeBytes(text, offset, length); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - @Override - public void writeUTF8String(byte[] text, int offset, int len) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - // One or multiple segments? - if (len <= _outputMaxContiguous) { - _writeUTF8Segment(text, offset, len); - } else { - _writeUTF8Segments(text, offset, len); - } - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - /* * /********************************************************** * /* Output method implementations, unprocessed ("raw") @@ -572,28 +308,6 @@ public void writeRaw(String text, int offset, int len) throws IOException { } } - @Override - public void writeRaw(SerializableString text) throws IOException { - int len = text.appendUnquotedUTF8(_outputBuffer, _outputTail); - if (len < 0) { - _writeBytes(text.asUnquotedUTF8()); - } else { - _outputTail += len; - } - } - - // since 2.5 - @Override - public void writeRawValue(SerializableString text) throws IOException { - _verifyValueWrite(WRITE_RAW); - int len = text.appendUnquotedUTF8(_outputBuffer, _outputTail); - if (len < 0) { - _writeBytes(text.asUnquotedUTF8()); - } else { - _outputTail += len; - } - } - // @TODO: rewrite for speed... @Override public final void writeRaw(char[] cbuf, int offset, int len) throws IOException { @@ -634,22 +348,6 @@ public final void writeRaw(char[] cbuf, int offset, int len) throws IOException } } - @Override - public void writeRaw(char ch) throws IOException { - 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 @@ -739,66 +437,12 @@ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int l _outputBuffer[_outputTail++] = _quoteChar; } - @Override - public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException { - _verifyValueWrite(WRITE_BINARY); - // Starting quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - 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++] = _quoteChar; - 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 void _writeQuotedShort(short s) throws IOException { - if ((_outputTail + 8) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = _quoteChar; - } - @Override public void writeNumber(int i) throws IOException { _verifyValueWrite(WRITE_NUMBER); @@ -806,29 +450,12 @@ public void writeNumber(int i) throws IOException { if ((_outputTail + 11) >= _outputEnd) { _flushBuffer(); } - if (_cfgNumbersAsStrings) { - _writeQuotedInt(i); - return; - } - _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); - } - - private void _writeQuotedInt(int i) throws IOException { - if ((_outputTail + 13) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = _quoteChar; } @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(); @@ -836,32 +463,10 @@ public void writeNumber(long l) throws IOException { _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); } - private void _writeQuotedLong(long l) throws IOException { - if ((_outputTail + 23) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = _quoteChar; - } - - @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()); - } - } - @SuppressWarnings("deprecation") @Override public void writeNumber(double d) throws IOException { - if (_cfgNumbersAsStrings - || (NumberOutput.notFinite(d) && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features))) { + if (NumberOutput.notFinite(d) && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)) { writeString(String.valueOf(d)); return; } @@ -873,8 +478,7 @@ public void writeNumber(double d) throws IOException { @SuppressWarnings("deprecation") @Override public void writeNumber(float f) throws IOException { - if (_cfgNumbersAsStrings - || (NumberOutput.notFinite(f) && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features))) { + if (NumberOutput.notFinite(f) && Feature.QUOTE_NON_NUMERIC_NUMBERS.enabledIn(_features)) { writeString(String.valueOf(f)); return; } @@ -884,74 +488,15 @@ public void writeNumber(float f) throws IOException { } @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) { - _writeQuotedRaw(_asString(value)); - } else { - writeRaw(_asString(value)); + public void writeBoolean(boolean state) throws IOException { + _verifyValueWrite(WRITE_BOOLEAN); + if ((_outputTail + 5) >= _outputEnd) { + _flushBuffer(); } - } - - @Override - public void writeNumber(String encodedValue) throws IOException { - _verifyValueWrite(WRITE_NUMBER); - if (encodedValue == null) { - _writeNull(); - } else if (_cfgNumbersAsStrings) { - _writeQuotedRaw(encodedValue); - } else { - writeRaw(encodedValue); - } - } - - @Override - public void writeNumber(char[] encodedValueBuffer, int offset, int length) throws IOException { - _verifyValueWrite(WRITE_NUMBER); - if (_cfgNumbersAsStrings) { - _writeQuotedRaw(encodedValueBuffer, offset, length); - } else { - writeRaw(encodedValueBuffer, offset, length); - } - } - - private void _writeQuotedRaw(String value) throws IOException { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - writeRaw(value); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - private void _writeQuotedRaw(char[] text, int offset, int length) throws IOException { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - writeRaw(text, offset, length); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - @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; + byte[] keyword = state ? TRUE_BYTES : FALSE_BYTES; + int len = keyword.length; + System.arraycopy(keyword, 0, _outputBuffer, _outputTail, len); + _outputTail += len; } @Override @@ -984,12 +529,7 @@ protected final void _verifyValueWrite(String typeMsg) throws IOException { break; case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator - if (_rootValueSeparator != null) { - byte[] raw = _rootValueSeparator.asUnquotedUTF8(); - if (raw.length > 0) { - _writeBytes(raw); - } - } + _writeSpace(); return; case JsonWriteContext.STATUS_EXPECT_NAME: @@ -1081,31 +621,12 @@ protected void _releaseBuffers() { * /********************************************************** */ - private 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 void _writeBytes(byte[] bytes, int offset, int len) throws IOException { - if ((_outputTail + len) > _outputEnd) { + private void _writeSpace() throws IOException { + if ((_outputTail + 1) > _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; + _outputBuffer[_outputTail] = ' '; + _outputTail += 1; } /* @@ -1121,13 +642,11 @@ private void _writeBytes(byte[] bytes, int offset, int len) throws IOException { * to single-segment writes (instead of maximum slices that * would fit in copy buffer) */ - private void _writeStringSegments(String text, boolean addQuotes) throws IOException { - if (addQuotes) { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; + private void _writeStringSegments(String text) throws IOException { + if (_outputTail >= _outputEnd) { + _flushBuffer(); } + _outputBuffer[_outputTail++] = _quoteChar; int left = text.length(); int offset = 0; @@ -1142,30 +661,10 @@ private void _writeStringSegments(String text, boolean addQuotes) throws IOExcep left -= len; } - if (addQuotes) { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; + if (_outputTail >= _outputEnd) { + _flushBuffer(); } - } - - /** - * 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 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); + _outputBuffer[_outputTail++] = _quoteChar; } private void _writeStringSegments(String text, int offset, int totalLen) throws IOException { @@ -1186,46 +685,6 @@ private void _writeStringSegments(String text, int offset, int totalLen) throws * /********************************************************** */ - /** - * 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 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) { - if (_characterEscapes != null) { - _writeCustomStringSegment2(cbuf, offset, len); - } else if (_maximumNonEscapedChar == 0) { - _writeStringSegment2(cbuf, offset, len); - } else { - _writeStringSegmentASCII2(cbuf, offset, len); - } - - } - } - private 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 @@ -1233,12 +692,11 @@ private void _writeStringSegment(String text, int offset, int len) throws IOExce 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) { + if (ch > 0x7F || sOutputEscapes[ch] != 0) { break; } outputBuffer[outputPtr++] = (byte) ch; @@ -1246,58 +704,10 @@ private void _writeStringSegment(String text, int offset, int len) throws IOExce } _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); - } + _writeStringSegment2(text, offset, len); } } - /** - * Secondary method called when content contains characters to escape, - * and/or multi-byte UTF-8 characters. - */ - private 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 void _writeStringSegment2(final String text, int offset, final int end) throws IOException { if ((_outputTail + 6 * (end - offset)) > _outputEnd) { _flushBuffer(); @@ -1306,16 +716,15 @@ private void _writeStringSegment2(final String text, int offset, final int end) 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) { + if (sOutputEscapes[ch] == 0) { outputBuffer[outputPtr++] = (byte) ch; continue; } - int escape = escCodes[ch]; + int escape = sOutputEscapes[ch]; if (escape > 0) { // 2-char escape, fine outputBuffer[outputPtr++] = BYTE_BACKSLASH; outputBuffer[outputPtr++] = (byte) escape; @@ -1335,332 +744,6 @@ private void _writeStringSegment2(final String text, int offset, final int end) _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 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 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 int _writeCustomEscape(byte[] outputBuffer, int outputPtr, SerializableString esc, int remainingChars) - throws IOException { - 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 int _handleLongCustomEscape(byte[] outputBuffer, int outputPtr, int outputEnd, byte[] raw, - int remainingChars) throws IOException { - final 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) { - _outputTail = outputPtr; - _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 void _writeUTF8Segments(byte[] utf8, int offset, int totalLen) throws IOException { - do { - int len = Math.min(_outputMaxContiguous, totalLen); - _writeUTF8Segment(utf8, offset, len); - offset += len; - totalLen -= len; - } while (totalLen > 0); - } - - private void _writeUTF8Segment(byte[] utf8, final int offset, final int len) throws IOException { - // 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 void _writeUTF8Segment2(final byte[] utf8, int offset, int len) throws IOException { - 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++]; - if ((int) b < 0 || escCodes[b] == 0) { - outputBuffer[outputPtr++] = b; - continue; - } - int escape = escCodes[b]; - if (escape > 0) { // 2-char escape, fine - outputBuffer[outputPtr++] = BYTE_BACKSLASH; - outputBuffer[outputPtr++] = (byte) escape; - } else { - // ctrl-char, 6-byte escape... - outputPtr = _writeGenericEscape(b, outputPtr); - } - } - _outputTail = outputPtr; - } - /* * /********************************************************** * /* Internal methods, low-level writing, base64 encoded @@ -1707,143 +790,6 @@ protected final void _writeBinary(Base64Variant b64variant, byte[] input, int in } } - // write-method called when length is definitely known - protected final int _writeBinary(Base64Variant b64variant, InputStream data, byte[] readBuffer, int bytesLeft) - throws IOException { - 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 { - 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, character escapes/encoding diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8StreamJsonParser.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8StreamJsonParser.java index 5daefedcb11f..2aff08c4add2 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8StreamJsonParser.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/UTF8StreamJsonParser.java @@ -1,37 +1,36 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.json; -import java.io.*; - -import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.base.ParserBase; +import com.azure.json.implementation.jackson.core.Base64Variant; +import com.azure.json.implementation.jackson.core.Base64Variants; +import com.azure.json.implementation.jackson.core.JsonLocation; +import com.azure.json.implementation.jackson.core.JsonParseException; +import com.azure.json.implementation.jackson.core.JsonParser; +import com.azure.json.implementation.jackson.core.JsonToken; import com.azure.json.implementation.jackson.core.io.CharTypes; import com.azure.json.implementation.jackson.core.io.IOContext; import com.azure.json.implementation.jackson.core.sym.ByteQuadsCanonicalizer; -import com.azure.json.implementation.jackson.core.util.*; +import com.azure.json.implementation.jackson.core.util.ByteArrayBuilder; + +import java.io.IOException; +import java.io.InputStream; -import static com.azure.json.implementation.jackson.core.JsonTokenId.*; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_FIELD_NAME; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NUMBER_FLOAT; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_NUMBER_INT; +import static com.azure.json.implementation.jackson.core.JsonTokenId.ID_STRING; /** * This is a concrete implementation of {@link JsonParser}, which is * based on a {@link InputStream} as the input source. */ @SuppressWarnings("fallthrough") -public class UTF8StreamJsonParser extends ParserBase { +public class UTF8StreamJsonParser extends JsonParser { final static byte BYTE_LF = (byte) '\n'; - @SuppressWarnings("deprecation") - private final static int FEAT_MASK_TRAILING_COMMA = Feature.ALLOW_TRAILING_COMMA.getMask(); - @SuppressWarnings("deprecation") - private final static int FEAT_MASK_LEADING_ZEROS = Feature.ALLOW_NUMERIC_LEADING_ZEROS.getMask(); @SuppressWarnings("deprecation") private final static int FEAT_MASK_NON_NUM_NUMBERS = Feature.ALLOW_NON_NUMERIC_NUMBERS.getMask(); - @SuppressWarnings("deprecation") - private final static int FEAT_MASK_ALLOW_MISSING = Feature.ALLOW_MISSING_VALUES.getMask(); - private final static int FEAT_MASK_ALLOW_SINGLE_QUOTES = Feature.ALLOW_SINGLE_QUOTES.getMask(); - private final static int FEAT_MASK_ALLOW_UNQUOTED_NAMES = Feature.ALLOW_UNQUOTED_FIELD_NAMES.getMask(); private final static int FEAT_MASK_ALLOW_JAVA_COMMENTS = Feature.ALLOW_COMMENTS.getMask(); - private final static int FEAT_MASK_ALLOW_YAML_COMMENTS = Feature.ALLOW_YAML_COMMENTS.getMask(); // This is the main input-code lookup table, fetched eagerly private final static int[] _icUTF8 = CharTypes.getInputCodeUtf8(); @@ -46,13 +45,6 @@ public class UTF8StreamJsonParser extends ParserBase { * /********************************************************** */ - /** - * Codec used for data binding when (if) requested; typically full - * ObjectMapper, but that abstract is not part of core - * package. - */ - protected ObjectCodec _objectCodec; - /** * Symbol table that contains field names encountered so far */ @@ -145,31 +137,6 @@ public class UTF8StreamJsonParser extends ParserBase { * @param ctxt I/O context to use * @param features Standard stream read features enabled * @param in InputStream used for reading actual content, if any; {@code null} if none - * @param codec {@code ObjectCodec} to delegate object deserialization to - * @param sym Name canonicalizer to use - * @param inputBuffer Input buffer to read initial content from (before Reader) - * @param start Pointer in {@code inputBuffer} that has the first content character to decode - * @param end Pointer past the last content character in {@code inputBuffer} - * @param bufferRecyclable Whether {@code inputBuffer} passed is managed by Jackson core - * (and thereby needs recycling) - * - * @deprecated Since 2.10 - */ - @Deprecated - public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in, ObjectCodec codec, - ByteQuadsCanonicalizer sym, byte[] inputBuffer, int start, int end, boolean bufferRecyclable) { - this(ctxt, features, in, codec, sym, inputBuffer, start, end, 0, bufferRecyclable); - } - - /** - * Constructor called when caller wants to provide input buffer directly - * (or needs to, in case of bootstrapping having read some of contents) - * and it may or may not be recyclable use standard recycle context. - * - * @param ctxt I/O context to use - * @param features Standard stream read features enabled - * @param in InputStream used for reading actual content, if any; {@code null} if none - * @param codec {@code ObjectCodec} to delegate object deserialization to * @param sym Name canonicalizer to use * @param inputBuffer Input buffer to read initial content from (before Reader) * @param start Pointer in {@code inputBuffer} that has the first content character to decode @@ -178,12 +145,10 @@ public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in, Object * @param bufferRecyclable Whether {@code inputBuffer} passed is managed by Jackson core * (and thereby needs recycling) */ - public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in, ObjectCodec codec, - ByteQuadsCanonicalizer sym, byte[] inputBuffer, int start, int end, int bytesPreProcessed, - boolean bufferRecyclable) { + public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in, ByteQuadsCanonicalizer sym, + byte[] inputBuffer, int start, int end, int bytesPreProcessed, boolean bufferRecyclable) { super(ctxt, features); _inputStream = in; - _objectCodec = codec; _symbols = sym; _inputBuffer = inputBuffer; _inputPtr = start; @@ -194,32 +159,6 @@ public UTF8StreamJsonParser(IOContext ctxt, int features, InputStream in, Object _bufferRecyclable = bufferRecyclable; } - @Override - public ObjectCodec getCodec() { - return _objectCodec; - } - - @Override - public void setCodec(ObjectCodec c) { - _objectCodec = c; - } - - @Override // @since 2.12 - public JacksonFeatureSet getReadCapabilities() { - return JSON_READ_CAPABILITIES; - } - - /* - * /********************************************************** - * /* Overrides for life-cycle - * /********************************************************** - */ - - @Override - public Object getInputSource() { - return _inputStream; - } - /* * /********************************************************** * /* Overrides, low-level reading @@ -266,7 +205,7 @@ protected void _closeInput() throws IOException { // 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)) { + if (_ioContext.isResourceManaged()) { _inputStream.close(); } _inputStream = null; @@ -315,32 +254,6 @@ public String getText() throws IOException { return _getText2(_currToken); } - @Override // since 2.8 - public int getText(Writer writer) throws IOException { - JsonToken t = _currToken; - if (t == JsonToken.VALUE_STRING) { - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - return _textBuffer.contentsToWriter(writer); - } - if (t == JsonToken.FIELD_NAME) { - String n = _parsingContext.getCurrentName(); - writer.write(n); - return n.length(); - } - if (t != null) { - if (t.isNumeric()) { - return _textBuffer.contentsToWriter(writer); - } - char[] ch = t.asCharArray(); - writer.write(ch); - return ch.length; - } - return 0; - } - // // // Let's override default impls for improved performance // @since 2.1 @@ -354,7 +267,7 @@ public String getValueAsString() throws IOException { return _textBuffer.contentsAsString(); } if (_currToken == JsonToken.FIELD_NAME) { - return getCurrentName(); + return currentName(); } return super.getValueAsString(null); } @@ -370,49 +283,11 @@ public String getValueAsString(String defValue) throws IOException { return _textBuffer.contentsAsString(); } if (_currToken == JsonToken.FIELD_NAME) { - return getCurrentName(); + return currentName(); } 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; @@ -433,92 +308,8 @@ protected final String _getText2(JsonToken t) { } @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 { + public byte[] getBinaryValue() throws IOException { + Base64Variant b64variant = Base64Variants.getDefaultVariant(); if (_currToken != JsonToken.VALUE_STRING && (_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) { _reportError("Current token (" + _currToken @@ -538,167 +329,13 @@ public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { if (_binaryValue == null) { @SuppressWarnings("resource") ByteArrayBuilder builder = _getByteArrayBuilder(); - _decodeBase64(getText(), builder, b64variant); + _decodeBase64(getText(), builder); _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 == INT_QUOTE) { - decodedData >>= 4; - buffer[outputPtr++] = (byte) decodedData; - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } - 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)) { - if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) { - 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 == INT_QUOTE) { - decodedData >>= 2; - buffer[outputPtr++] = (byte) (decodedData >> 8); - buffer[outputPtr++] = (byte) decodedData; - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } - 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 @@ -750,12 +387,6 @@ public JsonToken nextToken() throws IOException { _reportUnexpectedChar(i, "was expecting comma to separate " + _parsingContext.typeDesc() + " entries"); } i = _skipWS(); - // Was that a trailing comma? - if ((_features & FEAT_MASK_TRAILING_COMMA) != 0) { - if ((i == INT_RBRACKET) || (i == INT_RCURLY)) { - return _closeScope(i); - } - } } /* @@ -902,20 +533,6 @@ private JsonToken _nextAfterName() { return (_currToken = t); } - @Override - public void finishToken() throws IOException { - if (_tokenIncomplete) { - _tokenIncomplete = false; - _finishString(); // only strings can be incomplete - } - } - - /* - * /********************************************************** - * /* Public API, traversal, nextXxxValue/nextFieldName - * /********************************************************** - */ - /* * /********************************************************** * /* Internal methods, number parsing @@ -924,11 +541,7 @@ public void finishToken() throws IOException { // @since 2.11, [core#611] protected final JsonToken _parseFloatThatStartsWithPeriod() throws IOException { - // [core#611]: allow optionally leading decimal point - if (!isEnabled(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { - return _handleUnexpectedValue(INT_PERIOD); - } - return _parseFloat(_textBuffer.emptyAndGetCurrentSegment(), 0, INT_PERIOD, false, 0); + return _handleUnexpectedValue(INT_PERIOD); } /** @@ -1096,24 +709,7 @@ private int _verifyNoLeadingZeroes() throws IOException { if (ch < INT_0 || ch > INT_9) { return INT_0; } - // [JACKSON-358]: we may want to allow them, after all... - if ((_features & FEAT_MASK_LEADING_ZEROS) == 0) { - 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; - } - } - } + reportInvalidNumber(); return ch; } @@ -1590,173 +1186,10 @@ protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int * {@link JsonParseException} for decoding problems (invalid name) */ protected String _handleOddName(int ch) throws IOException { - // First: may allow single quotes - if (ch == INT_APOS && (_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) { - return _parseAposName(); - } // Allow unquoted names if feature enabled: - if ((_features & FEAT_MASK_ALLOW_UNQUOTED_NAMES) == 0) { - 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", JsonToken.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 apostrope-quoted names. 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 field name", JsonToken.FIELD_NAME); - } - } - int ch = _inputBuffer[_inputPtr++] & 0xFF; - if (ch == INT_APOS) { // special case, '' - return ""; - } - int[] quads = _quadBuffer; - int qlen = 0; - int currQuad = 0; - int currQuadBytes = 0; - - // Copied from parseEscapedFieldName, with minor mods: - - while (true) { - if (ch == INT_APOS) { - break; - } - // additional check to skip handling of double-quotes - if ((_icLatin1[ch] != 0) && (ch != INT_QUOTE)) { - if (ch != '\\') { - // Unquoted white space? - // As per [JACKSON-208], call can now return: - _throwUnquotedSpace(ch, "name"); - } else { - // Nope, escape sequence - ch = _decodeEscaped(); - } - // as per main code, inefficient but will have to do - 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", JsonToken.FIELD_NAME); - } - } - ch = _inputBuffer[_inputPtr++] & 0xFF; - } - - if (currQuadBytes > 0) { - if (qlen >= quads.length) { - _quadBuffer = quads = growArrayBy(quads, quads.length); - } - quads[qlen++] = _padLastQuad(currQuad, currQuadBytes); - } - String name = _symbols.findName(quads, qlen); - if (name == null) { - name = addName(quads, qlen, currQuadBytes); - } - return name; + char c = (char) _decodeCharForError(ch); + _reportUnexpectedChar(c, "was expecting double-quote to start field name"); + return null; } /* @@ -2187,25 +1620,12 @@ protected JsonToken _handleUnexpectedValue(int c) throws IOException { } // fall through case ',': - // 28-Mar-2016: [core#116]: If Feature.ALLOW_MISSING_VALUES is enabled - // we may allow "missing values", that is, encountering a trailing - // comma or closing marker where value would be expected - // 11-May-2020, tatu: [core#616] No commas in root level - if (!_parsingContext.inRoot()) { - if ((_features & FEAT_MASK_ALLOW_MISSING) != 0) { - --_inputPtr; - return JsonToken.VALUE_NULL; - } - } // fall through case '}': // Error: neither is valid at this point; valid closers have // been handled earlier _reportUnexpectedChar(c, "expected a value"); case '\'': - if ((_features & FEAT_MASK_ALLOW_SINGLE_QUOTES) != 0) { - return _handleApos(); - } break; case 'N': @@ -2235,104 +1655,13 @@ protected JsonToken _handleUnexpectedValue(int c) throws IOException { } // [core#77] Try to decode most likely token if (Character.isJavaIdentifierStart(c)) { - _reportInvalidToken("" + ((char) c), _validJsonTokenList()); + _reportInvalidToken("" + ((char) c), _validJsonValueList()); } // but if it doesn't look like a token: _reportUnexpectedChar(c, "expected a valid value " + _validJsonValueList()); 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 == INT_APOS) { - break main_loop; - } - if ((codes[c] != 0) - // 13-Oct-2021, tatu: [core#721] Alas, regular quote is included as - // special, need to ignore here - && (c != INT_QUOTE)) { - break ascii_loop; - } - outBuf[outPtr++] = (char) c; - } - } - - 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) { - _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; - } - /* * /********************************************************** * /* Internal methods, well-known token decoding @@ -2496,11 +1825,6 @@ private int _skipWS2() throws IOException { _skipComment(); continue; } - if (i == INT_HASH) { - if (_skipYAMLComment()) { - continue; - } - } return i; } if (i != INT_SPACE) { @@ -2575,11 +1899,6 @@ private int _skipWSOrEnd2() throws IOException { _skipComment(); continue; } - if (i == INT_HASH) { - if (_skipYAMLComment()) { - continue; - } - } return i; } else if (i != INT_SPACE) { if (i == INT_LF) { @@ -2659,11 +1978,6 @@ private int _skipColon2(boolean gotColon) throws IOException { _skipComment(); continue; } - if (i == INT_HASH) { - if (_skipYAMLComment()) { - continue; - } - } if (gotColon) { return i; } @@ -2755,14 +2069,6 @@ private void _skipCComment() throws IOException { _reportInvalidEOF(" in a comment", null); } - private boolean _skipYAMLComment() throws IOException { - if ((_features & FEAT_MASK_ALLOW_YAML_COMMENTS) == 0) { - return false; - } - _skipLine(); - return true; - } - // Method for skipping contents of an input line; usually for CPP // and YAML style comments. private void _skipLine() throws IOException { @@ -3085,7 +2391,7 @@ private int nextByte() throws IOException { */ protected void _reportInvalidToken(String matchedPart) throws IOException { - _reportInvalidToken(matchedPart, _validJsonTokenList()); + _reportInvalidToken(matchedPart, _validJsonValueList()); } protected void _reportInvalidToken(String matchedPart, String msg) throws IOException { @@ -3112,7 +2418,7 @@ protected void _reportInvalidToken(String matchedPart, String msg) throws IOExce break; } } - _reportError("Unrecognized token '%s': was expecting %s", sb, msg); + _reportError(sb, msg); } protected void _reportInvalidChar(int c) throws JsonParseException { @@ -3204,10 +2510,8 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio if (ch == INT_QUOTE) { decodedData >>= 4; builder.append(decodedData); - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } + --_inputPtr; // to keep parser state bit more consistent + _handleBase64MissingPadding(); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 2); @@ -3218,10 +2522,9 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio _loadMoreGuaranteed(); } ch = _inputBuffer[_inputPtr++] & 0xFF; - if (!b64variant.usesPaddingChar(ch)) { + if (ch != '=') { if (_decodeBase64Escape(b64variant, ch, 3) != Base64Variant.BASE64_VALUE_PADDING) { - throw reportInvalidBase64Char(b64variant, ch, 3, - "expected padding character '" + b64variant.getPaddingChar() + "'"); + throw reportInvalidBase64Char(ch, 3, "expected padding character '='"); } } // Got 12 bits, only need 8, need to shift @@ -3244,10 +2547,8 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio if (ch == INT_QUOTE) { decodedData >>= 2; builder.appendTwoBytes(decodedData); - if (b64variant.usesPadding()) { - --_inputPtr; // to keep parser state bit more consistent - _handleBase64MissingPadding(b64variant); - } + --_inputPtr; // to keep parser state bit more consistent + _handleBase64MissingPadding(); return builder.toByteArray(); } bits = _decodeBase64Escape(b64variant, ch, 3); @@ -3275,17 +2576,7 @@ protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOExceptio // As per [core#108], must ensure we call the right method @Override - public JsonLocation getTokenLocation() { - if (_currToken == JsonToken.FIELD_NAME) { - long total = _currInputProcessed + (_nameStartOffset - 1); - return new JsonLocation(_contentReference(), total, -1L, _nameStartRow, _nameStartCol); - } - return new JsonLocation(_contentReference(), _tokenInputTotal - 1, -1L, _tokenInputRow, _tokenInputCol); - } - - // As per [core#108], must ensure we call the right method - @Override - public JsonLocation getCurrentLocation() { + public JsonLocation currentLocation() { int col = _inputPtr - _currInputRowStart + 1; // 1-based return new JsonLocation(_contentReference(), _currInputProcessed + _inputPtr, -1L, // bytes, chars _currInputRow, col); @@ -3313,15 +2604,6 @@ private void _updateNameLocation() { * /********************************************************** */ - private JsonToken _closeScope(int i) throws JsonParseException { - if (i == INT_RCURLY) { - _closeObjectScope(); - return (_currToken = JsonToken.END_OBJECT); - } - _closeArrayScope(); - return (_currToken = JsonToken.END_ARRAY); - } - private void _closeArrayScope() throws JsonParseException { _updateLocation(); if (!_parsingContext.inArray()) { diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/WriterBasedJsonGenerator.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/WriterBasedJsonGenerator.java index c23c2e5f6791..632a13f58b2b 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/WriterBasedJsonGenerator.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/json/WriterBasedJsonGenerator.java @@ -1,21 +1,21 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.json; -import java.io.*; -import java.math.BigDecimal; -import java.math.BigInteger; - -import com.azure.json.implementation.jackson.core.*; +import com.azure.json.implementation.jackson.core.Base64Variant; +import com.azure.json.implementation.jackson.core.JsonGenerator; +import com.azure.json.implementation.jackson.core.JsonStreamContext; import com.azure.json.implementation.jackson.core.io.CharTypes; -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; import com.azure.json.implementation.jackson.core.io.IOContext; import com.azure.json.implementation.jackson.core.io.NumberOutput; +import java.io.IOException; +import java.io.Writer; + /** * {@link JsonGenerator} that outputs JSON content using a {@link Writer} * which handles character encoding. */ -public class WriterBasedJsonGenerator extends JsonGeneratorImpl { +public class WriterBasedJsonGenerator extends JsonGenerator { protected final static int SHORT_WRITE = 32; protected final static char[] HEX_CHARS = CharTypes.copyHexChars(); @@ -32,7 +32,7 @@ public class WriterBasedJsonGenerator extends JsonGeneratorImpl { * Character used for quoting JSON Object property names * and String values. */ - protected char _quoteChar; + protected final char _quoteChar; /* * /********************************************************** @@ -69,12 +69,6 @@ public class WriterBasedJsonGenerator extends JsonGeneratorImpl { */ 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; - /** * Intermediate buffer in which characters of a String are copied * before being encoded. @@ -89,47 +83,13 @@ public class WriterBasedJsonGenerator extends JsonGeneratorImpl { * /********************************************************** */ - @Deprecated // since 2.10 - public WriterBasedJsonGenerator(IOContext ctxt, int features, ObjectCodec codec, Writer w) { - this(ctxt, features, codec, w, JsonFactory.DEFAULT_QUOTE_CHAR); - } - // @since 2.10 - public WriterBasedJsonGenerator(IOContext ctxt, int features, ObjectCodec codec, Writer w, char quoteChar) - - { - super(ctxt, features, codec); + public WriterBasedJsonGenerator(IOContext ctxt, int features, Writer w) { + super(ctxt, features); _writer = w; _outputBuffer = ctxt.allocConcatBuffer(); _outputEnd = _outputBuffer.length; - _quoteChar = quoteChar; - if (quoteChar != '"') { // since 2.10 - _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar); - } - } - - /* - * /********************************************************** - * /* Overridden configuration, introspection 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); - } - - // json does allow this so - @Override - public boolean canWriteFormattedNumbers() { - return true; + _quoteChar = '"'; } /* @@ -147,16 +107,6 @@ public void writeFieldName(String name) throws IOException { _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 final void _writeFieldName(String name, boolean commaBefore) throws IOException { // for fast+std case, need to output up to 2 chars, comma, dquote if ((_outputTail + 1) >= _outputEnd) { @@ -165,11 +115,6 @@ protected final void _writeFieldName(String name, boolean commaBefore) throws IO 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++] = _quoteChar; // The beef: @@ -181,45 +126,6 @@ protected final void _writeFieldName(String name, boolean commaBefore) throws IO _outputBuffer[_outputTail++] = _quoteChar; } - protected final void _writeFieldName(SerializableString name, boolean commaBefore) throws IOException { - // 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) { - final char[] ch = name.asQuotedChars(); - writeRaw(ch, 0, ch.length); - return; - } - // we know there's room for at least one more char - _outputBuffer[_outputTail++] = _quoteChar; - // The beef: - - int len = name.appendQuoted(_outputBuffer, _outputTail); - if (len < 0) { - _writeFieldNameTail(name); - return; - } - _outputTail += len; - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - private void _writeFieldNameTail(SerializableString name) throws IOException { - final char[] quoted = name.asQuotedChars(); - writeRaw(quoted, 0, quoted.length); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - /* * /********************************************************** * /* Output method implementations, structural @@ -236,26 +142,6 @@ public void writeStartArray() throws IOException { _outputBuffer[_outputTail++] = '['; } - @Override // since 2.12 - public void writeStartArray(Object currentValue) throws IOException { - _verifyValueWrite("start an array"); - _writeContext = _writeContext.createChildArrayContext(currentValue); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '['; - } - - @Override // since 2.12 - public void writeStartArray(Object currentValue, int size) throws IOException { - _verifyValueWrite("start an array"); - _writeContext = _writeContext.createChildArrayContext(currentValue); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '['; - } - @Override public void writeEndArray() throws IOException { if (!_writeContext.inArray()) { @@ -278,17 +164,6 @@ public void writeStartObject() throws IOException { _outputBuffer[_outputTail++] = '{'; } - @Override // since 2.8 - public void writeStartObject(Object forValue) throws IOException { - _verifyValueWrite("start an object"); - JsonWriteContext ctxt = _writeContext.createChildObjectContext(forValue); - _writeContext = ctxt; - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = '{'; - } - @Override public void writeEndObject() throws IOException { if (!_writeContext.inObject()) { @@ -326,108 +201,6 @@ public void writeString(String text) throws IOException { _outputBuffer[_outputTail++] = _quoteChar; } - @Override - public void writeString(Reader reader, final int len) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (reader == null) { - _reportError("null reader"); - return; // just to block warnings by lgtm.com - } - int toRead = (len >= 0) ? len : Integer.MAX_VALUE; - // Add leading quote - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - - final char[] buf = _allocateCopyBuffer(); - while (toRead > 0) { - int toReadNow = Math.min(toRead, buf.length); - int numRead = reader.read(buf, 0, toReadNow); - if (numRead <= 0) { - break; - } - _writeString(buf, 0, numRead); - toRead -= numRead; - } - // Add trailing quote - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - - if (toRead > 0 && len >= 0) { - _reportError("Didn't read enough from reader"); - } - } - - @Override - public void writeString(char[] text, int offset, int len) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - _writeString(text, offset, len); - // And finally, closing quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - @Override - public void writeString(SerializableString sstr) throws IOException { - _verifyValueWrite(WRITE_STRING); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - int len = sstr.appendQuoted(_outputBuffer, _outputTail); - if (len < 0) { - _writeString2(sstr); - return; - } - _outputTail += len; - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - private void _writeString2(SerializableString sstr) throws IOException { - // Note: copied from writeRaw: - char[] text = sstr.asQuotedChars(); - final int len = text.length; - if (len < SHORT_WRITE) { - int room = _outputEnd - _outputTail; - if (len > room) { - _flushBuffer(); - } - System.arraycopy(text, 0, _outputBuffer, _outputTail, len); - _outputTail += len; - } else { - _flushBuffer(); - _writer.write(text, 0, len); - } - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - @Override - public void writeRawUTF8String(byte[] text, int offset, int length) { - // could add support for buffering if we really want it... - _reportUnsupportedOperation(); - } - - @Override - public void writeUTF8String(byte[] text, int offset, int length) { - // could add support for buffering if we really want it... - _reportUnsupportedOperation(); - } - /* * /********************************************************** * /* Output method implementations, unprocessed ("raw") @@ -471,17 +244,6 @@ public void writeRaw(String text, int start, int len) throws IOException { } } - // @since 2.1 - @Override - public void writeRaw(SerializableString text) throws IOException { - int len = text.appendUnquoted(_outputBuffer, _outputTail); - if (len < 0) { - writeRaw(text.getValue()); - return; - } - _outputTail += len; - } - @Override public void writeRaw(char[] text, int offset, int len) throws IOException { // Only worth buffering if it's a short write? @@ -499,14 +261,6 @@ public void writeRaw(char[] text, int offset, int len) throws IOException { _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 @@ -553,73 +307,15 @@ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int l _outputBuffer[_outputTail++] = _quoteChar; } - @Override - public int writeBinary(Base64Variant b64variant, InputStream data, int dataLength) throws IOException { - _verifyValueWrite(WRITE_BINARY); - // Starting quotes - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - 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++] = _quoteChar; - 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++] = _quoteChar; - _outputTail = NumberOutput.outputInt(s, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = _quoteChar; - } - @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(); @@ -627,22 +323,9 @@ public void writeNumber(int i) throws IOException { _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); } - private void _writeQuotedInt(int i) throws IOException { - if ((_outputTail + 13) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - _outputTail = NumberOutput.outputInt(i, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = _quoteChar; - } - @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(); @@ -650,33 +333,12 @@ public void writeNumber(long l) throws IOException { _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); } - private void _writeQuotedLong(long l) throws IOException { - if ((_outputTail + 23) >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - _outputTail = NumberOutput.outputLong(l, _outputBuffer, _outputTail); - _outputBuffer[_outputTail++] = _quoteChar; - } - // !!! 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()); - } - } - @SuppressWarnings("deprecation") @Override public void writeNumber(double d) throws IOException { - if (_cfgNumbersAsStrings || (NumberOutput.notFinite(d) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS))) { + if (NumberOutput.notFinite(d) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)) { writeString(String.valueOf(d)); return; } @@ -688,7 +350,7 @@ public void writeNumber(double d) throws IOException { @SuppressWarnings("deprecation") @Override public void writeNumber(float f) throws IOException { - if (_cfgNumbersAsStrings || (NumberOutput.notFinite(f) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS))) { + if (NumberOutput.notFinite(f) && isEnabled(Feature.QUOTE_NON_NUMERIC_NUMBERS)) { writeString(String.valueOf(f)); return; } @@ -698,91 +360,32 @@ public void writeNumber(float f) throws IOException { } @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) { - _writeQuotedRaw(_asString(value)); - } else { - writeRaw(_asString(value)); + public void writeBoolean(boolean state) throws IOException { + _verifyValueWrite(WRITE_BOOLEAN); + if ((_outputTail + 5) >= _outputEnd) { + _flushBuffer(); } - } - - @Override - public void writeNumber(String encodedValue) throws IOException { - _verifyValueWrite(WRITE_NUMBER); - if (encodedValue == null) { - _writeNull(); - } else if (_cfgNumbersAsStrings) { - _writeQuotedRaw(encodedValue); + int ptr = _outputTail; + char[] buf = _outputBuffer; + if (state) { + buf[ptr] = 't'; + buf[++ptr] = 'r'; + buf[++ptr] = 'u'; + buf[++ptr] = 'e'; } else { - writeRaw(encodedValue); + buf[ptr] = 'f'; + buf[++ptr] = 'a'; + buf[++ptr] = 'l'; + buf[++ptr] = 's'; + buf[++ptr] = 'e'; } + _outputTail = ptr + 1; } @Override - public void writeNumber(char[] encodedValueBuffer, int offset, int length) throws IOException { - _verifyValueWrite(WRITE_NUMBER); - if (_cfgNumbersAsStrings) { - _writeQuotedRaw(encodedValueBuffer, offset, length); - } else { - writeRaw(encodedValueBuffer, offset, length); - } - } - - private void _writeQuotedRaw(String value) throws IOException { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - writeRaw(value); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - private void _writeQuotedRaw(char[] text, int offset, int length) throws IOException { - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - writeRaw(text, offset, length); - if (_outputTail >= _outputEnd) { - _flushBuffer(); - } - _outputBuffer[_outputTail++] = _quoteChar; - } - - @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(); + public void writeNull() throws IOException { + _verifyValueWrite(WRITE_NULL); + _writeNull(); } /* @@ -809,9 +412,7 @@ protected final void _verifyValueWrite(String typeMsg) throws IOException { break; case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator - if (_rootValueSeparator != null) { - writeRaw(_rootValueSeparator.getValue()); - } + writeRaw(" "); return; case JsonWriteContext.STATUS_EXPECT_NAME: @@ -921,26 +522,19 @@ private void _writeString(String text) throws IOException { } text.getChars(0, len, _outputBuffer, _outputTail); - if (_characterEscapes != null) { - _writeStringCustom(len); - } else if (_maximumNonEscapedChar != 0) { - _writeStringASCII(len, _maximumNonEscapedChar); - } else { - _writeString2(len); - } + _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; + final int escLen = sOutputEscapes.length; output_loop: while (_outputTail < end) { // Fast loop for chars not needing escaping while (true) { char c = _outputBuffer[_outputTail]; - if (c < escLen && escCodes[c] != 0) { + if (c < escLen && sOutputEscapes[c] != 0) { break; } if (++_outputTail >= end) { @@ -962,7 +556,7 @@ private void _writeString2(final int len) throws IOException { * we have room now. */ char c = _outputBuffer[_outputTail++]; - _prependOrWriteCharacterEscape(c, escCodes[c]); + _prependOrWriteCharacterEscape(c, sOutputEscapes[c]); } } @@ -981,13 +575,7 @@ private void _writeLongString(String text) throws IOException { 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); - } + _writeSegment(segmentLen); offset += segmentLen; } while (offset < textLen); } @@ -1002,8 +590,7 @@ private void _writeLongString(String text) throws IOException { * 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; + final int escLen = sOutputEscapes.length; int ptr = 0; int start = ptr; @@ -1013,7 +600,7 @@ private void _writeSegment(int end) throws IOException { char c; while (true) { c = _outputBuffer[ptr]; - if (c < escLen && escCodes[c] != 0) { + if (c < escLen && sOutputEscapes[c] != 0) { break; } if (++ptr >= end) { @@ -1035,356 +622,7 @@ private void _writeSegment(int end) throws IOException { } ++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 { - // 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; - - output_loop: while (_outputTail < end) { - char c; - // Fast loop for chars not needing escaping - while (true) { - c = _outputBuffer[_outputTail]; - if (c < escLimit) { - escCode = escCodes[c]; - if (escCode != 0) { - break; - } - } else if (c > maxNonEscaped) { - escCode = CharacterEscapes.ESCAPE_STANDARD; - break; - } - 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 { - final int[] escCodes = _outputEscapes; - final int escLimit = Math.min(escCodes.length, maxNonEscaped + 1); - - int ptr = 0; - int escCode = 0; - int start = ptr; - - 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; - } - } - ++ptr; - start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode); - } - } - - private void _writeStringASCII(char[] text, int offset, int len, final int maxNonEscaped) throws IOException { - 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 { - // 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; - final CharacterEscapes customEscapes = _characterEscapes; - - output_loop: while (_outputTail < end) { - char c; - // Fast loop for chars not needing escaping - while (true) { - c = _outputBuffer[_outputTail]; - 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 (++_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 { - 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; - - 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; - } - } - ++ptr; - start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode); - } - } - - private void _writeStringCustom(char[] text, int offset, int len) throws IOException { - 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); + start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, sOutputEscapes[c]); } } @@ -1434,143 +672,6 @@ protected final void _writeBinary(Base64Variant b64variant, byte[] input, int in } } - // write-method called when length is definitely known - protected final int _writeBinary(Base64Variant b64variant, InputStream data, byte[] readBuffer, int bytesLeft) - throws IOException { - 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 { - 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 @@ -1620,66 +721,45 @@ private void _prependOrWriteCharacterEscape(char ch, int escCode) throws IOExcep _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 (_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; - 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); + 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; } - String escape; - - if (_currentEscape == null) { - escape = _characterEscapes.getEscapeSequence(ch).getValue(); - } else { - escape = _currentEscape.getValue(); - _currentEscape = null; + // won't fit, flush and write + char[] buf = _entityBuffer; + if (buf == null) { + buf = _allocateEntityBuffer(); } - 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); + 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); + } } /** @@ -1706,117 +786,45 @@ private int _prependOrWriteCharacterEscape(char[] buffer, int ptr, int end, char } 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 { - 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'; + 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; - buf[ptr++] = HEX_CHARS[hi >> 4]; - buf[ptr++] = HEX_CHARS[hi & 0xF]; + buffer[ptr++] = HEX_CHARS[hi >> 4]; + buffer[ptr++] = HEX_CHARS[hi & 0xF]; ch &= 0xFF; } else { - buf[ptr++] = '0'; - buf[ptr++] = '0'; + buffer[ptr++] = '0'; + buffer[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(); + buffer[ptr++] = HEX_CHARS[ch >> 4]; + buffer[ptr] = HEX_CHARS[ch & 0xF]; + ptr -= 5; } 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; + // 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); } } - escape.getChars(0, len, _outputBuffer, _outputTail); - _outputTail += len; + return ptr; } private char[] _allocateEntityBuffer() { @@ -1835,16 +843,6 @@ private char[] _allocateEntityBuffer() { return buf; } - /** - * @since 2.9 - */ - private char[] _allocateCopyBuffer() { - if (_copyBuffer == null) { - _copyBuffer = _ioContext.allocNameCopyBuffer(2000); - } - return _copyBuffer; - } - protected void _flushBuffer() throws IOException { int len = _outputTail - _outputHead; if (len > 0) { diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/package-info.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/package-info.java index be62f990e7bd..8999921c5ae3 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/package-info.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/package-info.java @@ -12,17 +12,6 @@ * is found from the "jackson-databind" bundle, except for following * base interfaces that are defined here: *

*/ diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/ByteQuadsCanonicalizer.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/ByteQuadsCanonicalizer.java index 8cd50339f5de..7e4a4a0bcbcc 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/ByteQuadsCanonicalizer.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/ByteQuadsCanonicalizer.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.concurrent.atomic.AtomicReference; -import com.azure.json.implementation.jackson.core.JsonFactory; import com.azure.json.implementation.jackson.core.util.InternCache; /** @@ -310,14 +309,10 @@ private static ByteQuadsCanonicalizer createRoot(int seed) { * Factory method used to create actual symbol table instance to * use for parsing. * - * @param flags Bit flags of active {@link JsonFactory.Feature}s enabled. - * * @return Actual canonicalizer instance that can be used by a parser */ - public ByteQuadsCanonicalizer makeChild(int flags) { - return new ByteQuadsCanonicalizer(this, _seed, _tableInfo.get(), - JsonFactory.Feature.INTERN_FIELD_NAMES.enabledIn(flags), - JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW.enabledIn(flags)); + public ByteQuadsCanonicalizer makeChild() { + return new ByteQuadsCanonicalizer(this, _seed, _tableInfo.get(), true, true); } /** @@ -938,9 +933,7 @@ private boolean _checkNeedForRehash() { // Yes if above 80%, or above 50% AND have ~1% spill-overs if (_count > (_hashSize >> 1)) { // over 50% int spillCount = (_spilloverEnd - _spilloverStart()) >> 2; - if ((spillCount > (1 + _count >> 7)) || (_count > (_hashSize * 0.80))) { - return true; - } + return (spillCount > (1 + _count >> 7)) || (_count > (_hashSize * 0.80)); } return false; } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/CharsToNameCanonicalizer.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/CharsToNameCanonicalizer.java index cba05bd1518c..4b79c2ac799b 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/CharsToNameCanonicalizer.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/CharsToNameCanonicalizer.java @@ -124,8 +124,6 @@ public final class CharsToNameCanonicalizer { */ private final int _seed; - private final int _flags; - /** * Whether any canonicalization should be attempted (whether using * intern or not. @@ -234,7 +232,6 @@ private CharsToNameCanonicalizer(int seed) { // 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: _hashShared = false; // doesn't really matter for root instance _longestCollisionList = 0; @@ -247,12 +244,11 @@ private CharsToNameCanonicalizer(int seed) { /** * Internal constructor used when creating child instances. */ - private CharsToNameCanonicalizer(CharsToNameCanonicalizer parent, int flags, int seed, TableInfo parentState) { + private CharsToNameCanonicalizer(CharsToNameCanonicalizer parent, int seed, TableInfo parentState) { _parent = parent; _seed = seed; _tableInfo = null; // not used by child tables - _flags = flags; - _canonicalize = JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(flags); + _canonicalize = true; // Then copy shared state _symbols = parentState.symbols; @@ -313,12 +309,10 @@ private static CharsToNameCanonicalizer createRoot(int seed) { * on which only makeChild/mergeChild are called, but instance itself * is not used as a symbol table. * - * @param flags Bit flags of active {@link JsonFactory.Feature}s enabled. - * * @return Actual canonicalizer instance that can be used by a parser */ - public CharsToNameCanonicalizer makeChild(int flags) { - return new CharsToNameCanonicalizer(this, flags, _seed, _tableInfo.get()); + public CharsToNameCanonicalizer makeChild() { + return new CharsToNameCanonicalizer(this, _seed, _tableInfo.get()); } /** @@ -467,9 +461,7 @@ private String _addSymbol(char[] buffer, int start, int len, int h, int index) { } String newSymbol = new String(buffer, start, len); - if (JsonFactory.Feature.INTERN_FIELD_NAMES.enabledIn(_flags)) { - newSymbol = InternCache.instance.intern(newSymbol); - } + newSymbol = InternCache.instance.intern(newSymbol); ++_size; // Ok; do we need to add primary entry, or a bucket? if (_symbols[index] == null) { @@ -504,9 +496,7 @@ private void _handleSpillOverflow(int bucketIndex, Bucket newBucket, int mainInd } else { if (_overflows.get(bucketIndex)) { // Has happened once already for this bucket index, so probably not coincidental... - if (JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW.enabledIn(_flags)) { - _reportTooManyCollisions(MAX_COLL_CHAIN_LENGTH); - } + _reportTooManyCollisions(); // but even if we don't fail, we will stop canonicalizing as safety measure // (so as not to cause problems with PermGen) _canonicalize = false; @@ -675,13 +665,12 @@ private void rehash() { } /** - * @param maxLen Maximum allowed length of collision chain - * * @since 2.1 */ - private 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"); + private void _reportTooManyCollisions() { + throw new IllegalStateException( + "Longest collision chain in symbol table (of size " + _size + ") now exceeds maximum, " + + CharsToNameCanonicalizer.MAX_COLL_CHAIN_LENGTH + " -- suspect a DoS attack based on hash collisions"); } // since 2.10, for tests only diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/Name.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/Name.java deleted file mode 100644 index 6c81c3ff6778..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/sym/Name.java +++ /dev/null @@ -1,60 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.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); - - 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); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/ResolvedType.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/ResolvedType.java deleted file mode 100644 index 0263fbda54a3..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/ResolvedType.java +++ /dev/null @@ -1,53 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.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 JavaType from "databind" bundle -- this - * abstraction is only needed so that types can be passed through - * {@link com.azure.json.implementation.jackson.core.JsonParser#readValueAs} methods. - * - * @since 2.0 - */ -public abstract class ResolvedType { - /* - * /********************************************************** - * /* Public API, simple property accessors - * /********************************************************** - */ - - public abstract boolean isAbstract(); - - public abstract boolean isThrowable(); - - public abstract boolean isInterface(); - - public abstract boolean isFinal(); - - /* - * /********************************************************** - * /* Public API, type parameter access - * /********************************************************** - */ - - /** - * @deprecated Since 2.7: does not have meaning as parameters depend on type - * resolved. - * - * @return Type-erased class of something not usable at this point - */ - @Deprecated // since 2.7 - public Class getParameterSource() { - return null; - } - - /* - * /********************************************************** - * /* Public API, other - * /********************************************************** - */ - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/TypeReference.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/TypeReference.java deleted file mode 100644 index fecfa23b0316..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/TypeReference.java +++ /dev/null @@ -1,62 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.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. - *

- * Usage is by sub-classing: here is one way to instantiate reference - * to generic type 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 TypeReference implements Comparable> { - protected final Type _type; - - protected TypeReference() { - Type superClass = getClass().getGenericSuperclass(); - if (superClass instanceof Class) { // sanity check, should never happen - throw new IllegalArgumentException( - "Internal error: TypeReference constructed without actual type information"); - } - /* - * 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect - * it is possible to make it fail? - * But let's deal with specific - * case when we know an actual use case, and thereby suitable - * workarounds for valid case(s) and/or error to throw - * on invalid one(s). - */ - _type = ((ParameterizedType) superClass).getActualTypeArguments()[0]; - } - - public Type getType() { - return _type; - } - - /** - * The only reason we define this method (and require implementation - * of Comparable) is to prevent constructing a - * reference without type information. - */ - @Override - public int compareTo(TypeReference o) { - return 0; - } - // just need an implementation, not a good one... hence ^^^ -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/WritableTypeId.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/WritableTypeId.java deleted file mode 100644 index cc21ea553f44..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/WritableTypeId.java +++ /dev/null @@ -1,128 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.type; - -import com.azure.json.implementation.jackson.core.JsonToken; - -/** - * This is a simple value class used between core streaming and higher level - * databinding to pass information about type ids to write. - * Properties are exposed and mutable on purpose: they are only used for communication - * over serialization of a single value, and neither retained across calls nor shared - * between threads. - *

- * Usual usage pattern is such that instance of this class is passed on two calls that are - * needed for outputting type id (and possible additional wrapping, depending on format; - * JSON, for example, requires wrapping as type id is part of regular data): first, a "prefix" - * write (which usually includes actual id), performed before value write; and then - * matching "suffix" write after value serialization. - * - * @since 2.9 - */ -public class WritableTypeId { - /** - * Enumeration of values that matches enum `As` from annotation - * `JsonTypeInfo`: separate definition to avoid dependency between - * streaming core and annotations packages; also allows more flexibility - * in case new values needed at this level of internal API. - *

- * NOTE: in most cases this only matters with formats that do NOT have native - * type id capabilities, and require type id to be included within regular - * data (whether exposed as Java properties or not). Formats with native - * types usually use native type id functionality regardless, unless - * overridden by a feature to use "non-native" type inclusion. - */ - public enum Inclusion { - /** - * Inclusion as wrapper Array (1st element type id, 2nd element value). - *

- * Corresponds to JsonTypeInfo.As.WRAPPER_ARRAY. - */ - WRAPPER_ARRAY, - - /** - * Inclusion as wrapper Object that has one key/value pair where type id - * is the key for typed value. - *

- * Corresponds to JsonTypeInfo.As.WRAPPER_OBJECT. - */ - WRAPPER_OBJECT, - - /** - * Inclusion as a property within Object to write, but logically as separate - * metadata that is not exposed as payload to caller: that is, does not match - * any of visible properties value object has. - *

- * NOTE: if shape of typed value to write is NOT Object, will instead use - * {@link #WRAPPER_ARRAY} inclusion. - *

- * Corresponds to JsonTypeInfo.As.PROPERTY. - */ - METADATA_PROPERTY, - - /** - * Inclusion as a property within "parent" Object of value Object to write. - * This typically requires slightly convoluted processing in which property - * that contains type id is actually written after typed value object - * itself is written. - *
- * Note that it is illegal to call write method if the current (parent) write context - * is not Object: no coercion is done for other inclusion types (unlike with - * other xxx_PROPERTY choices. - * This also means that root values MAY NOT use this type id inclusion mechanism - * (as they have no parent context). - *

- * Corresponds to JsonTypeInfo.As.EXTERNAL_PROPERTY. - */ - PARENT_PROPERTY - - } - - /** - * Java object for which type id is being written. Not needed by default handling, - * but may be useful for customized format handling. - */ - public Object forValue; - - /** - * Actual type id to use: usually {link java.lang.String}. - */ - public Object id; - - /** - * Property used to indicate style of inclusion for this type id, in cases where - * no native type id may be used (either because format has none, like JSON; or - * because use of native type ids is disabled [with YAML]). - */ - public Inclusion include; - - /** - * Information about intended shape of the value being written (that is, {@link #forValue}); - * in case of structured values, start token of the structure; for scalars, value token. - * Main difference is between structured values - * ({@link JsonToken#START_ARRAY}, {@link JsonToken#START_OBJECT}) - * and scalars ({@link JsonToken#VALUE_STRING}): specific scalar type may not be - * important for processing. - */ - public JsonToken valueShape; - - /** - * Optional additional information that generator may add during "prefix write", - * to be available on matching "suffix write". - */ - public Object extra; - - /** - * Constructor used when calling a method for writing Type Id; - * caller knows value object, its intended shape as well as id to - * use; but not details of wrapping (if any). - * - * @param value Actual value for which type information is written - * @param valueShape Serialize shape writer will use for value - * @param id Actual type id to use if known; {@code null} if not - */ - public WritableTypeId(Object value, JsonToken valueShape, Object id) { - forValue = value; - this.id = id; - this.valueShape = valueShape; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/package-info.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/package-info.java deleted file mode 100644 index eeb8c0885ec2..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/type/package-info.java +++ /dev/null @@ -1,13 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -/** - * Contains classes needed for type introspection, mostly used by data binding - * functionality. Most of this functionality is needed to properly handled - * generic types, and to simplify and unify processing of things Jackson needs - * to determine how contained types (of {@link java.util.Collection} and - * {@link java.util.Map} classes) are to be handled. - *

- * With 2.9, an additional type ({@link com.azure.json.implementation.jackson.core.type.WritableTypeId}) - * was added to help handling of type identifiers needed to support polymorphic - * type serialization, deserialization. - */ -package com.azure.json.implementation.jackson.core.type; diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecycler.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecycler.java index 0b6a9f000798..37abab8761e4 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecycler.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecycler.java @@ -32,14 +32,6 @@ public class BufferRecycler { */ 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; - /** * Buffer used as input buffer for tokenization for character-based parsers. */ @@ -54,10 +46,7 @@ public class BufferRecycler { /** * Used through {@link TextBuffer}: directly by parsers (to concatenate - * String values) - * and indirectly via - * {@link com.azure.json.implementation.jackson.core.io.SegmentedStringWriter} - * when serializing (databind level {@code ObjectMapper} and + * String values) when serializing (databind level {@code ObjectMapper} and * {@code ObjectWriter}). In both cases used as segments (and not for whole value), * but may result in retention of larger chunks for big content * (long text values during parsing; bigger output documents for generation). diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecyclers.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecyclers.java index 43aa62604b9d..1d8b91cafa27 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecyclers.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/BufferRecyclers.java @@ -3,8 +3,6 @@ import java.lang.ref.SoftReference; -import com.azure.json.implementation.jackson.core.io.JsonStringEncoder; - /** * Helper entity used to control access to simple buffer recyling scheme used for * some encoding, decoding tasks. @@ -77,86 +75,4 @@ public static BufferRecycler getBufferRecycler() { } return br; } - - /* - * /********************************************************************** - * /* Obsolete things re-introduced in 2.12.5 after accidental direct - * /* removal from 2.10.0 - * /********************************************************************** - */ - - /** - * Not to be used any more: call {@link JsonStringEncoder#getInstance()} instead. - * - * @return {@code JsonStringEncoder} instance to use. - * - * @deprecated Since 2.10 (note: was accidentally removed but reintroduced as deprecated - * in 2.12.5, to be removed from 3.0) - */ - @Deprecated - public static JsonStringEncoder getJsonStringEncoder() { - return JsonStringEncoder.getInstance(); - } - - /** - * Not to be used any more: call {@link JsonStringEncoder#getInstance()} (and then - * {@code encodeAsUTF8()}) instead. - * - * @param text String to encode - * @return String encoded as UTF-8 bytes. - * - * @deprecated Since 2.10 (note: was accidentally removed but reintroduced as deprecated - * in 2.12.5, to be removed from 3.0) - */ - @Deprecated - public static byte[] encodeAsUTF8(String text) { - return JsonStringEncoder.getInstance().encodeAsUTF8(text); - } - - /** - * Not to be used any more: call {@link JsonStringEncoder#getInstance()} (and then - * {@code quoteAsString()}) instead. - * - * @param rawText String to quote - * - * @return Quoted text as {@code char[]} - * - * @deprecated Since 2.10 (note: was accidentally removed but reintroduced as deprecated - * in 2.12.5, to be removed from 3.0) - */ - @Deprecated - public static char[] quoteAsJsonText(String rawText) { - return JsonStringEncoder.getInstance().quoteAsString(rawText); - } - - /** - * Not to be used any more: call {@link JsonStringEncoder#getInstance()} (and then - * {@code quoteAsString()}) instead. - * - * @param input Textual content to quote - * @param output Builder to append quoted content - * - * @deprecated Since 2.10 (note: was accidentally removed but reintroduced as deprecated - * in 2.12.5, to be removed from 3.0) - */ - @Deprecated - public static void quoteAsJsonText(CharSequence input, StringBuilder output) { - JsonStringEncoder.getInstance().quoteAsString(input, output); - } - - /** - * Not to be used any more: call {@link JsonStringEncoder#getInstance()} (and then - * {@code quoteAsUTF8()}) instead. - * - * @param rawText String to quote - * - * @return Quoted text as {@code byte[]} - * - * @deprecated Since 2.10 (note: was accidentally removed but reintroduced as deprecated - * in 2.12.5, to be removed from 3.0) - */ - @Deprecated - public static byte[] quoteAsJsonUTF8(String rawText) { - return JsonStringEncoder.getInstance().quoteAsUTF8(rawText); - } } diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JacksonFeature.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JacksonFeature.java deleted file mode 100644 index c0dface83ca2..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JacksonFeature.java +++ /dev/null @@ -1,36 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -/** - * Basic API implemented by Enums used for simple Jackson "features": on/off - * settings and capabilities exposed as something that can be internally - * represented as bit sets. - * Designed to be used with {@link JacksonFeatureSet}. - * - * @since 2.12 - */ -public interface JacksonFeature { - /** - * Accessor for checking whether this feature is enabled by default. - * - * @return Whether this instance is enabled by default or not - */ - boolean enabledByDefault(); - - /** - * Returns bit mask for this feature instance; must be a single bit, - * that is of form {@code 1 << N}. - * - * @return Bit mask of this feature - */ - int getMask(); - - /** - * Convenience method for checking whether feature is enabled in given bitmask. - * - * @param flags Bit field that contains a set of enabled features of this type - * - * @return True if this feature is enabled in passed bit field - */ - boolean enabledIn(int flags); -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JacksonFeatureSet.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JacksonFeatureSet.java deleted file mode 100644 index 730efcf301e0..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JacksonFeatureSet.java +++ /dev/null @@ -1,93 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -/** - * Container similar to {@link java.util.EnumSet} meant for storing sets of - * {@link JacksonFeature}s (usually {@link Enum}s): main - * difference being that these sets are immutable. Also only supports relatively - * small sets of features: specifically, up to 31 features. - * - * @since 2.12 - */ -public final class JacksonFeatureSet { - private final int _enabled; - - /** - * Constructor for creating instance with specific bitmask, wherein - * {@code 1} bit means matching {@link JacksonFeature} is enabled and - * {@code 0} disabled. - * - * @param bitmask Bitmask for features that are enabled - */ - private JacksonFeatureSet(int bitmask) { - _enabled = bitmask; - } - - /** - * "Default" factory which will calculate settings based on default-enabled - * status of all features. - * - * @param Self-reference type for convenience - * - * @param allFeatures Set of all features (enabled or disabled): usually from - * {@code Enum.values()} - * - * @return Feature set instance constructed - */ - public static JacksonFeatureSet fromDefaults(F[] allFeatures) { - // first sanity check - if (allFeatures.length > 31) { - final String desc = allFeatures[0].getClass().getName(); - throw new IllegalArgumentException(String.format( - "Can not use type `%s` with JacksonFeatureSet: too many entries (%d > 31)", desc, allFeatures.length)); - } - - int flags = 0; - for (F f : allFeatures) { - if (f.enabledByDefault()) { - flags |= f.getMask(); - } - } - return new JacksonFeatureSet<>(flags); - } - - /** - * Mutant factory for getting a set in which specified feature is enabled: - * will either return this instance (if no change), or newly created set (if there - * is change). - * - * @param feature Feature to enable in set returned - * - * @return Newly created set of state of feature changed; {@code this} if not - */ - public JacksonFeatureSet with(F feature) { - int newMask = _enabled | feature.getMask(); - return (newMask == _enabled) ? this : new JacksonFeatureSet<>(newMask); - } - - /** - * Mutant factory for getting a set in which specified feature is disabled: - * will either return this instance (if no change), or newly created set (if there - * is change). - * - * @param feature Feature to disable in set returned - * - * @return Newly created set of state of feature changed; {@code this} if not - */ - public JacksonFeatureSet without(F feature) { - int newMask = _enabled & ~feature.getMask(); - return (newMask == _enabled) ? this : new JacksonFeatureSet<>(newMask); - } - - /** - * Main accessor for checking whether given feature is enabled in this feature set. - * - * @param feature Feature to check - * - * @return True if feature is enabled in this set; false otherwise - */ - public boolean isEnabled(F feature) { - return (feature.getMask() & _enabled) != 0; - } - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonGeneratorDelegate.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonGeneratorDelegate.java deleted file mode 100644 index 18ef6eba0d6f..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonGeneratorDelegate.java +++ /dev/null @@ -1,641 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -import com.azure.json.implementation.jackson.core.*; -import com.azure.json.implementation.jackson.core.io.CharacterEscapes; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.math.BigDecimal; -import java.math.BigInteger; - -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 - * /********************************************************************** - */ - - /** - * @param d Underlying generator to delegate calls to - * @param delegateCopyMethods Flag assigned to delagateCopyMethod - * 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; - } - - /* - * /********************************************************************** - * /* Public API, metadata/state access - * /********************************************************************** - */ - - @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(); - } - - @Override - public void assignCurrentValue(Object v) { - delegate.assignCurrentValue(v); - } - - @Override - public Object currentValue() { - return delegate.currentValue(); - } - - // TODO: deprecate in 2.14 or later - @Override - public void setCurrentValue(Object v) { - delegate.setCurrentValue(v); - } - - // TODO: deprecate in 2.14 or later - @Override - public Object getCurrentValue() { - return delegate.getCurrentValue(); - } - - /* - * /********************************************************************** - * /* Public API, capability introspection - * /********************************************************************** - */ - - @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(); - } - - @Override - public boolean canWriteFormattedNumbers() { - return delegate.canWriteFormattedNumbers(); - } - - @Override - public JacksonFeatureSet getWriteCapabilities() { - return delegate.getWriteCapabilities(); - } - - /* - * /********************************************************************** - * /* 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 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(); - } - - @SuppressWarnings("deprecation") - @Override - public void writeStartArray(int size) throws IOException { - delegate.writeStartArray(size); - } - - @Override - public void writeStartArray(Object forValue) throws IOException { - delegate.writeStartArray(forValue); - } - - @Override - public void writeStartArray(Object forValue, int size) throws IOException { - delegate.writeStartArray(forValue, size); - } - - @Override - public void writeEndArray() throws IOException { - delegate.writeEndArray(); - } - - @Override - public void writeStartObject() throws IOException { - delegate.writeStartObject(); - } - - @Override - public void writeStartObject(Object forValue) throws IOException { - delegate.writeStartObject(forValue); - } - - @Override - public void writeStartObject(Object forValue, int size) throws IOException { - delegate.writeStartObject(forValue, size); - } - - @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); - } - - @Override - public void writeFieldId(long id) throws IOException { - delegate.writeFieldId(id); - } - - @Override - public void writeArray(int[] array, int offset, int length) throws IOException { - delegate.writeArray(array, offset, length); - } - - @Override - public void writeArray(long[] array, int offset, int length) throws IOException { - delegate.writeArray(array, offset, length); - } - - @Override - public void writeArray(double[] array, int offset, int length) throws IOException { - delegate.writeArray(array, offset, length); - } - - @Override - public void writeArray(String[] array, int offset, int length) throws IOException { - delegate.writeArray(array, offset, length); - } - - /* - * /********************************************************************** - * /* Public API, write methods, text/String values - * /********************************************************************** - */ - - @Override - public void writeString(String text) throws IOException { - delegate.writeString(text); - } - - @Override - public void writeString(Reader reader, int len) throws IOException { - delegate.writeString(reader, len); - } - - @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 writeNumber(char[] encodedValueBuffer, int offset, int length) - throws IOException, UnsupportedOperationException { - delegate.writeNumber(encodedValueBuffer, offset, length); - } - - @Override - public void writeBoolean(boolean state) throws IOException { - delegate.writeBoolean(state); - } - - @Override - public void writeNull() throws IOException { - delegate.writeNull(); - } - - /* - * /********************************************************************** - * /* Public API, convenience field-write methods - * /********************************************************************** - */ - - // 04-Oct-2019, tatu: Reminder: these should NOT be delegated, unless matching - // methods in `FilteringGeneratorDelegate` are re-defined to "split" calls again - - // public void writeBinaryField(String fieldName, byte[] data) throws IOException { - // public void writeBooleanField(String fieldName, boolean value) throws IOException { - // public void writeNullField(String fieldName) throws IOException { - // public void writeStringField(String fieldName, String value) throws IOException { - // public void writeNumberField(String fieldName, short value) throws IOException { - - // public void writeArrayFieldStart(String fieldName) throws IOException { - // public void writeObjectFieldStart(String fieldName) throws IOException { - // public void writeObjectField(String fieldName, Object pojo) throws IOException { - // public void writePOJOField(String fieldName, Object pojo) throws IOException { - - // Sole exception being this method as it is not a "combo" method - - @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); - } - - @Override - public void writeEmbeddedObject(Object object) throws IOException { - delegate.writeEmbeddedObject(object); - } - - /* - * /********************************************************************** - * /* Public API, write methods, serializing Java objects - * /********************************************************************** - */ - - @Override - public void writeObject(Object pojo) throws IOException { - if (delegateCopyMethods) { - delegate.writeObject(pojo); - return; - } - if (pojo == null) { - writeNull(); - } else { - ObjectCodec c = getCodec(); - if (c != null) { - c.writeValue(this, pojo); - return; - } - _writeSimpleObject(pojo); - } - } - - @Override - public void writeTree(TreeNode tree) throws IOException { - if (delegateCopyMethods) { - delegate.writeTree(tree); - return; - } - // As with 'writeObject()', we are not check if write would work - if (tree == null) { - writeNull(); - } else { - ObjectCodec c = getCodec(); - if (c == null) { - throw new IllegalStateException("No ObjectCodec defined"); - } - c.writeTree(this, tree); - } - } - - /* - * /********************************************************************** - * /* Public API, convenience field write methods - * /********************************************************************** - */ - - // // These are fine, just delegate to other methods... - - /* - * /********************************************************************** - * /* Public API, copy-through methods - * /********************************************************************** - */ - - @Override - public void copyCurrentEvent(JsonParser p) throws IOException { - if (delegateCopyMethods) - delegate.copyCurrentEvent(p); - else - super.copyCurrentEvent(p); - } - - @Override - public void copyCurrentStructure(JsonParser p) throws IOException { - if (delegateCopyMethods) - delegate.copyCurrentStructure(p); - else - super.copyCurrentStructure(p); - } - - /* - * /********************************************************************** - * /* 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(); - } - - @Override - public boolean isClosed() { - return delegate.isClosed(); - } - - /* - * /********************************************************************** - * /* Extended API - * /********************************************************************** - */ - - @Deprecated // since 2.11 - public JsonGenerator getDelegate() { - return delegate; - } - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonParserDelegate.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonParserDelegate.java deleted file mode 100644 index e61d9e5e6648..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonParserDelegate.java +++ /dev/null @@ -1,526 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.math.BigDecimal; -import java.math.BigInteger; - -import com.azure.json.implementation.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; - } - - /* - * /********************************************************************** - * /* 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(); - } - - @Override - public JacksonFeatureSet getReadCapabilities() { - return delegate.getReadCapabilities(); - } - - /* - * /********************************************************************** - * /* Closeable impl - * /********************************************************************** - */ - - @Override - public void close() throws IOException { - delegate.close(); - } - - @Override - public boolean isClosed() { - return delegate.isClosed(); - } - - /* - * /********************************************************************** - * /* Public API, state change/override methods - * /********************************************************************** - */ - - @Override - public void clearCurrentToken() { - delegate.clearCurrentToken(); - } - - @Override - public JsonToken getLastClearedToken() { - return delegate.getLastClearedToken(); - } - - @Override - public void overrideCurrentName(String name) { - delegate.overrideCurrentName(name); - } - - @Override // since 2.13 - public void assignCurrentValue(Object v) { - delegate.assignCurrentValue(v); - } - - // TODO: deprecate in 2.14 or later - @Override - public void setCurrentValue(Object v) { - delegate.setCurrentValue(v); - } - - /* - * /********************************************************************** - * /* Public API, state/location accessors - * /********************************************************************** - */ - - @Override - public JsonStreamContext getParsingContext() { - return delegate.getParsingContext(); - } - - @Override - public JsonToken currentToken() { - return delegate.currentToken(); - } - - @Override - public int currentTokenId() { - return delegate.currentTokenId(); - } - - @Override - public String currentName() throws IOException { - return delegate.currentName(); - } - - @Override // since 2.13 - public Object currentValue() { - return delegate.currentValue(); - } - - @Override // since 2.13 - public JsonLocation currentLocation() { - return delegate.getCurrentLocation(); - } - - @Override // since 2.13 - public JsonLocation currentTokenLocation() { - return delegate.getTokenLocation(); - } - - // TODO: deprecate in 2.14 or later - @Override - public JsonToken getCurrentToken() { - return delegate.getCurrentToken(); - } - - @Deprecated // since 2.12 - @Override - public int getCurrentTokenId() { - return delegate.getCurrentTokenId(); - } - - // TODO: deprecate in 2.14 or later - @Override - public String getCurrentName() throws IOException { - return delegate.getCurrentName(); - } - - // TODO: deprecate in 2.14 or later - @Override - public Object getCurrentValue() { - return delegate.getCurrentValue(); - } - - // TODO: deprecate in 2.14 or later - @Override - public JsonLocation getCurrentLocation() { - return delegate.getCurrentLocation(); - } - - // TODO: deprecate in 2.14 or later - @Override - public JsonLocation getTokenLocation() { - return delegate.getTokenLocation(); - } - - /* - * /********************************************************************** - * /* Public API, token accessors - * /********************************************************************** - */ - - @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 boolean isExpectedStartArrayToken() { - return delegate.isExpectedStartArrayToken(); - } - - @Override - public boolean isExpectedStartObjectToken() { - return delegate.isExpectedStartObjectToken(); - } - - @Override - public boolean isExpectedNumberIntToken() { - return delegate.isExpectedNumberIntToken(); - } - - @Override - public boolean isNaN() throws IOException { - return delegate.isNaN(); - } - - /* - * /********************************************************************** - * /* Public API, access to token textual content - * /********************************************************************** - */ - - @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(); - } - - @Override - public int getText(Writer writer) throws IOException, UnsupportedOperationException { - return delegate.getText(writer); - } - - /* - * /********************************************************************** - * /* Public API, access to token numeric values - * /********************************************************************** - */ - - @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(); - } - - @Override - public Number getNumberValueExact() throws IOException { - return delegate.getNumberValueExact(); - } - - /* - * /********************************************************************** - * /* 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 JsonToken nextToken() throws IOException { - return delegate.nextToken(); - } - - @Override - public JsonToken nextValue() throws IOException { - return delegate.nextValue(); - } - - @Override - public void finishToken() throws IOException { - delegate.finishToken(); - } - - @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(); - } - - /* - * /********************************************************************** - * /* Extended API - * /********************************************************************** - */ - -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonParserSequence.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonParserSequence.java deleted file mode 100644 index 43e9b22e4500..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/JsonParserSequence.java +++ /dev/null @@ -1,225 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -import java.io.IOException; -import java.util.*; - -import com.azure.json.implementation.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}. - *

- * 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; - - /** - * Configuration that determines whether state of parsers is first verified - * to see if parser already points to a token (that is, - * {@link JsonParser#hasCurrentToken()} returns true), and if so - * that token is first return before {@link JsonParser#nextToken} is called. - * If enabled, this check is made; if disabled, no check is made and - * {@link JsonParser#nextToken} is always called for all parsers. - *

- * Default setting is false (for backwards-compatibility) - * so that possible existing token is not considered for parsers. - * - * @since 2.8 - */ - protected final boolean _checkForExistingToken; - - /** - * Index of the next parser in {@link #_parsers}. - */ - protected int _nextParserIndex; - - /** - * Flag used to indicate that `JsonParser.nextToken()` should not be called, - * due to parser already pointing to a token. - * - * @since 2.8 - */ - protected boolean _hasToken; - - /* - ******************************************************* - * Construction - ******************************************************* - */ - - @Deprecated // since 2.8 - protected JsonParserSequence(JsonParser[] parsers) { - this(false, parsers); - } - - // @since 2.8 - protected JsonParserSequence(boolean checkForExistingToken, JsonParser[] parsers) { - super(parsers[0]); - _checkForExistingToken = checkForExistingToken; - _hasToken = checkForExistingToken && delegate.hasCurrentToken(); - _parsers = parsers; - _nextParserIndex = 1; - } - - /** - * Method that will construct a sequence (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. - * - * @param checkForExistingToken Flag passed to be assigned as - * {@link #_checkForExistingToken} for resulting sequence - * @param first First parser to traverse - * @param second Second parser to traverse - * - * @return Sequence instance constructed - */ - public static JsonParserSequence createFlattened(boolean checkForExistingToken, JsonParser first, - JsonParser second) { - if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) { - return new JsonParserSequence(checkForExistingToken, new JsonParser[] { first, second }); - } - ArrayList p = new ArrayList<>(); - if (first instanceof JsonParserSequence) { - ((JsonParserSequence) first).addFlattenedActiveParsers(p); - } else { - p.add(first); - } - if (second instanceof JsonParserSequence) { - ((JsonParserSequence) second).addFlattenedActiveParsers(p); - } else { - p.add(second); - } - return new JsonParserSequence(checkForExistingToken, p.toArray(new JsonParser[0])); - } - - @Deprecated // since 2.8 - public static JsonParserSequence createFlattened(JsonParser first, JsonParser second) { - return createFlattened(false, first, second); - } - - @SuppressWarnings("resource") - protected void addFlattenedActiveParsers(List listToAddIn) { - for (int i = _nextParserIndex - 1, len = _parsers.length; i < len; ++i) { - JsonParser p = _parsers[i]; - if (p instanceof JsonParserSequence) { - ((JsonParserSequence) p).addFlattenedActiveParsers(listToAddIn); - } else { - listToAddIn.add(p); - } - } - } - - /* - * /******************************************************* - * /* Overridden methods, needed: cases where default - * /* delegation does not work - * /******************************************************* - */ - - @Override - public void close() throws IOException { - do { - delegate.close(); - } while (switchToNext()); - } - - @Override - public JsonToken nextToken() throws IOException { - if (delegate == null) { - return null; - } - if (_hasToken) { - _hasToken = false; - return delegate.currentToken(); - } - JsonToken t = delegate.nextToken(); - if (t == null) { - return switchAndReturnNext(); - } - return t; - } - - /** - * Need to override, re-implement similar to how method defined in - * {@link com.azure.json.implementation.jackson.core.base.ParserMinimalBase}, to keep - * state correct here. - */ - @Override - public JsonParser skipChildren() throws IOException { - if ((delegate.currentToken() != JsonToken.START_OBJECT) && (delegate.currentToken() != 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; - } - } - } - } - - /* - * /******************************************************* - * /* Additional extended API - * /******************************************************* - */ - - /* - * /******************************************************* - * /* Helper methods - * /******************************************************* - */ - - /** - * Method that will switch active delegate parser from the current one - * to the next parser in sequence, if there is another parser left: - * if so, the next parser will become the active delegate parser. - * - * @return True if switch succeeded; false otherwise - * - * @since 2.8 - */ - protected boolean switchToNext() { - if (_nextParserIndex < _parsers.length) { - delegate = _parsers[_nextParserIndex++]; - return true; - } - return false; - } - - protected JsonToken switchAndReturnNext() throws IOException { - while (_nextParserIndex < _parsers.length) { - delegate = _parsers[_nextParserIndex++]; - if (_checkForExistingToken && delegate.hasCurrentToken()) { - return delegate.getCurrentToken(); - } - JsonToken t = delegate.nextToken(); - if (t != null) { - return t; - } - } - return null; - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/RequestPayload.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/RequestPayload.java deleted file mode 100644 index 056e72a1df46..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/RequestPayload.java +++ /dev/null @@ -1,45 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -import java.io.IOException; - -/** - * Container object used to contain optional information on content - * being parsed, passed to {@link com.azure.json.implementation.jackson.core.JsonParseException} in case of - * exception being thrown; this may be useful for caller to display - * information on failure. - * - * @since 2.8 - */ -public class RequestPayload implements java.io.Serializable // just in case, even though likely included as transient -{ - private static final long serialVersionUID = 1L; - - // request payload as byte[] - protected byte[] _payloadAsBytes; - - // request payload as String - protected CharSequence _payloadAsText; - - // Charset if the request payload is set in bytes - protected String _charset; - - public RequestPayload(CharSequence str) { - if (str == null) { - throw new IllegalArgumentException(); - } - _payloadAsText = str; - } - - @Override - public String toString() { - if (_payloadAsBytes != null) { - try { - return new String(_payloadAsBytes, _charset); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - return _payloadAsText.toString(); - } -} diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/TextBuffer.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/TextBuffer.java index 24bb974bcd59..57b76773207b 100644 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/TextBuffer.java +++ b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/TextBuffer.java @@ -1,8 +1,6 @@ // Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. package com.azure.json.implementation.jackson.core.util; -import java.io.*; -import java.math.BigDecimal; import java.util.*; import com.azure.json.implementation.jackson.core.io.NumberInput; @@ -124,29 +122,6 @@ public TextBuffer(BufferRecycler allocator) { _allocator = allocator; } - // @since 2.10 - private TextBuffer(BufferRecycler allocator, char[] initialSegment) { - _allocator = allocator; - _currentSegment = initialSegment; - _currentSize = initialSegment.length; - _inputStart = -1; - } - - /** - * Factory method for constructing an instance with no allocator, and - * with initial full segment. - * - * @param initialSegment Initial, full segment to use for creating buffer (buffer - * {@link #size()} would return length of {@code initialSegment}) - * - * @return TextBuffer constructed - * - * @since 2.10 - */ - public static TextBuffer fromInitial(char[] initialSegment) { - return new TextBuffer(null, initialSegment); - } - /** * Method called to indicate that the underlying buffers should now * be recycled if they haven't yet been recycled. Although caller @@ -383,31 +358,6 @@ public char[] contentsAsArray() { return result; } - /** - * Convenience method for converting contents of the buffer - * into a {@link BigDecimal}. - * - * @return Buffered text value parsed as a {@link BigDecimal}, if possible - * - * @throws NumberFormatException if contents are not a valid Java number - */ - 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. @@ -476,51 +426,6 @@ public long contentsAsLong(boolean neg) { return NumberInput.parseLong(_currentSegment, 0, _currentSize); } - /** - * Accessor that will write buffered contents using given {@link Writer}. - * - * @param w Writer to use for writing out buffered content - * - * @return Number of characters written (same as {@link #size()}) - * - * @throws IOException If write using {@link Writer} parameter fails - * - * @since 2.8 - */ - public int contentsToWriter(Writer w) throws IOException { - if (_resultArray != null) { - w.write(_resultArray); - return _resultArray.length; - } - if (_resultString != null) { // Can take a shortcut... - w.write(_resultString); - return _resultString.length(); - } - // Do we use shared array? - if (_inputStart >= 0) { - final int len = _inputLen; - if (len > 0) { - w.write(_inputBuffer, _inputStart, len); - } - return len; - } - // nope, not shared - int total = 0; - if (_segments != null) { - for (char[] curr : _segments) { - int currLen = curr.length; - w.write(curr, 0, currLen); - total += currLen; - } - } - int len = _currentSize; - if (len > 0) { - w.write(_currentSegment, 0, len); - total += len; - } - return total; - } - /* * /********************************************************** * /* Public mutators: @@ -537,7 +442,7 @@ public void append(char c) { // Room in current segment? char[] curr = _currentSegment; if (_currentSize >= curr.length) { - expand(1); + expand(); curr = _currentSegment; } curr[_currentSize++] = c; @@ -569,7 +474,7 @@ public void append(char[] c, int start, int len) { // And then allocate new segment; we are guaranteed to now // have enough room in segment. do { - expand(len); + expand(); int amount = Math.min(_currentSegment.length, len); System.arraycopy(c, start, _currentSegment, 0, amount); _currentSize += amount; @@ -603,7 +508,7 @@ public void append(String str, int offset, int len) { // And then allocate new segment; we are guaranteed to now // have enough room in segment. do { - expand(len); + expand(); int amount = Math.min(_currentSegment.length, len); str.getChars(offset, offset + amount, _currentSegment, 0); _currentSize += amount; @@ -632,7 +537,7 @@ public char[] getCurrentSegment() { _currentSegment = buf(0); } else if (_currentSize >= curr.length) { // Plus, we better have room for at least one more char - expand(1); + expand(); } } return _currentSegment; @@ -781,7 +686,7 @@ private void unshare(int needExtra) { } // Method called when current segment is full, to allocate new segment. - private void expand(int minNewSegmentSize) { + private void expand() { // First, let's move current segment to segment list: if (_segments == null) { _segments = new ArrayList<>(); diff --git a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/VersionUtil.java b/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/VersionUtil.java deleted file mode 100644 index 15f21a9e9fd1..000000000000 --- a/sdk/serialization/azure-json/src/main/java/com/azure/json/implementation/jackson/core/util/VersionUtil.java +++ /dev/null @@ -1,177 +0,0 @@ -// Original file from https://github.com/FasterXML/jackson-core under Apache-2.0 license. -package com.azure.json.implementation.jackson.core.util; - -import java.io.*; -import java.util.Properties; -import java.util.regex.Pattern; - -import com.azure.json.implementation.jackson.core.Version; -import com.azure.json.implementation.jackson.core.Versioned; - -/** - * Functionality for supporting exposing of component {@link Version}s. - * Also contains other misc methods that have no other place to live in. - *

- * 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("[-_./;:]"); - - /* - * /********************************************************************** - * /* Instance life-cycle - * /********************************************************************** - */ - - protected VersionUtil() { - } - - @Deprecated // since 2.9 - public Version version() { - return Version.unknownVersion(); - } - - /* - * /********************************************************************** - * /* Static load methods - * /********************************************************************** - */ - - /** - * 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 "empty" {@link Version} - * returned by {@link Version#unknownVersion()}. - * - * @param cls Class for which to look version information - * - * @return Version information discovered if any; - * {@link Version#unknownVersion()} if none - */ - public static Version versionFor(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.getDeclaredConstructor().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; - } - - /** - * Alias of {@link #versionFor(Class)}. - * - * @param cls Class for which to look version information - * - * @return Version information discovered if any; - * {@link Version#unknownVersion()} if none - * - * @deprecated Since 2.12 simply use {@link #versionFor(Class)} instead - */ - @Deprecated - public static Version packageVersionFor(Class cls) { - return versionFor(cls); - } - - /** - * 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 PackageVersion classes to decode version injected by Maven build. - * - * @param s Version String to parse - * @param groupId Maven group id to include with version - * @param artifactId Maven artifact id to include with version - * - * @return Version instance constructed from parsed components, if successful; - * {@link Version#unknownVersion()} if parsing of components fail - */ - public static Version parseVersion(String s, String groupId, String artifactId) { - if (s != null && !(s = s.trim()).isEmpty()) { - 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 static void _close(Closeable c) { - try { - c.close(); - } catch (IOException e) { - } - } - - /* - * /********************************************************************** - * /* Orphan utility methods - * /********************************************************************** - */ - - public static void throwInternal() { - throw new RuntimeException("Internal error: this code path should never get executed"); - } -} diff --git a/sdk/serialization/azure-xml/spotbugs-exclude.xml b/sdk/serialization/azure-xml/spotbugs-exclude.xml index b533cae39afc..9c7043b87abe 100644 --- a/sdk/serialization/azure-xml/spotbugs-exclude.xml +++ b/sdk/serialization/azure-xml/spotbugs-exclude.xml @@ -34,7 +34,7 @@ - + @@ -45,7 +45,7 @@ - + @@ -54,7 +54,7 @@ - + diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/WFCException.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/WFCException.java deleted file mode 100644 index 8cf2288aed21..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/WFCException.java +++ /dev/null @@ -1,32 +0,0 @@ -// Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. -/* Woodstox Lite ("wool") XML processor - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in the file LICENSE which is - * included with the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.azure.xml.implementation.aalto; - -import javax.xml.stream.Location; - -import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; - -/** - * Base class for reader-side Well-Formedness Constraint violation - * (fatal error) exceptions. - */ -@SuppressWarnings("serial") -public class WFCException extends StreamExceptionBase { - public WFCException(String msg, Location loc) { - super(msg, loc); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/CommonConfig.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/CommonConfig.java index 9f91746e6527..c43842850cd6 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/CommonConfig.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/CommonConfig.java @@ -1,9 +1,7 @@ // Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. package com.azure.xml.implementation.aalto.impl; -import java.util.*; - -import com.azure.xml.implementation.stax2.XMLStreamProperties; +import java.util.HashMap; /** * Base class for reader and writer-side configuration/context objects @@ -29,6 +27,66 @@ public abstract class CommonConfig { */ protected final static String IMPL_VERSION = "0.9"; + // // // Information about implementation + + /** + * This read-only property returns name of the implementation. It + * can be used to determine implementation-specific feature sets, + * in case other methods (calling isPropertySupported) + * does not work adequately. + */ + protected static final String XSP_IMPLEMENTATION_NAME = "com.azure.xml.implementation.stax2.implName"; + + /** + * This read-only property returns the version of the implementation, + * and is to be used with implementation name + * ({@link #XSP_IMPLEMENTATION_NAME}) property. + */ + protected static final String XSP_IMPLEMENTATION_VERSION = "com.azure.xml.implementation.stax2.implVersion"; + + /** + * This read-only property indicates whether the implementation + * supports xml 1.1 content; Boolean.TRUE indicates it does, + * Boolean.FALSE that it does not. + */ + protected static final String XSP_SUPPORTS_XML11 = "com.azure.xml.implementation.stax2.supportsXml11"; + + // // // Re-declared properties from XMLInputFactory + + /** + * Property that can be set to indicate that namespace information is + * to be handled in conformance to the xml namespaces specifiation; or + * false to indicate no namespace handling should be done. + */ + protected static final String XSP_NAMESPACE_AWARE = "javax.xml.stream.isNamespaceAware"; + + /** + * Property that can be set to specify a problem handler which will get + * notified of non-fatal problem (validation errors in non-validating mode, + * warnings). Its value has to be of type + * {@link javax.xml.stream.XMLReporter} + */ + protected static final String XSP_PROBLEM_REPORTER = "javax.xml.stream.reporter"; + + // // // Generic XML feature support: + + /** + * Read/write property that can be set to change the level of xml:id + * specification support, if the implementation implements xml:id + * specification. + *

+ * Default value is implementation-specific, but recommended default + * value is XSP_V_XMLID_TYPING for implementations + * that do support Xml:id specification: those that do not, have to + * default to XSP_V_XMLID_NONE. + * For Xml:id-enabled implementations, typing support is the most + * logical default, since it + * provides the intuitive behavior of xml:id functionality, as well + * as reasonable performance (very little overhead in non-validating + * mode; usual id checking overhead for validating mode). + */ + protected static final String XSP_SUPPORT_XMLID = "com.azure.xml.implementation.stax2.supportXmlId"; + /* /********************************************************************** /* Internal constants @@ -48,14 +106,14 @@ public abstract class CommonConfig { final static HashMap sStdProperties = new HashMap<>(16); static { // Basic information about the implementation: - sStdProperties.put(XMLStreamProperties.XSP_IMPLEMENTATION_NAME, PROP_IMPL_NAME); - sStdProperties.put(XMLStreamProperties.XSP_IMPLEMENTATION_VERSION, PROP_IMPL_VERSION); + sStdProperties.put(XSP_IMPLEMENTATION_NAME, PROP_IMPL_NAME); + sStdProperties.put(XSP_IMPLEMENTATION_VERSION, PROP_IMPL_VERSION); // XML version support: - sStdProperties.put(XMLStreamProperties.XSP_SUPPORTS_XML11, PROP_SUPPORTS_XML11); + sStdProperties.put(XSP_SUPPORTS_XML11, PROP_SUPPORTS_XML11); // Xml:id support: - sStdProperties.put(XMLStreamProperties.XSP_SUPPORT_XMLID, PROP_SUPPORTS_XMLID); + sStdProperties.put(XSP_SUPPORT_XMLID, PROP_SUPPORTS_XMLID); /* 23-Apr-2008, tatus: Additional interoperability property, * one that Sun implementation uses. Can map tor Stax2 @@ -135,19 +193,6 @@ public boolean setProperty(String propName, Object value) { /********************************************************************** */ - /** - * This method returns name of encoding that has been passed - * explicitly to the reader or writer, from outside. An example - * is that HTTP server may pass encoding as declared in HTTP - * headers. This should either be null (if none passed), or the - * same as actual encoding (which is determined from physical - * stream contents [for readers], or from encoder - * properties / configuration [for writers] - * - * @return Encoding that has been passed externally by the application - */ - public abstract String getExternalEncoding(); - /** * @return Actual encoding in use, as determined by the processor. */ diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/ErrorConsts.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/ErrorConsts.java index 83b0609b8da2..2804355f88ce 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/ErrorConsts.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/ErrorConsts.java @@ -1,10 +1,20 @@ // Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. package com.azure.xml.implementation.aalto.impl; -import com.azure.xml.implementation.stax2.ri.Stax2Util; - import javax.xml.XMLConstants; +import static javax.xml.stream.XMLStreamConstants.CDATA; +import static javax.xml.stream.XMLStreamConstants.CHARACTERS; +import static javax.xml.stream.XMLStreamConstants.COMMENT; +import static javax.xml.stream.XMLStreamConstants.DTD; +import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT; +import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; +import static javax.xml.stream.XMLStreamConstants.ENTITY_REFERENCE; +import static javax.xml.stream.XMLStreamConstants.PROCESSING_INSTRUCTION; +import static javax.xml.stream.XMLStreamConstants.SPACE; +import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT; +import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; + /** * This class contains various String constants used for error reporting. *

@@ -82,17 +92,6 @@ public final class ErrorConsts { public static String WERR_NAME_EMPTY = "Illegal to pass empty name"; - // // // Warning-related: - - // // Types of warnings we issue via XMLReporter - - public static String WT_XML_DECL = "xml declaration"; - - // // Warning messages: - - public static String W_MIXED_ENCODINGS - = "Inconsistent text encoding; declared as \"{0}\" in xml declaration, application had passed \"{1}\""; - /* //////////////////////////////////////////////////// // Utility methods @@ -100,7 +99,41 @@ public final class ErrorConsts { */ public static String tokenTypeDesc(int type) { - return Stax2Util.eventTypeDesc(type); + switch (type) { + case START_ELEMENT: + return "START_ELEMENT"; + + case END_ELEMENT: + return "END_ELEMENT"; + + case START_DOCUMENT: + return "START_DOCUMENT"; + + case END_DOCUMENT: + return "END_DOCUMENT"; + + case CHARACTERS: + return "CHARACTERS"; + + case CDATA: + return "CDATA"; + + case SPACE: + return "SPACE"; + + case COMMENT: + return "COMMENT"; + + case PROCESSING_INSTRUCTION: + return "PROCESSING_INSTRUCTION"; + + case DTD: + return "DTD"; + + case ENTITY_REFERENCE: + return "ENTITY_REFERENCE"; + } + return "[" + type + "]"; } public static void throwInternalError() { diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/IoStreamException.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/IoStreamException.java deleted file mode 100644 index 2d800579c678..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/impl/IoStreamException.java +++ /dev/null @@ -1,19 +0,0 @@ -// Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. -package com.azure.xml.implementation.aalto.impl; - -import java.io.IOException; - -/** - * Simple wrapper for {@link IOException}s; needed when StAX does not expose - * underlying I/O exceptions via its methods. - */ -@SuppressWarnings("serial") -public class IoStreamException extends StreamExceptionBase { - public IoStreamException(IOException ie) { - super(ie); - } - - public IoStreamException(String msg) { - super(msg); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPName.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPName.java deleted file mode 100644 index 0fe9cf86979b..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPName.java +++ /dev/null @@ -1,78 +0,0 @@ -// Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. -/* Woodstox Lite ("wool") XML processor - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in the file LICENSE which is - * included with the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.azure.xml.implementation.aalto.in; - -/** - * This intermediate abstract class defines more specialized API needed - * by components like symbol tables, which need to provide efficient - * access to byte-based PNames. Byte-based names can be used to directly - * convert byte sequences to actual character-based names, without - * intervening byte-to-character decoding phase. - */ -public abstract class ByteBasedPName extends PName { - /** - * Since the hash is calculated different from the way eventual - * String's hash will be (bit faster, not significantly worse - * hashing uniformness), we need to store that hash here. - */ - protected final int mHash; - - protected ByteBasedPName(String pname, String prefix, String ln, int hash) { - super(pname, prefix, ln); - mHash = hash; - } - - /* - /********************************************************************** - /* Specialized comparators and accessors - /********************************************************************** - */ - - // From base class: - - @Override - public abstract int getQuad(int index); - - @Override - public abstract int sizeInQuads(); - - // additional ones: - - public abstract boolean equals(int quad1, int quad2); - - public abstract boolean equals(int[] quads, int qlen); - - public abstract boolean hashEquals(int h, int quad1, int quad2); - - public abstract boolean hashEquals(int h, int[] quads, int qlen); - - /* - /********************************************************************** - /* Overridden standard methods - /********************************************************************** - */ - - /** - * Whether we should use internal hash, or the hash of prefixed - * name string itself is an open question. For now, let's use - * former. - */ - @Override - public int hashCode() { - return mHash; - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameFactory.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameFactory.java index 04de08270a77..768c5c5f9bf7 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameFactory.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameFactory.java @@ -23,11 +23,6 @@ * to know details of concrete implementations. */ public final class ByteBasedPNameFactory { - /** - * Can be set to false for debugging (for example, to test memory - * usage) - */ - private final static boolean DO_INTERN = true; /* /********************************************************************** @@ -50,12 +45,10 @@ public static ByteBasedPNameFactory getInstance() { /********************************************************************** */ - public ByteBasedPName constructPName(int hash, String pname, int colonIx, int[] quads, int qlen) { + public PName constructPName(int hash, String pname, int colonIx, int[] quads, int qlen) { if (qlen < 4) { // Need to check for 3 quad one, can do others too if (colonIx < 0) { // no prefix - if (DO_INTERN) { - pname = pname.intern(); - } + pname = pname.intern(); if (qlen == 3) { return new PName3(pname, null, pname, hash, quads); } else if (qlen == 2) { @@ -65,10 +58,8 @@ public ByteBasedPName constructPName(int hash, String pname, int colonIx, int[] } String prefix = pname.substring(0, colonIx); String ln = pname.substring(colonIx + 1); - if (DO_INTERN) { - ln = ln.intern(); - prefix = prefix.intern(); - } + ln = ln.intern(); + prefix = prefix.intern(); if (qlen == 3) { return new PName3(pname, prefix, ln, hash, quads); } else if (qlen == 2) { @@ -80,9 +71,7 @@ public ByteBasedPName constructPName(int hash, String pname, int colonIx, int[] int[] buf = new int[qlen]; System.arraycopy(quads, 0, buf, 0, qlen); if (colonIx < 0) { // no prefix, simpler - if (DO_INTERN) { - pname = pname.intern(); - } + pname = pname.intern(); return new PNameN(pname, null, pname, hash, buf, qlen); } /* !!! TODO: cache prefix intern() calls, since they are bound @@ -90,10 +79,8 @@ public ByteBasedPName constructPName(int hash, String pname, int colonIx, int[] */ String prefix = pname.substring(0, colonIx); String ln = pname.substring(colonIx + 1); - if (DO_INTERN) { - ln = ln.intern(); - prefix = prefix.intern(); - } + ln = ln.intern(); + prefix = prefix.intern(); return new PNameN(pname, prefix, ln, hash, buf, qlen); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameTable.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameTable.java index 7d42e1528764..5a2383ac278b 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameTable.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedPNameTable.java @@ -20,9 +20,9 @@ /** * This is a symbol table implementation used for storing byte-based - * PNames, specifically, instances of ({@link ByteBasedPName}). + * PNames, specifically, instances of ({@link PName}). */ -public final class ByteBasedPNameTable extends NameTable { +public final class ByteBasedPNameTable implements NameTable { final static int MIN_HASH_SIZE = 16; final static int INITIAL_COLLISION_LEN = 32; @@ -69,7 +69,7 @@ public final class ByteBasedPNameTable extends NameTable { * entries in mMainHash. Contains nulls for unused * entries. */ - private ByteBasedPName[] mMainNames; + private PName[] mMainNames; // // // Then the collision/spill-over area info @@ -163,7 +163,7 @@ public ByteBasedPNameTable(int hashSize) { mMainNamesShared = false; mMainHashMask = hashSize - 1; mMainHash = new int[hashSize]; - mMainNames = new ByteBasedPName[hashSize]; + mMainNames = new PName[hashSize]; mCollListShared = true; // just since it'll need to be allocated mCollList = null; @@ -258,7 +258,7 @@ public boolean maybeDirty() { * @return PName matching the symbol passed (or constructed for * it) */ - public ByteBasedPName findSymbol(int hash, int firstQuad, int secondQuad) { + public PName findSymbol(int hash, int firstQuad, int secondQuad) { int ix = (hash & mMainHashMask); int val = mMainHash[ix]; @@ -268,7 +268,7 @@ public ByteBasedPName findSymbol(int hash, int firstQuad, int secondQuad) { */ if ((((val >> 8) ^ hash) << 8) == 0) { // match // Ok, but do we have an actual match? - ByteBasedPName pname = mMainNames[ix]; + PName pname = mMainNames[ix]; if (pname == null) { // main slot empty; can't find return null; } @@ -309,7 +309,7 @@ public ByteBasedPName findSymbol(int hash, int firstQuad, int secondQuad) { * @return PName matching the symbol passed (or constructed for * it) */ - public ByteBasedPName findSymbol(int hash, int[] quads, int qlen) { + public PName findSymbol(int hash, int[] quads, int qlen) { if (qlen < 3) { // another sanity check return findSymbol(hash, quads[0], (qlen < 2) ? 0 : quads[1]); } @@ -317,7 +317,7 @@ public ByteBasedPName findSymbol(int hash, int[] quads, int qlen) { int ix = (hash & mMainHashMask); int val = mMainHash[ix]; if ((((val >> 8) ^ hash) << 8) == 0) { - ByteBasedPName pname = mMainNames[ix]; + PName pname = mMainNames[ix]; if (pname == null) { // main slot empty; no collision list then either return null; } @@ -344,9 +344,8 @@ public ByteBasedPName findSymbol(int hash, int[] quads, int qlen) { /********************************************************************** */ - public ByteBasedPName addSymbol(int hash, String symbolStr, int colonIx, int[] quads, int qlen) { - ByteBasedPName symbol - = ByteBasedPNameFactory.getInstance().constructPName(hash, symbolStr, colonIx, quads, qlen); + public PName addSymbol(int hash, String symbolStr, int colonIx, int[] quads, int qlen) { + PName symbol = ByteBasedPNameFactory.getInstance().constructPName(hash, symbolStr, colonIx, quads, qlen); doAddSymbol(hash, symbol); return symbol; } @@ -430,7 +429,7 @@ public String toString() { /********************************************************************** */ - private void doAddSymbol(int hash, ByteBasedPName symbol) { + private void doAddSymbol(int hash, PName symbol) { if (mMainHashShared) { // always have to modify main entry unshareMain(); } @@ -516,10 +515,10 @@ private void rehash() { int len = oldMainHash.length; mMainHash = new int[len + len]; mMainHashMask = (len + len - 1); - ByteBasedPName[] oldNames = mMainNames; - mMainNames = new ByteBasedPName[len + len]; + PName[] oldNames = mMainNames; + mMainNames = new PName[len + len]; for (int i = 0; i < len; ++i) { - ByteBasedPName symbol = oldNames[i]; + PName symbol = oldNames[i]; if (symbol != null) { ++symbolsSeen; int hash = symbol.hashCode(); @@ -547,7 +546,7 @@ private void rehash() { for (int i = 0; i < oldEnd; ++i) { for (Bucket curr = oldBuckets[i]; curr != null; curr = curr.mNext) { ++symbolsSeen; - ByteBasedPName symbol = curr.mName; + PName symbol = curr.mName; int hash = symbol.hashCode(); int ix = (hash & mMainHashMask); int val = mMainHash[ix]; @@ -635,9 +634,9 @@ private void unshareCollision() { } private void unshareNames() { - ByteBasedPName[] old = mMainNames; + PName[] old = mMainNames; int len = old.length; - mMainNames = new ByteBasedPName[len]; + mMainNames = new PName[len]; System.arraycopy(old, 0, mMainNames, 0, len); mMainNamesShared = false; } @@ -656,10 +655,10 @@ private void expandCollision() { */ final static class Bucket { - final ByteBasedPName mName; + final PName mName; final Bucket mNext; - Bucket(ByteBasedPName name, Bucket next) { + Bucket(PName name, Bucket next) { mName = name; mNext = next; } @@ -672,12 +671,12 @@ public int length() { return len; } - public ByteBasedPName find(int hash, int firstQuad, int secondQuad) { + public PName find(int hash, int firstQuad, int secondQuad) { if (mName.hashEquals(hash, firstQuad, secondQuad)) { return mName; } for (Bucket curr = mNext; curr != null; curr = curr.mNext) { - ByteBasedPName currName = curr.mName; + PName currName = curr.mName; if (currName.hashEquals(hash, firstQuad, secondQuad)) { return currName; } @@ -685,12 +684,12 @@ public ByteBasedPName find(int hash, int firstQuad, int secondQuad) { return null; } - public ByteBasedPName find(int hash, int[] quads, int qlen) { + public PName find(int hash, int[] quads, int qlen) { if (mName.hashEquals(hash, quads, qlen)) { return mName; } for (Bucket curr = mNext; curr != null; curr = curr.mNext) { - ByteBasedPName currName = curr.mName; + PName currName = curr.mName; if (currName.hashEquals(hash, quads, qlen)) { return currName; } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedScanner.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedScanner.java deleted file mode 100644 index 456cafbd5572..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteBasedScanner.java +++ /dev/null @@ -1,410 +0,0 @@ -// Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. -/* Aalto XML processor - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in the file LICENSE which is - * included with the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.azure.xml.implementation.aalto.in; - -import java.io.IOException; - -import javax.xml.stream.Location; -import javax.xml.stream.XMLStreamException; - -import com.azure.xml.implementation.aalto.impl.LocationImpl; -import com.azure.xml.implementation.aalto.util.DataUtil; -import com.azure.xml.implementation.aalto.util.XmlCharTypes; -import com.azure.xml.implementation.aalto.util.XmlChars; - -/** - * Intermediate base class used by different byte-backed scanners. - * Specifically, used as a base by both blocking (stream) and - * non-blocking (async) byte-based scanners (as opposed to Reader-backed, - * character-based scanners) - */ -public abstract class ByteBasedScanner extends XmlScanner { - /* - /********************************************************************** - /* Byte constants - /********************************************************************** - */ - - // White-space: - - final protected static byte BYTE_SPACE = (byte) ' '; - final protected static byte BYTE_LF = (byte) '\n'; - final protected static byte BYTE_CR = (byte) '\r'; - final protected static byte BYTE_TAB = (byte) 9; - - final protected static byte BYTE_LT = (byte) '<'; - final protected static byte BYTE_GT = (byte) '>'; - final protected static byte BYTE_AMP = (byte) '&'; - final protected static byte BYTE_HASH = (byte) '#'; - final protected static byte BYTE_EXCL = (byte) '!'; - final protected static byte BYTE_HYPHEN = (byte) '-'; - final protected static byte BYTE_QMARK = (byte) '?'; - final protected static byte BYTE_SLASH = (byte) '/'; - final protected static byte BYTE_LBRACKET = (byte) '['; - final protected static byte BYTE_RBRACKET = (byte) ']'; - final protected static byte BYTE_SEMICOLON = (byte) ';'; - - final protected static byte BYTE_a = (byte) 'a'; - final protected static byte BYTE_g = (byte) 'g'; - final protected static byte BYTE_l = (byte) 'l'; - final protected static byte BYTE_m = (byte) 'm'; - final protected static byte BYTE_o = (byte) 'o'; - final protected static byte BYTE_p = (byte) 'p'; - final protected static byte BYTE_q = (byte) 'q'; - final protected static byte BYTE_s = (byte) 's'; - final protected static byte BYTE_t = (byte) 't'; - final protected static byte BYTE_u = (byte) 'u'; - final protected static byte BYTE_x = (byte) 'x'; - - final protected static byte BYTE_D = (byte) 'D'; - final protected static byte BYTE_P = (byte) 'P'; - final protected static byte BYTE_S = (byte) 'S'; - - /* - /********************************************************************** - /* Input buffering - /********************************************************************** - */ - - /** - * Pointer to the next unread byte in the input buffer. - */ - protected int _inputPtr; - - /** - * Pointer to the first byte after the end of valid content. - * This may point beyond of the physical buffer array. - */ - protected int _inputEnd; - - /* - /********************************************************************** - /* Parsing state - /********************************************************************** - */ - - /** - * Storage location for a single character that can not be easily - * pushed back (for example, multi-byte char; or char entity - * expansion). Negative, if from entity expansion; positive if - * a singular char. - */ - protected int _tmpChar = INT_NULL; - - /* - /********************************************************************** - /* Life-cycle - /********************************************************************** - */ - - protected ByteBasedScanner(ReaderConfig cfg) { - super(cfg); - _pastBytesOrChars = 0; // should it be passed by caller? - _rowStartOffset = 0; // should probably be passed by caller... - } - - // @Override protected abstract void _releaseBuffers(); - - @Override - protected abstract void _closeSource() throws IOException; - - /* - /********************************************************************** - /* Location handling - /********************************************************************** - */ - - @Override - public Location getCurrentLocation() { - return LocationImpl.fromZeroBased(_pastBytesOrChars + _inputPtr, _currRow, _inputPtr - _rowStartOffset); - } - - protected final void markLF(int offset) { - _rowStartOffset = offset; - ++_currRow; - } - - protected final void markLF() { - _rowStartOffset = _inputPtr; - ++_currRow; - } - - protected final void setStartLocation() { - _startRawOffset = _pastBytesOrChars + _inputPtr; - _startRow = _currRow; - _startColumn = _inputPtr - _rowStartOffset; - } - - /* - /********************************************************************** - /* Abstract methods for sub-classes to implement - /********************************************************************** - */ - - /** - * Method called by methods when encountering a byte that - * can not be part of a valid character in the current context. - * Should return the actual decoded character for error reporting - * purposes. - */ - protected abstract int decodeCharForError(byte b) throws XMLStreamException; - - /* - /********************************************************************** - /* And then shared functionality for sub-classes - /********************************************************************** - */ - - /** - * Conceptually, this method really does NOT belong here. However, - * currently it is quite hard to refactor it, so it'll have to - * stay here until better place is found - */ - protected final PName addUTFPName(ByteBasedPNameTable symbols, XmlCharTypes charTypes, int hash, int[] quads, - int qlen, int lastQuadBytes) throws XMLStreamException { - // 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; - } - - // Let's handle first char separately (different validation): - int ch = (quads[0] >>> 24); - boolean ok; - int ix = 1; - char[] cbuf = _nameBuffer; - int cix = 0; - final int[] TYPES = charTypes.NAME_CHARS; - - switch (TYPES[ch]) { - case XmlCharTypes.CT_NAME_NONE: - case XmlCharTypes.CT_NAME_COLON: // not ok as first - case XmlCharTypes.CT_NAME_NONFIRST: - case InputCharTypes.CT_INPUT_NAME_MB_N: - ok = false; - break; - - case XmlCharTypes.CT_NAME_ANY: - ok = true; - break; - - default: // multi-byte (UTF-8) chars: - { - 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) { - reportEofInName(); - } - ix += needed; - - int q = quads[0]; - // Always need at least one more right away: - int ch2 = (q >> 16) & 0xFF; - if ((ch2 & 0xC0) != 0x080) { - reportInvalidOther(ch2); - } - ch = (ch << 6) | (ch2 & 0x3F); - - /* And then may need more. Note: here we do not do all the - * checks that UTF-8 text decoder might do. Reason is that - * name validity checking methods handle most of such checks - */ - if (needed > 1) { - ch2 = (q >> 8) & 0xFF; - if ((ch2 & 0xC0) != 0x080) { - reportInvalidOther(ch2); - } - ch = (ch << 6) | (ch2 & 0x3F); - if (needed > 2) { // 4 bytes? (need surrogates on output) - ch2 = q & 0xFF; - if ((ch2 & 0xC0) != 0x080) { - reportInvalidOther(ch2 & 0xFF); - } - ch = (ch << 6) | (ch2 & 0x3F); - } - } - ok = XmlChars.is10NameStartChar(ch); - if (needed > 2) { // outside of basic 16-bit range? need surrogates - /* so, let's first output first char (high surrogate), - * let second be output by later code - */ - ch -= 0x10000; // to normalize it starting with 0x0 - cbuf[cix++] = (char) (0xD800 + (ch >> 10)); - ch = (0xDC00 | (ch & 0x03FF)); - } - } - } - - if (!ok) { // 0 to indicate it's first char, even with surrogates - reportInvalidNameChar(ch, 0); - } - - cbuf[cix++] = (char) ch; // the only char, or second (low) surrogate - - /* Whoa! Tons of code for just the start char. But now we get to - * decode the name proper, at last! - */ - int last_colon = -1; - - while (ix < byteLen) { - ch = quads[ix >> 2]; // current quad, need to shift+mask - int byteIx = (ix & 3); - ch = (ch >> ((3 - byteIx) << 3)) & 0xFF; - ++ix; - - // Ascii? - switch (TYPES[ch]) { - case XmlCharTypes.CT_NAME_NONE: - case XmlCharTypes.CT_MULTIBYTE_N: - ok = false; - break; - - case XmlCharTypes.CT_NAME_COLON: // not ok as first - if (last_colon >= 0) { - reportMultipleColonsInName(); - } - last_colon = cix; - ok = true; - break; - - case XmlCharTypes.CT_NAME_NONFIRST: - case XmlCharTypes.CT_NAME_ANY: - ok = true; - break; - - default: { - 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) { - reportEofInName(); - } - - // 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); - - // Once again, some of validation deferred to name char validator - 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); - } - } - ok = XmlChars.is10NameChar(ch); - 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) { - _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); - } - cbuf[cix++] = (char) (0xD800 + (ch >> 10)); - ch = 0xDC00 | (ch & 0x03FF); - } - } - } - if (!ok) { - reportInvalidNameChar(ch, cix); - } - if (cix >= cbuf.length) { - _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); - } - cbuf[cix++] = (char) ch; - } - - /* Ok. Now we have the character array, and can construct the - * String (as well as check proper composition of semicolons - * for ns-aware mode...) - */ - String baseName = new String(cbuf, 0, cix); - // And finally, unalign if necessary - if (lastQuadBytes < 4) { - quads[qlen - 1] = lastQuad; - } - return symbols.addSymbol(hash, baseName, last_colon, quads, qlen); - } - - /* - /********************************************************************** - /* Error reporting - /********************************************************************** - */ - - protected void reportInvalidInitial(int mask) throws XMLStreamException { - reportInputProblem("Invalid UTF-8 start byte 0x" + Integer.toHexString(mask)); - } - - protected void reportInvalidOther(int mask) throws XMLStreamException { - reportInputProblem("Invalid UTF-8 middle byte 0x" + Integer.toHexString(mask)); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteSourceBootstrapper.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteSourceBootstrapper.java index d3f6241a59b0..058d242b7815 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteSourceBootstrapper.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ByteSourceBootstrapper.java @@ -16,14 +16,19 @@ package com.azure.xml.implementation.aalto.in; -import java.io.*; +import com.azure.xml.implementation.aalto.impl.LocationImpl; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; +import com.azure.xml.implementation.aalto.util.CharsetNames; +import com.azure.xml.implementation.aalto.util.XmlConsts; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamException; - -import com.azure.xml.implementation.aalto.impl.IoStreamException; -import com.azure.xml.implementation.aalto.impl.LocationImpl; -import com.azure.xml.implementation.aalto.util.CharsetNames; +import java.io.CharConversionException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; /** * Class that takes care of bootstrapping main document input from @@ -108,7 +113,7 @@ public XmlScanner bootstrap() throws XMLStreamException { try { return doBootstrap(); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } finally { _config.freeSmallCBuffer(mKeyword); } @@ -151,7 +156,7 @@ public XmlScanner doBootstrap() throws IOException, XMLStreamException { if (normEnc.equals(CharsetNames.CS_UTF8) || normEnc.equals(CharsetNames.CS_ISO_LATIN1) || normEnc.equals(CharsetNames.CS_US_ASCII)) { - return new Utf8Scanner(_config, _in, _inputBuffer, _inputPtr, _inputLen); + return new StreamScanner(_config, _in, _inputBuffer, _inputPtr, _inputLen); } else if (normEnc.startsWith(CharsetNames.CS_UTF32)) { // Since this is such a rare encoding, we'll just create // a Reader, and dispatch it to reader scanner? @@ -173,7 +178,7 @@ public XmlScanner doBootstrap() throws IOException, XMLStreamException { try { return new ReaderScanner(_config, new InputStreamReader(in, normEnc)); } catch (UnsupportedEncodingException usex) { - throw new IoStreamException("Unsupported encoding: " + usex.getMessage()); + throw new StreamExceptionBase("Unsupported encoding: " + usex.getMessage()); } } @@ -319,7 +324,7 @@ private boolean hasXmlDeclaration() throws IOException, XMLStreamException { && _inputBuffer[_inputPtr + 2] == 'x' && _inputBuffer[_inputPtr + 3] == 'm' && _inputBuffer[_inputPtr + 4] == 'l' - && ((_inputBuffer[_inputPtr + 5] & 0xFF) <= CHAR_SPACE)) { + && ((_inputBuffer[_inputPtr + 5] & 0xFF) <= XmlConsts.CHAR_SPACE)) { // Let's skip stuff so far: _inputPtr += 6; @@ -334,7 +339,7 @@ && nextMultiByte() == '?' && nextMultiByte() == 'x' && nextMultiByte() == 'm' && nextMultiByte() == 'l' - && nextMultiByte() <= CHAR_SPACE) { + && nextMultiByte() <= XmlConsts.CHAR_SPACE) { return true; } _inputPtr = start; // push data back @@ -479,9 +484,9 @@ protected int readQuotedValue(char[] kw, int quoteChar) throws IOException, XMLS if (mb) { c = nextMultiByte(); - if (c == CHAR_CR || c == CHAR_LF) { + if (c == XmlConsts.CHAR_CR || c == XmlConsts.CHAR_LF) { skipMbLF(c); - c = CHAR_LF; + c = XmlConsts.CHAR_LF; } } else { byte b = (_inputPtr < _inputLen) ? _inputBuffer[_inputPtr++] : nextByte(); @@ -541,7 +546,7 @@ private void skipSbWs() throws IOException, XMLStreamException { while (true) { byte b = (_inputPtr < _inputLen) ? _inputBuffer[_inputPtr++] : nextByte(); - if ((b & 0xFF) > CHAR_SPACE) { + if ((b & 0xFF) > XmlConsts.CHAR_SPACE) { --_inputPtr; break; } @@ -582,7 +587,7 @@ private int checkSbKeyword(String expected) throws IOException, XMLStreamExcepti } } - return CHAR_NULL; + return XmlConsts.CHAR_NULL; } /* @@ -626,22 +631,22 @@ private void skipMbWs() throws IOException, XMLStreamException { while (true) { int c = nextMultiByte(); - if (c > CHAR_SPACE) { + if (c > XmlConsts.CHAR_SPACE) { _inputPtr -= mBytesPerChar; break; } - if (c == CHAR_CR || c == CHAR_LF) { + if (c == XmlConsts.CHAR_CR || c == XmlConsts.CHAR_LF) { skipMbLF(c); - } else if (c == CHAR_NULL) { + } else if (c == XmlConsts.CHAR_NULL) { reportNull(); } } } private void skipMbLF(int lf) throws IOException, XMLStreamException { - if (lf == CHAR_CR) { + if (lf == XmlConsts.CHAR_CR) { int c = nextMultiByte(); - if (c != CHAR_LF) { + if (c != XmlConsts.CHAR_LF) { _inputPtr -= mBytesPerChar; } } @@ -666,7 +671,7 @@ private int checkMbKeyword(String expected) throws IOException, XMLStreamExcepti } } - return CHAR_NULL; + return XmlConsts.CHAR_NULL; } /* diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharBasedPNameTable.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharBasedPNameTable.java index e67a918bde57..8d94fc51cc06 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharBasedPNameTable.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharBasedPNameTable.java @@ -23,7 +23,7 @@ * PNames, specifically, instances of * ({@link PNameC}). */ -public class CharBasedPNameTable extends NameTable { +public class CharBasedPNameTable implements NameTable { final static int MIN_HASH_SIZE = 16; /* @@ -338,7 +338,7 @@ private void rehash() { * This class is a symbol table entry. Each entry acts as a node * in a linked list. */ - final static class Bucket { + protected final static class Bucket { private final PNameC mSymbol; private final Bucket mNext; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharSourceBootstrapper.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharSourceBootstrapper.java index 29a5c2218bea..a69fd4358cf4 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharSourceBootstrapper.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/CharSourceBootstrapper.java @@ -16,17 +16,14 @@ package com.azure.xml.implementation.aalto.in; -import java.io.*; -import java.text.MessageFormat; +import com.azure.xml.implementation.aalto.impl.LocationImpl; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; +import com.azure.xml.implementation.aalto.util.XmlConsts; import javax.xml.stream.Location; -import javax.xml.stream.XMLReporter; import javax.xml.stream.XMLStreamException; - -import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.impl.IoStreamException; -import com.azure.xml.implementation.aalto.impl.LocationImpl; -import com.azure.xml.implementation.aalto.util.CharsetNames; +import java.io.IOException; +import java.io.Reader; /** * Class that takes care of bootstrapping main document input from @@ -98,7 +95,7 @@ public XmlScanner bootstrap() throws XMLStreamException { try { return doBootstrap(); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } finally { _config.freeSmallCBuffer(mKeyword); } @@ -134,7 +131,7 @@ public XmlScanner doBootstrap() throws IOException, XMLStreamException { readXmlDeclaration(); if (mFoundEncoding != null) { - normEnc = verifyXmlEncoding(mFoundEncoding); + normEnc = mFoundEncoding; } } } else { @@ -150,7 +147,7 @@ public XmlScanner doBootstrap() throws IOException, XMLStreamException { * inform about the problem right away. */ if (c == 0xEF) { - throw new IoStreamException( + throw new StreamExceptionBase( "Unexpected first character (char code 0xEF), not valid in xml document: could be mangled UTF-8 BOM marker. Make sure that the Reader uses correct encoding or pass an InputStream instead"); } } @@ -160,33 +157,6 @@ public XmlScanner doBootstrap() throws IOException, XMLStreamException { return new ReaderScanner(_config, _in, _inputBuffer, _inputPtr, _inputLast); } - /* - //////////////////////////////////////////////////// - // Internal methods, main xml decl processing - //////////////////////////////////////////////////// - */ - - /** - * @return Normalized encoding name - */ - private String verifyXmlEncoding(String enc) throws XMLStreamException { - String charset = CharsetNames.normalize(enc); - - // Probably no point in comparing at all... is there? - // But we can report a possible problem? - String extEnc = _config.getExternalEncoding(); - if (extEnc != null && charset != null && !extEnc.equalsIgnoreCase(charset)) { - XMLReporter rep = _config.getXMLReporter(); - if (rep != null) { - Location loc = getLocation(); - rep.report(MessageFormat.format(ErrorConsts.W_MIXED_ENCODINGS, extEnc, enc), ErrorConsts.WT_XML_DECL, - this, loc); - } - } - - return enc; - } - /* ///////////////////////////////////////////////////// // Internal methods, loading input data @@ -251,12 +221,12 @@ protected int getNextAfterWs() throws IOException, XMLStreamException { while (true) { char c = (_inputPtr < _inputLast) ? _inputBuffer[_inputPtr++] : nextChar(); - if (c > CHAR_SPACE) { + if (c > XmlConsts.CHAR_SPACE) { return c; } - if (c == CHAR_CR || c == CHAR_LF) { + if (c == XmlConsts.CHAR_CR || c == XmlConsts.CHAR_LF) { skipCRLF(c); - } else if (c == CHAR_NULL) { + } else if (c == XmlConsts.CHAR_NULL) { reportNull(); } } @@ -276,12 +246,12 @@ protected int checkKeyword(String exp) throws IOException, XMLStreamException { if (c != exp.charAt(ptr)) { return c; } - if (c == CHAR_NULL) { + if (c == XmlConsts.CHAR_NULL) { reportNull(); } } - return CHAR_NULL; + return XmlConsts.CHAR_NULL; } @Override @@ -291,9 +261,9 @@ protected int readQuotedValue(char[] kw, int quoteChar) throws IOException, XMLS while (true) { char c = (_inputPtr < _inputLast) ? _inputBuffer[_inputPtr++] : nextChar(); - if (c == CHAR_CR || c == CHAR_LF) { + if (c == XmlConsts.CHAR_CR || c == XmlConsts.CHAR_LF) { skipCRLF(c); - } else if (c == CHAR_NULL) { + } else if (c == XmlConsts.CHAR_NULL) { reportNull(); } if (c == quoteChar) { diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/InputBootstrapper.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/InputBootstrapper.java index 9a1c13a07311..33dc5b57a286 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/InputBootstrapper.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/InputBootstrapper.java @@ -16,19 +16,18 @@ package com.azure.xml.implementation.aalto.in; -import java.io.*; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; +import com.azure.xml.implementation.aalto.util.XmlConsts; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamException; - -import com.azure.xml.implementation.aalto.WFCException; -import com.azure.xml.implementation.aalto.util.XmlConsts; +import java.io.IOException; /** * Abstract base class that defines shared functionality between different * bootstrappers (byte stream, char Readers, block input) */ -public abstract class InputBootstrapper implements XmlConsts { +public abstract class InputBootstrapper { /* /********************************************************************** /* Shared string consts @@ -182,7 +181,7 @@ protected void readXmlDeclaration() throws IOException, XMLStreamException { */ private int readXmlVersion() throws IOException, XMLStreamException { int c = checkKeyword(XmlConsts.XML_DECL_KW_VERSION); - if (c != CHAR_NULL) { + if (c != XmlConsts.CHAR_NULL) { reportUnexpectedChar(c, XmlConsts.XML_DECL_KW_VERSION); } c = handleEq(XmlConsts.XML_DECL_KW_VERSION); @@ -216,7 +215,7 @@ private int readXmlVersion() throws IOException, XMLStreamException { private String readXmlEncoding() throws IOException, XMLStreamException { int c = checkKeyword(XmlConsts.XML_DECL_KW_ENCODING); - if (c != CHAR_NULL) { + if (c != XmlConsts.CHAR_NULL) { reportUnexpectedChar(c, XmlConsts.XML_DECL_KW_ENCODING); } c = handleEq(XmlConsts.XML_DECL_KW_ENCODING); @@ -238,7 +237,7 @@ private String readXmlEncoding() throws IOException, XMLStreamException { private String readXmlStandalone() throws IOException, XMLStreamException { int c = checkKeyword(XmlConsts.XML_DECL_KW_STANDALONE); - if (c != CHAR_NULL) { + if (c != XmlConsts.CHAR_NULL) { reportUnexpectedChar(c, XmlConsts.XML_DECL_KW_STANDALONE); } c = handleEq(XmlConsts.XML_DECL_KW_STANDALONE); @@ -331,7 +330,7 @@ private int getWsOrChar() throws IOException, XMLStreamException { */ protected void reportXmlProblem(String msg) throws XMLStreamException { - throw new WFCException(msg, getLocation()); + throw new StreamExceptionBase(msg, getLocation()); } protected void reportNull() throws XMLStreamException { diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/NsBinding.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/NsBinding.java index 49c95a18327b..8da25b00dd5c 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/NsBinding.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/NsBinding.java @@ -25,7 +25,7 @@ * binding by URI being null). It is often included in * {@link PName} object. */ -final class NsBinding { +public final class NsBinding { // // // Couple of immutable bindings: /** diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName.java index ef61411718f1..092ac26ac8e3 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName.java @@ -36,16 +36,24 @@ public abstract class PName { */ protected NsBinding _namespaceBinding = null; + /** + * Since the hash is calculated different from the way eventual + * String's hash will be (bit faster, not significantly worse + * hashing uniformness), we need to store that hash here. + */ + protected final int mHash; + /* /********************************************************************** /* Life-cycle /********************************************************************** */ - protected PName(String pname, String prefix, String ln) { + protected PName(String pname, String prefix, String ln, int hash) { _prefixedName = pname; _prefix = prefix; _localName = ln; + mHash = hash; } public abstract PName createBoundName(NsBinding nsb); @@ -174,9 +182,14 @@ public final String toString() { return _prefixedName; } + /** + * Whether we should use internal hash, or the hash of prefixed + * name string itself is an open question. For now, let's use + * former. + */ @Override public int hashCode() { - return _prefixedName.hashCode(); + return mHash; } @Override @@ -210,4 +223,11 @@ public final boolean equals(Object o) { public abstract int getQuad(int index); + public abstract boolean equals(int quad1, int quad2); + + public abstract boolean equals(int[] quads, int qlen); + + public abstract boolean hashEquals(int h, int quad1, int quad2); + + public abstract boolean hashEquals(int h, int[] quads, int qlen); } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName1.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName1.java index 5a94c7df0193..92c57569949b 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName1.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName1.java @@ -25,7 +25,7 @@ * and to a lesser degree performance. Both are achieved for short * Strings by avoiding another level of indirection (via quad arrays) */ -public final class PName1 extends ByteBasedPName { +public final class PName1 extends PName { final int mQuad; public PName1(String pname, String prefix, String ln, int hash, int quad) { diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName2.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName2.java index ab73def8cb02..f86c7a59f624 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName2.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName2.java @@ -25,7 +25,7 @@ * and to a lesser degree performance. Both are achieved for short * Strings by avoiding another level of indirection (via quad arrays) */ -public final class PName2 extends ByteBasedPName { +public final class PName2 extends PName { final int mQuad1; final int mQuad2; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName3.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName3.java index 6031cd35c826..068316e5238f 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName3.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PName3.java @@ -10,7 +10,7 @@ * and to a lesser degree performance. Both are achieved for short * Strings by avoiding another level of indirection (via quad arrays) */ -public final class PName3 extends ByteBasedPName { +public final class PName3 extends PName { final int mQuad1; final int mQuad2; final int mQuad3; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameC.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameC.java index 9af4ce5b79b0..f59c79cf3514 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameC.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameC.java @@ -27,16 +27,8 @@ * work as expected. As such, these should only be used as temporary names. */ public final class PNameC extends PName { - /** - * Since the hash may be calculated different from the way eventual - * String's hash will be (right now it is not), we better store - * "our" hash here. - */ - private final int mHash; - public PNameC(String pname, String prefix, String ln, int hash) { - super(pname, prefix, ln); - mHash = hash; + super(pname, prefix, ln, hash); } @Override @@ -119,19 +111,23 @@ public int getQuad(int index) { return 0; // never gets here } - /* - ////////////////////////////////////////////////////////// - // Redefined standard methods - ////////////////////////////////////////////////////////// - */ + @Override + public boolean equals(int quad1, int quad2) { + return false; + } - /** - * Whether we should use internal hash, or the hash of prefixed - * name string itself is an open question. For now, let's use - * former. - */ @Override - public int hashCode() { - return mHash; + public boolean equals(int[] quads, int qlen) { + return false; + } + + @Override + public boolean hashEquals(int h, int quad1, int quad2) { + return false; + } + + @Override + public boolean hashEquals(int h, int[] quads, int qlen) { + return false; } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameN.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameN.java index c567b0949d07..154d2925b5bf 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameN.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/PNameN.java @@ -24,7 +24,7 @@ * and to a lesser degree performance. Both are achieved for short * Strings by avoiding another level of indirection (via quad arrays) */ -public final class PNameN extends ByteBasedPName { +public final class PNameN extends PName { final int[] mQuads; final int mQuadLen; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderConfig.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderConfig.java index ff936f143f30..161c5650754c 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderConfig.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderConfig.java @@ -2,12 +2,12 @@ package com.azure.xml.implementation.aalto.in; import com.azure.xml.implementation.aalto.impl.CommonConfig; +import com.azure.xml.implementation.aalto.stax.InputFactoryImpl; import com.azure.xml.implementation.aalto.util.BufferRecycler; import com.azure.xml.implementation.aalto.util.CharsetNames; import com.azure.xml.implementation.aalto.util.UriCanonicalizer; import com.azure.xml.implementation.aalto.util.XmlCharTypes; import com.azure.xml.implementation.aalto.util.XmlConsts; -import com.azure.xml.implementation.stax2.XMLInputFactory2; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLReporter; @@ -72,10 +72,10 @@ public final class ReaderConfig extends CommonConfig { sProperties.put(XMLInputFactory.ALLOCATOR, null); // // // Stax2: - sProperties.put(XMLInputFactory2.P_LAZY_PARSING, F_LAZY_PARSING); - sProperties.put(XMLInputFactory2.P_INTERN_NAMES, F_INTERN_NAMES); - sProperties.put(XMLInputFactory2.P_INTERN_NS_URIS, F_INTERN_NS_URIS); - sProperties.put(XMLInputFactory2.P_AUTO_CLOSE_INPUT, F_AUTO_CLOSE_INPUT); + sProperties.put(InputFactoryImpl.P_LAZY_PARSING, F_LAZY_PARSING); + sProperties.put(InputFactoryImpl.P_INTERN_NAMES, F_INTERN_NAMES); + sProperties.put(InputFactoryImpl.P_INTERN_NS_URIS, F_INTERN_NS_URIS); + sProperties.put(InputFactoryImpl.P_AUTO_CLOSE_INPUT, F_AUTO_CLOSE_INPUT); // (ones with fixed defaults) @@ -83,13 +83,13 @@ public final class ReaderConfig extends CommonConfig { * report white space in prolog/epilog, as it's not really part * of document content. */ - sProperties.put(XMLInputFactory2.P_REPORT_PROLOG_WHITESPACE, Boolean.FALSE); - sProperties.put(XMLInputFactory2.P_REPORT_CDATA, F_REPORT_CDATA); + sProperties.put(InputFactoryImpl.P_REPORT_PROLOG_WHITESPACE, Boolean.FALSE); + sProperties.put(InputFactoryImpl.P_REPORT_CDATA, F_REPORT_CDATA); - sProperties.put(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE); + sProperties.put(InputFactoryImpl.P_PRESERVE_LOCATION, Boolean.TRUE); // !!! Not really implemented, but let's recognize it - sProperties.put(XMLInputFactory2.P_DTD_OVERRIDE, null); + sProperties.put(InputFactoryImpl.P_DTD_OVERRIDE, null); } /** @@ -105,13 +105,6 @@ public final class ReaderConfig extends CommonConfig { */ private final UriCanonicalizer mCanonicalizer; - /** - * Encoding passed in as external information, possibly from source - * from which xml content was gained from (for example, as an HTTP - * header, or file metadata). - */ - private final String mExtEncoding; - /** * Name of the actual encoding that input was found to be in (if any * -- can't be determined if a Reader was passed in). @@ -152,10 +145,9 @@ public final class ReaderConfig extends CommonConfig { /********************************************************************** */ - private ReaderConfig(String extEnc, EncodingContext encCtxt, int flags, int flagMods, XMLReporter rep, - XMLResolver res, UriCanonicalizer canonicalizer) { + private ReaderConfig(EncodingContext encCtxt, int flags, int flagMods, XMLReporter rep, XMLResolver res, + UriCanonicalizer canonicalizer) { super(flags, flagMods); - mExtEncoding = extEnc; /* Ok, let's then see if we can find a buffer recycler. Since they * are lazily constructed, and since GC may just flush them out @@ -176,7 +168,7 @@ private ReaderConfig(String extEnc, EncodingContext encCtxt, int flags, int flag } public ReaderConfig() { - this(null, new EncodingContext(), DEFAULT_FLAGS, 0, null, null, new UriCanonicalizer()); + this(new EncodingContext(), DEFAULT_FLAGS, 0, null, null, new UriCanonicalizer()); } public void setActualEncoding(String actualEnc) { @@ -222,13 +214,8 @@ public void setXMLResolver(XMLResolver r) { /********************************************************************** */ - public ReaderConfig createNonShared(String extEnc) { - return new ReaderConfig(extEnc, mEncCtxt, _flags, _flagMods, mReporter, mResolver, mCanonicalizer); - } - - @Override - public String getExternalEncoding() { - return mExtEncoding; + public ReaderConfig createNonShared() { + return new ReaderConfig(mEncCtxt, _flags, _flagMods, mReporter, mResolver, mCanonicalizer); } @Override diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderScanner.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderScanner.java index e1578d357965..830d4945c836 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderScanner.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/ReaderScanner.java @@ -1,20 +1,20 @@ // Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. package com.azure.xml.implementation.aalto.in; -import java.io.*; - -import javax.xml.stream.Location; -import javax.xml.stream.XMLStreamException; - import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.impl.IoStreamException; import com.azure.xml.implementation.aalto.impl.LocationImpl; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; import com.azure.xml.implementation.aalto.util.DataUtil; import com.azure.xml.implementation.aalto.util.TextBuilder; import com.azure.xml.implementation.aalto.util.XmlCharTypes; import com.azure.xml.implementation.aalto.util.XmlChars; import com.azure.xml.implementation.aalto.util.XmlConsts; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import java.io.IOException; +import java.io.Reader; + /** * This is the concrete scanner implementation used when input comes * as a {@link java.io.Reader}. In general using this scanner is quite @@ -1359,7 +1359,7 @@ protected void finishPI() throws XMLStreamException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } - if (inputBuffer[_inputPtr] == CHAR_LF) { + if (inputBuffer[_inputPtr] == XmlConsts.CHAR_LF) { ++_inputPtr; } markLF(); @@ -2439,7 +2439,7 @@ protected void skipPI() throws XMLStreamException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } - if (inputBuffer[_inputPtr] == CHAR_LF) { + if (inputBuffer[_inputPtr] == XmlConsts.CHAR_LF) { ++_inputPtr; } markLF(); @@ -2514,7 +2514,7 @@ protected boolean skipCharacters() throws XMLStreamException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } - if (inputBuffer[_inputPtr] == CHAR_LF) { + if (inputBuffer[_inputPtr] == XmlConsts.CHAR_LF) { ++_inputPtr; } markLF(); @@ -2616,7 +2616,7 @@ protected void skipCData() throws XMLStreamException { loadMoreGuaranteed(); ptr = _inputPtr; } - if (inputBuffer[ptr] == CHAR_LF) { + if (inputBuffer[ptr] == XmlConsts.CHAR_LF) { ++ptr; ++_inputPtr; } @@ -2778,7 +2778,7 @@ private int checkInTreeIndentation(char c) throws XMLStreamException { if (c == '\r') { // First a degenerate case, a lone \r: if (_inputPtr >= _inputEnd && !loadMore()) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } if (_inputBuffer[_inputPtr] == '\n') { @@ -2844,7 +2844,7 @@ private int checkPrologIndentation(char c) throws XMLStreamException { if (c == '\r') { // First a degenerate case, a lone \r: if (_inputPtr >= _inputEnd && !loadMore()) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } if (_inputBuffer[_inputPtr] == '\n') { @@ -2854,14 +2854,14 @@ private int checkPrologIndentation(char c) throws XMLStreamException { markLF(); // Ok, indentation char? if (_inputPtr >= _inputEnd && !loadMore()) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } c = _inputBuffer[_inputPtr]; // won't advance past the char yet if (c != ' ' && c != '\t') { // If lt, it's still indentation ok: if (c == '<') { // need - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } // Nope... something else @@ -3213,7 +3213,7 @@ protected boolean loadMore() throws XMLStreamException { _inputEnd = count; return true; } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } @@ -3258,7 +3258,7 @@ private boolean loadAndRetain() throws XMLStreamException { } while (_inputEnd < 3); return true; } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/StreamScanner.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/StreamScanner.java index f38fe245ab33..cb7fbb547469 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/StreamScanner.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/StreamScanner.java @@ -16,21 +16,99 @@ package com.azure.xml.implementation.aalto.in; -import java.io.*; - -import javax.xml.stream.XMLStreamException; - import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.impl.IoStreamException; +import com.azure.xml.implementation.aalto.impl.LocationImpl; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; import com.azure.xml.implementation.aalto.util.DataUtil; import com.azure.xml.implementation.aalto.util.TextBuilder; import com.azure.xml.implementation.aalto.util.XmlCharTypes; +import com.azure.xml.implementation.aalto.util.XmlChars; +import com.azure.xml.implementation.aalto.util.XmlConsts; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; /** * Base class for various byte stream based scanners (generally one * for each type of encoding supported). */ -public abstract class StreamScanner extends ByteBasedScanner { +@SuppressWarnings("fallthrough") +public final class StreamScanner extends XmlScanner { + /* + /********************************************************************** + /* Byte constants + /********************************************************************** + */ + + // White-space: + + private final static byte BYTE_SPACE = (byte) ' '; + private final static byte BYTE_LF = (byte) '\n'; + private final static byte BYTE_CR = (byte) '\r'; + private final static byte BYTE_TAB = (byte) 9; + + private final static byte BYTE_LT = (byte) '<'; + private final static byte BYTE_GT = (byte) '>'; + private final static byte BYTE_AMP = (byte) '&'; + private final static byte BYTE_HASH = (byte) '#'; + private final static byte BYTE_EXCL = (byte) '!'; + private final static byte BYTE_HYPHEN = (byte) '-'; + private final static byte BYTE_QMARK = (byte) '?'; + private final static byte BYTE_SLASH = (byte) '/'; + private final static byte BYTE_LBRACKET = (byte) '['; + private final static byte BYTE_RBRACKET = (byte) ']'; + private final static byte BYTE_SEMICOLON = (byte) ';'; + + private final static byte BYTE_a = (byte) 'a'; + private final static byte BYTE_g = (byte) 'g'; + private final static byte BYTE_l = (byte) 'l'; + private final static byte BYTE_m = (byte) 'm'; + private final static byte BYTE_o = (byte) 'o'; + private final static byte BYTE_p = (byte) 'p'; + private final static byte BYTE_q = (byte) 'q'; + private final static byte BYTE_s = (byte) 's'; + private final static byte BYTE_t = (byte) 't'; + private final static byte BYTE_u = (byte) 'u'; + private final static byte BYTE_x = (byte) 'x'; + + private final static byte BYTE_D = (byte) 'D'; + private final static byte BYTE_P = (byte) 'P'; + private final static byte BYTE_S = (byte) 'S'; + + /* + /********************************************************************** + /* Input buffering + /********************************************************************** + */ + + /** + * Pointer to the next unread byte in the input buffer. + */ + private int _inputPtr; + + /** + * Pointer to the first byte after the end of valid content. + * This may point beyond of the physical buffer array. + */ + private int _inputEnd; + + /* + /********************************************************************** + /* Parsing state + /********************************************************************** + */ + + /** + * Storage location for a single character that can not be easily + * pushed back (for example, multi-byte char; or char entity + * expansion). Negative, if from entity expansion; positive if + * a singular char. + */ + private int _tmpChar = INT_NULL; + /* /********************************************************************** /* Configuration, input, buffering @@ -40,9 +118,9 @@ public abstract class StreamScanner extends ByteBasedScanner { /** * Underlying InputStream to use for reading content. */ - protected InputStream _in; + private InputStream _in; - protected byte[] _inputBuffer; + private byte[] _inputBuffer; /* /********************************************************************** @@ -56,19 +134,19 @@ public abstract class StreamScanner extends ByteBasedScanner { * we actually support multiple utf-8 compatible encodings, not * just utf-8 itself. */ - protected final XmlCharTypes _charTypes; + private final XmlCharTypes _charTypes; /** * For now, symbol table contains prefixed names. In future it is * possible that they may be split into prefixes and local names? */ - protected final ByteBasedPNameTable _symbols; + private final ByteBasedPNameTable _symbols; /** * This buffer is used for name parsing. Will be expanded if/as * needed; 32 ints can hold names 128 ascii chars long. */ - protected int[] _quadBuffer = new int[32]; + private int[] _quadBuffer = new int[32]; /* /********************************************************************** @@ -85,6 +163,8 @@ public StreamScanner(ReaderConfig cfg, InputStream in, byte[] buffer, int ptr, i _inputBuffer = buffer; _inputPtr = ptr; _inputEnd = last; + _pastBytesOrChars = 0; // should it be passed by caller? + _rowStartOffset = 0; // should probably be passed by caller... } @Override @@ -115,15 +195,332 @@ protected void _closeSource() throws IOException { /* /********************************************************************** - /* Abstract methods for sub-classes to implement + /* Location handling /********************************************************************** */ - protected abstract int handleEntityInText() throws XMLStreamException; + @Override + public Location getCurrentLocation() { + return LocationImpl.fromZeroBased(_pastBytesOrChars + _inputPtr, _currRow, _inputPtr - _rowStartOffset); + } + + private void markLF(int offset) { + _rowStartOffset = offset; + ++_currRow; + } + + private void markLF() { + _rowStartOffset = _inputPtr; + ++_currRow; + } + + private void setStartLocation() { + _startRawOffset = _pastBytesOrChars + _inputPtr; + _startRow = _currRow; + _startColumn = _inputPtr - _rowStartOffset; + } + + /** + * Method called when an ampersand is encounter in text segment. + * Method needs to determine whether it is a pre-defined or character + * entity (in which case it will be expanded into a single char or + * surrogate pair), or a general + * entity (in which case it will most likely be returned as + * ENTITY_REFERENCE event) + * + * @return 0 if a general parsed entity encountered; integer + * value of a (valid) XML content character otherwise + */ + private int handleEntityInText() throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + byte b = _inputBuffer[_inputPtr++]; + if (b == BYTE_HASH) { + return handleCharEntity(); + } + String start; + if (b == BYTE_a) { // amp or apos? + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_m) { // amp? + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_p) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_SEMICOLON) { + return INT_AMP; + } + start = "amp"; + } else { + start = "am"; + } + } else if (b == BYTE_p) { // apos? + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_o) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_s) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_SEMICOLON) { + return INT_APOS; + } + start = "apos"; + } else { + start = "apo"; + } + } else { + start = "ap"; + } + } else { + start = "a"; + } + } else if (b == BYTE_l) { // lt? + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_t) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_SEMICOLON) { + return INT_LT; + } + start = "lt"; + } else { + start = "l"; + } + } else if (b == BYTE_g) { // gt? + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_t) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_SEMICOLON) { + return INT_GT; + } + start = "gt"; + } else { + start = "g"; + } + } else if (b == BYTE_q) { // quot? + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_u) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_o) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_t) { + b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b == BYTE_SEMICOLON) { + return INT_QUOTE; + } + start = "quot"; + } else { + start = "quo"; + } + } else { + start = "qu"; + } + } else { + start = "q"; + } + } else { + start = ""; + } + + final int[] TYPES = _charTypes.NAME_CHARS; + + /* All righty: we have the beginning of the name, plus the first + * byte too. So let's see what we can do with it. + */ + char[] cbuf = _nameBuffer; + int cix = 0; + for (int len = start.length(); cix < len; ++cix) { + cbuf[cix] = start.charAt(cix); + } + //int colon = -1; + while (b != BYTE_SEMICOLON) { + boolean ok; + int c = (int) b & 0xFF; + + // Has to be a valid name start char though: + switch (TYPES[c]) { + case XmlCharTypes.CT_NAME_NONE: + case XmlCharTypes.CT_NAME_COLON: // not ok for entities? + case XmlCharTypes.CT_NAME_NONFIRST: + ok = (cix > 0); + break; + + case XmlCharTypes.CT_NAME_ANY: + ok = true; + break; + + case InputCharTypes.CT_INPUT_NAME_MB_2: + c = decodeUtf8_2(c); + ok = XmlChars.is10NameStartChar(c); + break; + + case InputCharTypes.CT_INPUT_NAME_MB_3: + c = decodeUtf8_3(c); + ok = XmlChars.is10NameStartChar(c); + break; + + case InputCharTypes.CT_INPUT_NAME_MB_4: + c = decodeUtf8_4(c); + ok = XmlChars.is10NameStartChar(c); + if (ok) { + if (cix >= cbuf.length) { + _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); + } + // Let's add first part right away: + c -= 0x10000; + cbuf[cix++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + } + break; + + case InputCharTypes.CT_INPUT_NAME_MB_N: + default: + ok = false; + break; + } + if (!ok) { + reportInvalidNameChar(c, cix); + } + if (cix >= cbuf.length) { + _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); + } + cbuf[cix++] = (char) c; + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = _inputBuffer[_inputPtr++]; + } + + // Ok, let's construct a (temporary) entity name, then: + String pname = new String(cbuf, 0, cix); + // (note: hash is dummy... not to be compared to anything etc) + _tokenName = new PNameC(pname, null, pname, 0); + + /* One more thing: do we actually allow entities in this mode + * and with this event? + */ + if (_config.willExpandEntities()) { + reportInputProblem("General entity reference (&" + pname + + ";) encountered in entity expanding mode: operation not (yet) implemented"); + } + return 0; + } + + /** + * Parsing of public ids is bit more complicated than that of system + * ids, since white space is to be coalesced. + */ + private String parsePublicId(byte quoteChar) throws XMLStreamException { + char[] outputBuffer = _nameBuffer; + int outPtr = 0; + final int[] TYPES = XmlCharTypes.PUBID_CHARS; + boolean addSpace = false; + + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + // Easier to check without char type table, first: + byte b = _inputBuffer[_inputPtr++]; + if (b == quoteChar) { + break; + } + int c = (int) b & 0xFF; + if (TYPES[c] != XmlCharTypes.PUBID_OK) { + throwUnexpectedChar(c, " in public identifier"); + } + + // White space? Needs to be coalesced + if (c <= INT_SPACE) { + addSpace = true; + continue; + } + if (addSpace) { + if (outPtr >= outputBuffer.length) { + _nameBuffer = outputBuffer = DataUtil.growArrayBy(outputBuffer, outputBuffer.length); + outPtr = 0; + } + outputBuffer[outPtr++] = ' '; + addSpace = false; + } + if (outPtr >= outputBuffer.length) { + _nameBuffer = outputBuffer = DataUtil.growArrayBy(outputBuffer, outputBuffer.length); + outPtr = 0; + } + outputBuffer[outPtr++] = (char) c; + } + return new String(outputBuffer, 0, outPtr); + } + + private String parseSystemId(byte quoteChar) throws XMLStreamException { + // caller has init'ed the buffer... + char[] outputBuffer = _nameBuffer; + int outPtr = 0; + // attribute types are closest matches, so let's use them + final int[] TYPES = _charTypes.ATTR_CHARS; + //boolean spaceToAdd = false; + + main_loop: while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + int c = (int) _inputBuffer[_inputPtr++] & 0xFF; + if (TYPES[c] != 0) { + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; - protected abstract String parsePublicId(byte quoteChar) throws XMLStreamException; + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + + case XmlCharTypes.CT_ATTR_QUOTE: + if (c == (int) quoteChar) { + break main_loop; + } + } + + } - protected abstract String parseSystemId(byte quoteChar) throws XMLStreamException; + if (outPtr >= outputBuffer.length) { + _nameBuffer = outputBuffer = DataUtil.growArrayBy(outputBuffer, outputBuffer.length); + outPtr = 0; + } + outputBuffer[outPtr++] = (char) c; + } + return new String(outputBuffer, 0, outPtr); + } /* /********************************************************************** @@ -132,7 +529,7 @@ protected void _closeSource() throws IOException { */ @Override - public final int nextFromProlog(boolean isProlog) throws XMLStreamException { + public int nextFromProlog(boolean isProlog) throws XMLStreamException { if (_tokenIncomplete) { // left-overs from last thingy? skipToken(); } @@ -200,7 +597,7 @@ public final int nextFromProlog(boolean isProlog) throws XMLStreamException { } @Override - public final int nextFromTree() throws XMLStreamException { + public int nextFromTree() throws XMLStreamException { if (_tokenIncomplete) { // left-overs? if (skipToken()) { // Figured out next event (ENTITY_REFERENCE)? // !!! We don't yet parse DTD, don't know real contents @@ -285,7 +682,7 @@ public final int nextFromTree() throws XMLStreamException { * Helper method used to isolate things that need to be (re)set in * cases where */ - protected int _nextEntity() { + private int _nextEntity() { // !!! Also, have to assume start location has been set or such _textBuilder.resetWithEmpty(); // !!! TODO: handle start location? @@ -494,7 +891,7 @@ private int handlePIStart() throws XMLStreamException { * @return Code point for the entity that expands to a valid XML * content character. */ - protected final int handleCharEntity() throws XMLStreamException { + private int handleCharEntity() throws XMLStreamException { // Hex or decimal? if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); @@ -550,117 +947,507 @@ protected final int handleCharEntity() throws XMLStreamException { * Parsing of start element requires parsing of the element name * (and attribute names), and is thus encoding-specific. */ - protected abstract int handleStartElement(byte b) throws XMLStreamException; - - /** - * Note that this method is currently also shareable for all Ascii-based - * encodings, and at least between UTF-8 and ISO-Latin1. The reason is - * that since we already know exact bytes that need to be matched, - * there's no danger of getting invalid encodings or such. - * So, for now, let's leave this method here in the base class. - */ - protected final int handleEndElement() throws XMLStreamException { - --_depth; - _currToken = END_ELEMENT; - // Ok, at this point we have seen '/', need the name - _tokenName = _currElem.getName(); + private int handleStartElement(byte b) throws XMLStreamException { + _currToken = START_ELEMENT; + _currNsCount = 0; + PName elemName = parsePName(b); - int size = _tokenName.sizeInQuads(); - /* Do we need to take the slow route? Let's separate that out - * to another method. - * Note: we'll require max bytes for name PLUS one (for trailing - * '>', most likely). + /* Ok. Need to create a qualified name. Simplest for element + * in default ns (no extra work -- expressed as null binding); + * otherwise need to find binding */ - if ((_inputEnd - _inputPtr) < ((size << 2) + 1)) { // may need to load more - return handleEndElementSlow(size); + String prefix = elemName.getPrefix(); + boolean allBound; // flag to check 'late' bindings + + if (prefix == null) { // element in default ns + allBound = true; // which need not be bound + } else { + elemName = bindName(elemName, prefix); + allBound = elemName.isBound(); } - int ptr = _inputPtr; - byte[] buf = _inputBuffer; + _tokenName = elemName; + _currElem = new ElementScope(elemName, _currElem); - // First all full chunks of 4 bytes (if any) - --size; - for (int qix = 0; qix < size; ++qix) { - int q = (buf[ptr] << 24) | ((buf[ptr + 1] & 0xFF) << 16) | ((buf[ptr + 2] & 0xFF) << 8) - | ((buf[ptr + 3] & 0xFF)); - ptr += 4; - // match? - if (q != _tokenName.getQuad(qix)) { - _inputPtr = ptr; - reportUnexpectedEndTag(_tokenName.getPrefixedName()); - } - } + // And then attribute parsing loop: + int attrPtr = 0; - /* After which we can deal with the last entry: it's bit - * tricky as we don't actually fully know byte length... - */ - int lastQ = _tokenName.getQuad(size); - int q = buf[ptr++] & 0xFF; - if (q != lastQ) { // need second byte? - q = (q << 8) | (buf[ptr++] & 0xFF); - if (q != lastQ) { // need third byte? - q = (q << 8) | (buf[ptr++] & 0xFF); - if (q != lastQ) { // need full 4 bytes? - q = (q << 8) | (buf[ptr++] & 0xFF); - if (q != lastQ) { // still no match? failure! - _inputPtr = ptr; - reportUnexpectedEndTag(_tokenName.getPrefixedName()); - } - } + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); } - } - // Trailing space? - int i2 = _inputBuffer[ptr] & 0xFF; - _inputPtr = ptr + 1; - while (i2 <= INT_SPACE) { - if (i2 == INT_LF) { - markLF(); - } else if (i2 == INT_CR) { - byte b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b != BYTE_LF) { - markLF(_inputPtr - 1); - i2 = (int) b & 0xFF; - continue; - } - markLF(); - } else if (i2 != INT_SPACE && i2 != INT_TAB) { - throwInvalidSpace(i2); + b = _inputBuffer[_inputPtr++]; + int c = (int) b & 0xFF; + // Intervening space to skip? + if (c <= INT_SPACE) { + do { + if (c == INT_LF) { + markLF(); + } else if (c == INT_CR) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + } else if (c != INT_SPACE && c != INT_TAB) { + throwInvalidSpace(c); + } + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = _inputBuffer[_inputPtr++]; + c = (int) b & 0xFF; + } while (c <= INT_SPACE); + } else if (c != INT_SLASH && c != INT_GT) { + c = decodeCharForError(b); + throwUnexpectedChar(c, " expected space, or '>' or \"/>\""); } - i2 = (int) ((_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne()) & 0xFF; - } - if (i2 != INT_GT) { - throwUnexpectedChar(decodeCharForError((byte) i2), " expected space or closing '>'"); - } - return END_ELEMENT; - } - private int handleEndElementSlow(int size) throws XMLStreamException { - /* Nope, will likely cross the input boundary; need - * to do proper checks - */ - --size; - for (int qix = 0; qix < size; ++qix) { // first, full chunks - int q = 0; - for (int i = 0; i < 4; ++i) { + // Ok; either need to get an attribute name, or end marker: + if (c == INT_SLASH) { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } - q = (q << 8) | (_inputBuffer[_inputPtr++] & 0xFF); - } - // match? - if (q != _tokenName.getQuad(qix)) { - reportUnexpectedEndTag(_tokenName.getPrefixedName()); + b = _inputBuffer[_inputPtr++]; + if (b != BYTE_GT) { + c = decodeCharForError(b); + throwUnexpectedChar(c, " expected '>'"); + } + _isEmptyTag = true; + break; + } else if (c == INT_GT) { + _isEmptyTag = false; + break; + } else if (c == INT_LT) { + reportInputProblem("Unexpected '<' character in element (missing closing '>'?)"); } - } - // And then the last 1-4 bytes: - int lastQ = _tokenName.getQuad(size); - int q = 0; - int i = 0; + // Ok, an attr name: + PName attrName = parsePName(b); + prefix = attrName.getPrefix(); - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); + boolean isNsDecl; + + if (prefix == null) { // can be default ns decl: + isNsDecl = (Objects.equals(attrName.getLocalName(), "xmlns")); + } else { + // May be a namespace decl though? + if (prefix.equals("xmlns")) { + isNsDecl = true; + } else { + attrName = bindName(attrName, prefix); + if (allBound) { + allBound = attrName.isBound(); + } + isNsDecl = false; + } + } + + // Optional space to skip again + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = _inputBuffer[_inputPtr++]; + c = (int) b & 0xFF; + if (c > INT_SPACE) { + break; + } + if (c == INT_LF) { + markLF(); + } else if (c == INT_CR) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + } else if (c != INT_SPACE && c != INT_TAB) { + throwInvalidSpace(c); + } + } + + if (c != INT_EQ) { + c = decodeCharForError(b); + throwUnexpectedChar(c, " expected '='"); + } + + // Optional space to skip again + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = _inputBuffer[_inputPtr++]; + c = (int) b & 0xFF; + if (c > INT_SPACE) { + break; + } + if (c == INT_LF) { + markLF(); + } else if (c == INT_CR) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + } else if (c != INT_SPACE && c != INT_TAB) { + throwInvalidSpace(c); + } + } + + if (c != INT_QUOTE && c != INT_APOS) { + c = decodeCharForError(b); + throwUnexpectedChar(c, " Expected a quote"); + } + + /* Ok, finally: value parsing. However, ns URIs are to be handled + * different from attribute values... let's offline URIs, since + * they should be less common than attribute values. + */ + if (isNsDecl) { // default ns, or explicit? + handleNsDeclaration(attrName, b); + ++_currNsCount; + } else { // nope, a 'real' attribute: + attrPtr = collectValue(attrPtr, b, attrName); + } + } + { + // Note: this call also checks attribute uniqueness + int act = _attrCollector.finishLastValue(attrPtr); + if (act < 0) { // error, dup attr indicated by -1 + act = _attrCollector.getCount(); // let's get correct count + reportInputProblem(_attrCollector.getErrorMsg()); + } + _attrCount = act; + } + ++_depth; + + /* Was there any prefix that wasn't bound prior to use? + * That's legal, assuming declaration was found later on... + * let's check + */ + if (!allBound) { + if (!elemName.isBound()) { // element itself unbound + reportUnboundPrefix(_tokenName, false); + } + for (int i = 0, len = _attrCount; i < len; ++i) { + PName attrName = _attrCollector.getName(i); + if (!attrName.isBound()) { + reportUnboundPrefix(attrName, true); + } + } + } + return START_ELEMENT; + } + + /** + * This method implements the tight loop for parsing attribute + * values. It's off-lined from the main start element method to + * simplify main method, which makes code more maintainable + * and possibly easier for JIT/HotSpot to optimize. + */ + private int collectValue(int attrPtr, byte quoteByte, PName attrName) throws XMLStreamException { + char[] attrBuffer = _attrCollector.startNewValue(attrName, attrPtr); + final int[] TYPES = _charTypes.ATTR_CHARS; + + value_loop: while (true) { + int c; + + ascii_loop: while (true) { + int ptr = _inputPtr; + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + if (attrPtr >= attrBuffer.length) { + attrBuffer = _attrCollector.valueBufferFull(); + } + int max = _inputEnd; + { + int max2 = ptr + (attrBuffer.length - attrPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) _inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + attrBuffer[attrPtr++] = (char) c; + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + // fall through + case XmlCharTypes.CT_WS_LF: + markLF(); + // fall through + case XmlCharTypes.CT_WS_TAB: + // Plus, need to convert these all to simple space + c = INT_SPACE; + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + if (attrPtr >= attrBuffer.length) { + attrBuffer = _attrCollector.valueBufferFull(); + } + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_LT: + throwUnexpectedChar(c, "'<' not allowed in attribute value"); + case XmlCharTypes.CT_AMP: + c = handleEntityInText(); + if (c == 0) { // unexpanded general entity... not good + reportUnexpandedEntityInAttr(false); + } + // Ok; does it need a surrogate though? (over 16 bits) + if ((c >> 16) != 0) { + c -= 0x10000; + attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + if (attrPtr >= attrBuffer.length) { + attrBuffer = _attrCollector.valueBufferFull(); + } + } + break; + + case XmlCharTypes.CT_ATTR_QUOTE: + if (c == (int) quoteByte) { + break value_loop; + } + + // default: + // Other chars are not important here... + } + // We know there's room for at least one char without checking + attrBuffer[attrPtr++] = (char) c; + } + + return attrPtr; + } + + /** + * Method called from the main START_ELEMENT handling loop, to + * parse namespace URI values. + */ + private void handleNsDeclaration(PName name, byte quoteByte) throws XMLStreamException { + int attrPtr = 0; + char[] attrBuffer = _nameBuffer; + + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + byte b = _inputBuffer[_inputPtr++]; + if (b == quoteByte) { + break; + } + int c; + if (b == BYTE_AMP) { // entity + c = handleEntityInText(); + if (c == 0) { // general entity; should never happen + reportUnexpandedEntityInAttr(true); + } + // Ok; does it need a surrogate though? (over 16 bits) + if ((c >> 16) != 0) { + if (attrPtr >= attrBuffer.length) { + _nameBuffer = attrBuffer = DataUtil.growArrayBy(attrBuffer, attrBuffer.length); + } + c -= 0x10000; + attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + } + } else if (b == BYTE_LT) { // error + c = b; + throwUnexpectedChar(c, "'<' not allowed in attribute value"); + } else { + c = (int) b & 0xFF; + if (c < INT_SPACE) { + if (c == INT_LF) { + markLF(); + } else if (c == INT_CR) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + } else if (c != INT_TAB) { + throwInvalidSpace(c); + } + } else if (c > 0x7F) { + c = decodeMultiByteChar(c, _inputPtr); + if (c < 0) { // surrogate pair + c = -c; + // Let's add first part right away: + if (attrPtr >= attrBuffer.length) { + _nameBuffer = attrBuffer = DataUtil.growArrayBy(attrBuffer, attrBuffer.length); + } + c -= 0x10000; + attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + } + } + } + if (attrPtr >= attrBuffer.length) { + _nameBuffer = attrBuffer = DataUtil.growArrayBy(attrBuffer, attrBuffer.length); + } + attrBuffer[attrPtr++] = (char) c; + } + + /* Simple optimization: for default ns removal (or, with + * ns 1.1, any other as well), will use empty value... no + * need to try to intern: + */ + if (attrPtr == 0) { + bindNs(name, ""); + } else { + String uri = _config.canonicalizeURI(attrBuffer, attrPtr); + bindNs(name, uri); + } + } + + /** + * Note that this method is currently also shareable for all Ascii-based + * encodings, and at least between UTF-8 and ISO-Latin1. The reason is + * that since we already know exact bytes that need to be matched, + * there's no danger of getting invalid encodings or such. + * So, for now, let's leave this method here in the base class. + */ + private int handleEndElement() throws XMLStreamException { + --_depth; + _currToken = END_ELEMENT; + // Ok, at this point we have seen '/', need the name + _tokenName = _currElem.getName(); + + int size = _tokenName.sizeInQuads(); + /* Do we need to take the slow route? Let's separate that out + * to another method. + * Note: we'll require max bytes for name PLUS one (for trailing + * '>', most likely). + */ + if ((_inputEnd - _inputPtr) < ((size << 2) + 1)) { // may need to load more + return handleEndElementSlow(size); + } + + int ptr = _inputPtr; + byte[] buf = _inputBuffer; + + // First all full chunks of 4 bytes (if any) + --size; + for (int qix = 0; qix < size; ++qix) { + int q = (buf[ptr] << 24) | ((buf[ptr + 1] & 0xFF) << 16) | ((buf[ptr + 2] & 0xFF) << 8) + | ((buf[ptr + 3] & 0xFF)); + ptr += 4; + // match? + if (q != _tokenName.getQuad(qix)) { + _inputPtr = ptr; + reportUnexpectedEndTag(_tokenName.getPrefixedName()); + } + } + + /* After which we can deal with the last entry: it's bit + * tricky as we don't actually fully know byte length... + */ + int lastQ = _tokenName.getQuad(size); + int q = buf[ptr++] & 0xFF; + if (q != lastQ) { // need second byte? + q = (q << 8) | (buf[ptr++] & 0xFF); + if (q != lastQ) { // need third byte? + q = (q << 8) | (buf[ptr++] & 0xFF); + if (q != lastQ) { // need full 4 bytes? + q = (q << 8) | (buf[ptr++] & 0xFF); + if (q != lastQ) { // still no match? failure! + _inputPtr = ptr; + reportUnexpectedEndTag(_tokenName.getPrefixedName()); + } + } + } + } + // Trailing space? + int i2 = _inputBuffer[ptr] & 0xFF; + _inputPtr = ptr + 1; + while (i2 <= INT_SPACE) { + if (i2 == INT_LF) { + markLF(); + } else if (i2 == INT_CR) { + byte b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); + if (b != BYTE_LF) { + markLF(_inputPtr - 1); + i2 = (int) b & 0xFF; + continue; + } + markLF(); + } else if (i2 != INT_SPACE && i2 != INT_TAB) { + throwInvalidSpace(i2); + } + i2 = (int) ((_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne()) & 0xFF; + } + if (i2 != INT_GT) { + throwUnexpectedChar(decodeCharForError((byte) i2), " expected space or closing '>'"); + } + return END_ELEMENT; + } + + private int handleEndElementSlow(int size) throws XMLStreamException { + /* Nope, will likely cross the input boundary; need + * to do proper checks + */ + --size; + for (int qix = 0; qix < size; ++qix) { // first, full chunks + int q = 0; + for (int i = 0; i < 4; ++i) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + q = (q << 8) | (_inputBuffer[_inputPtr++] & 0xFF); + } + // match? + if (q != _tokenName.getQuad(qix)) { + reportUnexpectedEndTag(_tokenName.getPrefixedName()); + } + } + + // And then the last 1-4 bytes: + int lastQ = _tokenName.getQuad(size); + int q = 0; + int i = 0; + + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); } q = (q << 8) | (_inputBuffer[_inputPtr++] & 0xFF); if (q == lastQ) { // match @@ -717,7 +1504,7 @@ private int handleEndElementSlow(int size) throws XMLStreamException { * * */ - protected final PName parsePName(byte b) throws XMLStreamException { + private PName parsePName(byte b) throws XMLStreamException { // First: can we optimize out bounds checks? if ((_inputEnd - _inputPtr) < 8) { // got 1 byte, but need 7, plus one trailing return parsePNameSlow(b); @@ -768,7 +1555,7 @@ protected final PName parsePName(byte b) throws XMLStreamException { return parsePNameMedium(i2, q); } - protected PName parsePNameMedium(int i2, int q1) throws XMLStreamException { + private PName parsePNameMedium(int i2, int q1) throws XMLStreamException { // Ok, so far so good; one quad, one byte. Then the second int q2 = i2; i2 = _inputBuffer[_inputPtr++] & 0xFF; @@ -808,7 +1595,7 @@ protected PName parsePNameMedium(int i2, int q1) throws XMLStreamException { return parsePNameLong(i2, quads); } - protected final PName parsePNameLong(int q, int[] quads) throws XMLStreamException { + private PName parsePNameLong(int q, int[] quads) throws XMLStreamException { int qix = 2; while (true) { // Second byte of a new quad @@ -854,7 +1641,7 @@ protected final PName parsePNameLong(int q, int[] quads) throws XMLStreamExcepti } } - protected final PName parsePNameSlow(byte b) throws XMLStreamException { + private PName parsePNameSlow(byte b) throws XMLStreamException { int q = b & 0xFF; // Let's do just quick sanity check first; a thorough check will be @@ -1044,7 +1831,7 @@ private PName findPName(int lastQuad, int lastByteCount, int firstQuad, int qlen return findPName(lastQuad, quads, qlen, lastByteCount); } - protected final PName addPName(int hash, int[] quads, int qlen, int lastQuadBytes) throws XMLStreamException { + private PName addPName(int hash, int[] quads, int qlen, int lastQuadBytes) throws XMLStreamException { return addUTFPName(_symbols, _charTypes, hash, quads, qlen, lastQuadBytes); } @@ -1057,7 +1844,7 @@ protected final PName addPName(int hash, int[] quads, int qlen, int lastQuadByte /** * @return First byte following skipped white space */ - protected byte skipInternalWs(boolean reqd, String msg) throws XMLStreamException { + private byte skipInternalWs(boolean reqd, String msg) throws XMLStreamException { if (_inputPtr >= _inputEnd) { loadMoreGuaranteed(); } @@ -1119,11 +1906,11 @@ private void matchAsciiKeyword(String keyw) throws XMLStreamException { * @return -1, if indentation was handled; offset in the output * buffer, if not */ - protected final int checkInTreeIndentation(int c) throws XMLStreamException { + private int checkInTreeIndentation(int c) throws XMLStreamException { if (c == INT_CR) { // First a degenerate case, a lone \r: if (_inputPtr >= _inputEnd && !loadMore()) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } if (_inputBuffer[_inputPtr] == BYTE_LF) { @@ -1140,12 +1927,12 @@ protected final int checkInTreeIndentation(int c) throws XMLStreamException { // May still be indentation, if it's lt + non-exclamation mark if (b == BYTE_LT) { if ((_inputPtr + 1) < _inputEnd && _inputBuffer[_inputPtr + 1] != BYTE_EXCL) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } } char[] outBuf = _textBuilder.resetWithEmpty(); - outBuf[0] = CHAR_LF; + outBuf[0] = XmlConsts.CHAR_LF; _textBuilder.setCurrentLength(1); return 1; } @@ -1172,7 +1959,7 @@ protected final int checkInTreeIndentation(int c) throws XMLStreamException { // Nope, hit something else, or too long: need to just copy the stuff // we know buffer has enough room either way char[] outBuf = _textBuilder.resetWithEmpty(); - outBuf[0] = CHAR_LF; + outBuf[0] = XmlConsts.CHAR_LF; char ind = (char) b; for (int i = 1; i <= count; ++i) { outBuf[i] = ind; @@ -1186,11 +1973,11 @@ protected final int checkInTreeIndentation(int c) throws XMLStreamException { * @return -1, if indentation was handled; offset in the output * buffer, if not */ - protected final int checkPrologIndentation(int c) throws XMLStreamException { + private int checkPrologIndentation(int c) throws XMLStreamException { if (c == INT_CR) { // First a degenerate case, a lone \r: if (_inputPtr >= _inputEnd && !loadMore()) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } if (_inputBuffer[_inputPtr] == BYTE_LF) { @@ -1200,19 +1987,19 @@ protected final int checkPrologIndentation(int c) throws XMLStreamException { markLF(); // Ok, indentation char? if (_inputPtr >= _inputEnd && !loadMore()) { - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } byte b = _inputBuffer[_inputPtr]; // won't advance past the char yet if (b != BYTE_SPACE && b != BYTE_TAB) { // If lt, it's still indentation ok: if (b == BYTE_LT) { // need - _textBuilder.resetWithIndentation(0, CHAR_SPACE); + _textBuilder.resetWithIndentation(0, XmlConsts.CHAR_SPACE); return -1; } // Nope... something else char[] outBuf = _textBuilder.resetWithEmpty(); - outBuf[0] = CHAR_LF; + outBuf[0] = XmlConsts.CHAR_LF; _textBuilder.setCurrentLength(1); return 1; } @@ -1232,7 +2019,7 @@ protected final int checkPrologIndentation(int c) throws XMLStreamException { if (count >= max) { // ok, can't share... but can build it still // we know buffer has enough room char[] outBuf = _textBuilder.resetWithEmpty(); - outBuf[0] = CHAR_LF; + outBuf[0] = XmlConsts.CHAR_LF; char ind = (char) b; for (int i = 1; i <= count; ++i) { outBuf[i] = ind; @@ -1254,7 +2041,7 @@ protected final int checkPrologIndentation(int c) throws XMLStreamException { */ @Override - protected final boolean loadMore() throws XMLStreamException { + protected boolean loadMore() throws XMLStreamException { // First, let's update offsets: _pastBytesOrChars += _inputEnd; _rowStartOffset -= _inputEnd; @@ -1282,35 +2069,1939 @@ protected final boolean loadMore() throws XMLStreamException { _inputEnd = count; return true; } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } - protected final byte nextByte() throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { - reportInputProblem( - "Unexpected end-of-input when trying to parse " + ErrorConsts.tokenTypeDesc(_currToken)); - } - } + /* + /********************************************************************** + /* Content skipping + /********************************************************************** + */ + + @Override + protected boolean skipCharacters() throws XMLStreamException { + final int[] TYPES = _charTypes.TEXT_CHARS; + final byte[] inputBuffer = _inputBuffer; + + while (true) { + int c; + + // Then the tight ascii non-funny-char loop: + 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 (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + skipUtf8_2(); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + skipUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + skipUtf8_4(); + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_LT: + --_inputPtr; + return false; + + case XmlCharTypes.CT_AMP: + c = handleEntityInText(); + if (c == 0) { // unexpandable general parsed entity + return true; + } + break; + + case XmlCharTypes.CT_RBRACKET: // ']]>'? + { + // Let's then just count number of brackets -- + // in case they are not followed by '>' + int count = 1; + byte b; + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = inputBuffer[_inputPtr]; + if (b != BYTE_RBRACKET) { + break; + } + ++_inputPtr; // to skip past bracket + ++count; + } + if (b == BYTE_GT && count > 1) { + reportIllegalCDataEnd(); + } + } + break; + + // default: + // Other types are not important here... + } + } + } + + @Override + protected void skipComment() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + + while (true) { + int c; + + // Then the tight ascii non-funny-char loop: + 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 (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + skipUtf8_2(); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + skipUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + skipUtf8_4(); + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_HYPHEN: // '-->'? + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_HYPHEN) { // ok, must be end then + ++_inputPtr; + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr++] != BYTE_GT) { + reportDoubleHyphenInComments(); + } + return; + } + break; + + // default: + // Other types are not important here... + } + } + } + + @Override + protected void skipCData() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + + while (true) { + int c; + + // Then the tight ascii non-funny-char loop: + 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 (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + skipUtf8_2(); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + skipUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + skipUtf8_4(); + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_RBRACKET: // ']]>'? + { + // end is nigh? + int count = 0; + byte b; + + do { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + ++count; + b = _inputBuffer[_inputPtr++]; + } while (b == BYTE_RBRACKET); + + if (b == BYTE_GT) { + if (count > 1) { // gotcha + return; + } + // can still skip plain ']>'... + } else { + --_inputPtr; // need to push back last char + } + } + break; + + // default: + // Other types are not important here... + } + } + } + + @Override + protected void skipPI() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + + while (true) { + int c; + + // Then the tight ascii non-funny-char loop: + 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 (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + skipUtf8_2(); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + skipUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + skipUtf8_4(); + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_QMARK: // '?>'? + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_GT) { + ++_inputPtr; + return; + } + break; + + // default: + // Other types are not important here... + } + } + } + + @Override + protected void skipSpace() throws XMLStreamException { + // mTmpChar has a space, but it's been checked, can ignore + int ptr = _inputPtr; + + while (true) { + if (ptr >= _inputEnd) { + if (!loadMore()) { + break; + } + ptr = _inputPtr; + } + int c = (int) _inputBuffer[ptr] & 0xFF; + if (c > INT_SPACE) { // !!! TODO: xml 1.1 ws + break; + } + ++ptr; + + if (c == INT_LF) { + markLF(ptr); + } else if (c == INT_CR) { + if (ptr >= _inputEnd) { + if (!loadMore()) { + break; + } + ptr = _inputPtr; + } + if (_inputBuffer[ptr] == BYTE_LF) { + ++ptr; + } + markLF(ptr); + } else if (c != INT_SPACE && c != INT_TAB) { + _inputPtr = ptr; + throwInvalidSpace(c); + } + } + + _inputPtr = ptr; + } + + private void skipUtf8_2() throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + int c = _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 void skipUtf8_3(int c) throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + c &= 0x0F; + if (c >= 0xD) { // have to check + c <<= 6; + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + c |= (d & 0x3F); + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + c = (c << 6) | (d & 0x3F); + // 0xD800-0xDFFF, 0xFFFE-0xFFFF illegal + if (c >= 0xD800) { // surrogates illegal, as well as 0xFFFE/0xFFFF + if (c < 0xE000 || c >= 0xFFFE) { + handleInvalidXmlChar(c); + } + } + } else { // no checks, can discard + c = _inputBuffer[_inputPtr++]; + if ((c & 0xC0) != 0x080) { + reportInvalidOther(c & 0xFF, _inputPtr); + } + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + c = _inputBuffer[_inputPtr++]; + if ((c & 0xC0) != 0x080) { + reportInvalidOther(c & 0xFF, _inputPtr); + } + } + } + + private void skipUtf8_4() throws XMLStreamException { + if ((_inputPtr + 4) > _inputEnd) { + skipUtf8_4Slow(); + return; + } + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + } + + private void skipUtf8_4Slow() throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + } + + /* + /********************************************************************** + /* Content parsing + /********************************************************************** + */ + + @Override + protected void finishCData() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + char[] outputBuffer = _textBuilder.resetWithEmpty(); + int outPtr = 0; + + /* At this point, space (if any) has been skipped, and we are + * to parse and store the contents + */ + main_loop: while (true) { + int c; + // Then the tight ascii non-funny-char loop: + ascii_loop: while (true) { + int ptr = _inputPtr; + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + int max = _inputEnd; + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + outputBuffer[outPtr++] = (char) c; + } + _inputPtr = ptr; + } + // And then exceptions: + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_RBRACKET: // close ']]>' marker? + /* Ok: let's just parse all consequtive right brackets, + * and see if followed by greater-than char. This because + * we can only push back at most one char at a time, and + * thus can't easily just check a subset + */ + int count = 0; // ignoring first one + byte b; + + do { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = _inputBuffer[_inputPtr]; + if (b != BYTE_RBRACKET) { + break; + } + ++_inputPtr; + ++count; + } while (true); + + // Was the marker found? + boolean ok = (b == BYTE_GT && count >= 1); + if (ok) { + --count; + } + // Brackets to copy to output? + for (; count > 0; --count) { + outputBuffer[outPtr++] = ']'; + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + } + if (ok) { + ++_inputPtr; // to consume '>' + break main_loop; + } + break; + } + // Ok, can output the char; there's room for one char at least + outputBuffer[outPtr++] = (char) c; + } + + _textBuilder.setCurrentLength(outPtr); + /* 03-Feb-2009, tatu: To support coalescing mode, may need to + * do some extra work + */ + if (_cfgCoalescing && !_entityPending) { + finishCoalescedText(); + } + } + + @Override + protected void finishCharacters() throws XMLStreamException { + int outPtr; + int c; + char[] outputBuffer; + + // Ok, so what was the first char / entity? + c = _tmpChar; + if (c < 0) { // from entity; can just copy as is + c = -c; + outputBuffer = _textBuilder.resetWithEmpty(); + outPtr = 0; + if ((c >> 16) != 0) { // surrogate pair? + c -= 0x10000; + /* Note: after resetting the buffer, it's known to have + * space for more than 2 chars we need to add + */ + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + } + outputBuffer[outPtr++] = (char) c; + } else { // white space that we are interested in? + if (c == INT_CR || c == INT_LF) { + ++_inputPtr; // wasn't advanced yet, in this case + outPtr = checkInTreeIndentation(c); + if (outPtr < 0) { + return; + } + // Above call also initializes the text builder appropriately + outputBuffer = _textBuilder.getBufferWithoutReset(); + } else { + outputBuffer = _textBuilder.resetWithEmpty(); + outPtr = 0; + } + } + + final int[] TYPES = _charTypes.TEXT_CHARS; + 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 >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + int max = _inputEnd; + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + outputBuffer[outPtr++] = (char) c; + } + _inputPtr = ptr; + } + // And then fallback for funny chars / UTF-8 multibytes: + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + if ((_inputEnd - _inputPtr) >= 2) { + c = decodeUtf8_3fast(c); + } else { + c = decodeUtf8_3(c); + } + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_LT: + --_inputPtr; + break main_loop; + + case XmlCharTypes.CT_AMP: + c = handleEntityInText(); + if (c == 0) { // unexpandable general parsed entity + // _inputPtr set by entity expansion method + _entityPending = true; + break main_loop; + } + // Ok; does it need a surrogate though? (over 16 bits) + if ((c >> 16) != 0) { + c -= 0x10000; + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + // Need to ensure room for one more char + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + } + break; + + case XmlCharTypes.CT_RBRACKET: // ']]>'? + { + // Let's then just count number of brackets -- + // in case they are not followed by '>' + int count = 1; + byte b; + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = inputBuffer[_inputPtr]; + if (b != BYTE_RBRACKET) { + break; + } + ++_inputPtr; // to skip past bracket + ++count; + } + if (b == BYTE_GT && count > 1) { + reportIllegalCDataEnd(); + } + // Nope. Need to output all brackets, then; except + // for one that can be left for normal output + while (count > 1) { + outputBuffer[outPtr++] = ']'; + // Need to ensure room for one more char + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + --count; + } + } + // Can just output the first ']' along normal output + break; + + // default: + // Other types are not important here... + } + // We know there's room for one more: + outputBuffer[outPtr++] = (char) c; + } + + _textBuilder.setCurrentLength(outPtr); + + /* 03-Feb-2009, tatu: To support coalescing mode, may need to + * do some extra work + */ + if (_cfgCoalescing && !_entityPending) { + finishCoalescedText(); + } + } + + @Override + protected void finishComment() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + char[] outputBuffer = _textBuilder.resetWithEmpty(); + int outPtr = 0; + + main_loop: while (true) { + int c; + // Then the tight ascii non-funny-char loop: + ascii_loop: while (true) { + int ptr = _inputPtr; + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + int max = _inputEnd; + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + outputBuffer[outPtr++] = (char) c; + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_HYPHEN: // '-->'? + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_HYPHEN) { // ok, must be end then + ++_inputPtr; + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr++] != BYTE_GT) { + reportDoubleHyphenInComments(); + } + break main_loop; + } + break; + // default: + // Other types are not important here... + } + + // Ok, can output the char (we know there's room for one more) + outputBuffer[outPtr++] = (char) c; + } + _textBuilder.setCurrentLength(outPtr); + } + + /** + * When this method gets called we know that we have an internal subset, + * and that the opening '[' has already been read. + */ + @Override + protected void finishDTD(boolean copyContents) throws XMLStreamException { + char[] outputBuffer = copyContents ? _textBuilder.resetWithEmpty() : null; + int outPtr = 0; + + final int[] TYPES = _charTypes.DTD_CHARS; + boolean inDecl = false; // in declaration/directive? + int quoteChar = 0; // inside quoted string? + + main_loop: while (true) { + int c; + + /* First we'll have a quickie loop for speeding through + * uneventful chars... + */ + ascii_loop: while (true) { + int ptr = _inputPtr; + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + int max = _inputEnd; + if (outputBuffer != null) { + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + } + while (ptr < max) { + c = (int) _inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + if (outputBuffer != null) { + outputBuffer[outPtr++] = (char) c; + } + } + _inputPtr = ptr; + } + + switch (TYPES[c]) { + + // First, common types + + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + if (outputBuffer != null) { + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + c = 0xDC00 | (c & 0x3FF); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + // And let the other char output down below + } + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + + // Then DTD-specific types: + + case XmlCharTypes.CT_DTD_QUOTE: // apos or quot + if (quoteChar == 0) { + quoteChar = c; + } else { + if (quoteChar == c) { + quoteChar = 0; + } + } + break; + + case XmlCharTypes.CT_DTD_LT: + if (!inDecl) { + inDecl = true; + } + break; + + case XmlCharTypes.CT_DTD_GT: + if (quoteChar == 0) { + inDecl = false; + } + break; + + case XmlCharTypes.CT_DTD_RBRACKET: + if (!inDecl && quoteChar == 0) { + break main_loop; + } + break; + + // default: + // Other types are not important here... + } + + if (outputBuffer != null) { // will have room for one more + outputBuffer[outPtr++] = (char) c; + } + } + if (outputBuffer != null) { + _textBuilder.setCurrentLength(outPtr); + } + + // but still need to match the '>'... + byte b = skipInternalWs(false, null); + if (b != BYTE_GT) { + throwUnexpectedChar(decodeCharForError(b), " expected '>' after the internal subset"); + } + } + + @Override + protected void finishPI() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + char[] outputBuffer = _textBuilder.resetWithEmpty(); + int outPtr = 0; + + /* At this point, space (if any) has been skipped, and we are + * to parse and store the contents + */ + main_loop: while (true) { + int c; + // Then the tight ascii non-funny-char loop: + ascii_loop: while (true) { + int ptr = _inputPtr; + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + int max = _inputEnd; + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + outputBuffer[outPtr++] = (char) c; + } + _inputPtr = ptr; + } + // And then exceptions: + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_QMARK: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (_inputBuffer[_inputPtr] == BYTE_GT) { // ok, the end! + ++_inputPtr; + break main_loop; + } + // Not end mark, just need to reprocess the second char + // default: + // Other types are not important here... + } + // Ok, can output the char (we know there's room for one more) + outputBuffer[outPtr++] = (char) c; + } + _textBuilder.setCurrentLength(outPtr); + } + + /** + * Note: this method is only called in cases where it is known + * that only space chars are legal. Thus, encountering a non-space + * is an error (WFC or VC). However, an end-of-input is ok. + */ + @Override + protected void finishSpace() throws XMLStreamException { + /* Ok: so, mTmpChar contains first space char. If it looks + * like indentation, we can probably optimize a bit... + */ + int tmp = _tmpChar; + char[] outputBuffer; + int outPtr; + + if (tmp == BYTE_CR || tmp == BYTE_LF) { + outPtr = checkPrologIndentation(tmp); + if (outPtr < 0) { + return; + } + // Above call also initializes the text builder appropriately + outputBuffer = _textBuilder.getBufferWithoutReset(); + } else { + outputBuffer = _textBuilder.resetWithEmpty(); + outputBuffer[0] = (char) tmp; + outPtr = 1; + } + + int ptr = _inputPtr; + + while (true) { + if (ptr >= _inputEnd) { + if (!loadMore()) { + break; + } + ptr = _inputPtr; + } + int c = (int) _inputBuffer[ptr] & 0xFF; + // !!! TODO: check for xml 1.1 whitespace? + if (c > INT_SPACE) { + break; + } + ++ptr; + + if (c == INT_LF) { + markLF(ptr); + } else if (c == INT_CR) { + if (ptr >= _inputEnd) { + if (!loadMore()) { // still need to output the lf + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + outputBuffer[outPtr++] = '\n'; + break; + } + ptr = _inputPtr; + } + if (_inputBuffer[ptr] == BYTE_LF) { + ++ptr; + } + markLF(ptr); + c = INT_LF; // need to convert to canonical lf + } else if (c != INT_SPACE && c != INT_TAB) { + _inputPtr = ptr; + throwInvalidSpace(c); + } + + // Ok, can output the char + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + outputBuffer[outPtr++] = (char) c; + } + + _inputPtr = ptr; + _textBuilder.setCurrentLength(outPtr); + } + + /* + /********************************************************************** + /* 2nd level parsing/skipping for coalesced text + /********************************************************************** + */ + + /** + * Method that gets called after a primary text segment (of type + * CHARACTERS or CDATA, not applicable to SPACE) has been read in + * text buffer. Method has to see if the following event would + * be textual as well, and if so, read it (and any other following + * textual segments). + */ + private void finishCoalescedText() throws XMLStreamException { + while (true) { + // no matter what, will need (and can get) one char + if (_inputPtr >= _inputEnd) { + if (!loadMore()) { // most likely an error, will be handled later on + return; + } + } + + if (_inputBuffer[_inputPtr] == BYTE_LT) { // markup of some kind + /* In worst case, need 3 chars ("= _inputEnd) { + if (!loadAndRetain()) { + // probably an error, but will be handled later + return; + } + } + if (_inputBuffer[_inputPtr + 1] != BYTE_EXCL || _inputBuffer[_inputPtr + 2] != BYTE_LBRACKET) { + // can't be CDATA, we are done here + return; + } + // but let's verify it still: + _inputPtr += 3; + for (int i = 0; i < 6; ++i) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + byte b = _inputBuffer[_inputPtr++]; + if (b != (byte) CDATA_STR.charAt(i)) { + int ch = decodeCharForError(b); + reportTreeUnexpChar(ch, " (expected '" + CDATA_STR.charAt(i) + "' for CDATA section)"); + } + } + finishCoalescedCData(); + } else { // textual (or entity, error etc) + finishCoalescedCharacters(); + if (_entityPending) { + break; + } + } + } + } + + // note: code mostly copied from 'finishCharacters', just simplified + // in some places + private void finishCoalescedCharacters() throws XMLStreamException { + // first char can't be from (char) entity (wrt finishCharacters) + + final int[] TYPES = _charTypes.TEXT_CHARS; + final byte[] inputBuffer = _inputBuffer; + + char[] outputBuffer = _textBuilder.getBufferWithoutReset(); + int outPtr = _textBuilder.getCurrentLength(); + + int c; + + 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 >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + int max = _inputEnd; + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + outputBuffer[outPtr++] = (char) c; + } + _inputPtr = ptr; + } + // And then fallback for funny chars / UTF-8 multibytes: + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + if ((_inputEnd - _inputPtr) >= 2) { + c = decodeUtf8_3fast(c); + } else { + c = decodeUtf8_3(c); + } + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_LT: + --_inputPtr; + break main_loop; + + case XmlCharTypes.CT_AMP: + c = handleEntityInText(); + if (c == 0) { // unexpandable general parsed entity + // _inputPtr set by entity expansion method + _entityPending = true; + break main_loop; + } + // Ok; does it need a surrogate though? (over 16 bits) + if ((c >> 16) != 0) { + c -= 0x10000; + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + // Need to ensure room for one more char + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + } + break; + + case XmlCharTypes.CT_RBRACKET: // ']]>'? + { + // Let's then just count number of brackets -- + // in case they are not followed by '>' + int count = 1; + byte b; + while (true) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = inputBuffer[_inputPtr]; + if (b != BYTE_RBRACKET) { + break; + } + ++_inputPtr; // to skip past bracket + ++count; + } + if (b == BYTE_GT && count > 1) { + reportIllegalCDataEnd(); + } + // Nope. Need to output all brackets, then; except + // for one that can be left for normal output + while (count > 1) { + outputBuffer[outPtr++] = ']'; + // Need to ensure room for one more char + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + --count; + } + } + // Can just output the first ']' along normal output + break; + + // default: + // Other types are not important here... + } + // We know there's room for one more: + outputBuffer[outPtr++] = (char) c; + } + + _textBuilder.setCurrentLength(outPtr); + } + + // note: code mostly copied from 'finishCharacters', just simplified + // in some places + private void finishCoalescedCData() throws XMLStreamException { + final int[] TYPES = _charTypes.OTHER_CHARS; + final byte[] inputBuffer = _inputBuffer; + + char[] outputBuffer = _textBuilder.getBufferWithoutReset(); + int outPtr = _textBuilder.getCurrentLength(); + + /* At this point, space (if any) has been skipped, and we are + * to parse and store the contents + */ + main_loop: while (true) { + int c; + // Then the tight ascii non-funny-char loop: + ascii_loop: while (true) { + int ptr = _inputPtr; + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + int max = _inputEnd; + { + int max2 = ptr + (outputBuffer.length - outPtr); + if (max2 < max) { + max = max2; + } + } + while (ptr < max) { + c = (int) inputBuffer[ptr++] & 0xFF; + if (TYPES[c] != 0) { + _inputPtr = ptr; + break ascii_loop; + } + outputBuffer[outPtr++] = (char) c; + } + _inputPtr = ptr; + } + // And then exceptions: + switch (TYPES[c]) { + case XmlCharTypes.CT_INVALID: + handleInvalidXmlChar(c); + case XmlCharTypes.CT_WS_CR: + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + if (inputBuffer[_inputPtr] == BYTE_LF) { + ++_inputPtr; + } + markLF(); + c = INT_LF; + break; + + case XmlCharTypes.CT_WS_LF: + markLF(); + break; + + case XmlCharTypes.CT_MULTIBYTE_2: + c = decodeUtf8_2(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_3: + c = decodeUtf8_3(c); + break; + + case XmlCharTypes.CT_MULTIBYTE_4: + c = decodeUtf8_4(c); + // Let's add first part right away: + outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + c = 0xDC00 | (c & 0x3FF); + // And let the other char output down below + break; + + case XmlCharTypes.CT_MULTIBYTE_N: + reportInvalidInitial(c); + case XmlCharTypes.CT_RBRACKET: // close ']]>' marker? + /* Ok: let's just parse all consequtive right brackets, + * and see if followed by greater-than char. This because + * we can only push back at most one char at a time, and + * thus can't easily just check a subset + */ + int count = 0; // ignoring first one + byte b; + + do { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + b = _inputBuffer[_inputPtr]; + if (b != BYTE_RBRACKET) { + break; + } + ++_inputPtr; + ++count; + } while (true); + + // Was the marker found? + boolean ok = (b == BYTE_GT && count >= 1); + if (ok) { + --count; + } + // Brackets to copy to output? + for (; count > 0; --count) { + outputBuffer[outPtr++] = ']'; + if (outPtr >= outputBuffer.length) { + outputBuffer = _textBuilder.finishCurrentSegment(); + outPtr = 0; + } + } + if (ok) { + ++_inputPtr; // to consume '>' + break main_loop; + } + break; + } + // Ok, can output the char; there's room for one char at least + outputBuffer[outPtr++] = (char) c; + } + + _textBuilder.setCurrentLength(outPtr); + } + + /** + * Method that gets called after a primary text segment (of type + * CHARACTERS or CDATA, not applicable to SPACE) has been skipped. + * Method has to see if the following event would + * be textual as well, and if so, skip it (and any other following + * textual segments). + * + * @return True if we encountered an unexpandable entity + */ + @Override + protected boolean skipCoalescedText() throws XMLStreamException { + while (true) { + // no matter what, will need (and can get) one char + if (_inputPtr >= _inputEnd) { + if (!loadMore()) { // most likely an error, will be handled later on + return false; + } + } + + if (_inputBuffer[_inputPtr] == BYTE_LT) { // markup of some kind + /* In worst case, need 3 chars ("= _inputEnd) { + if (!loadAndRetain()) { // probably an error, but will be handled later + return false; + } + } + if (_inputBuffer[_inputPtr + 1] != BYTE_EXCL || _inputBuffer[_inputPtr + 2] != BYTE_LBRACKET) { + // can't be CDATA, we are done here + return false; + } + // but let's verify it still: + _inputPtr += 3; + for (int i = 0; i < 6; ++i) { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + byte b = _inputBuffer[_inputPtr++]; + if (b != (byte) CDATA_STR.charAt(i)) { + int ch = decodeCharForError(b); + reportTreeUnexpChar(ch, " (expected '" + CDATA_STR.charAt(i) + "' for CDATA section)"); + } + } + skipCData(); + } else { // textual (or entity, error etc) + if (skipCharacters()) { + return true; + } + } + } + } + + /* + /********************************************************************** + /* Other methods, utf-decoding + /********************************************************************** + */ + + /** + * @return Either decoded character (if positive int); or negated + * value of a high-order char (one that needs surrogate pair) + */ + private int decodeMultiByteChar(int c, int ptr) throws XMLStreamException { + int needed; + + 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 + } + + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + int d = _inputBuffer[ptr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, ptr); + } + c = (c << 6) | (d & 0x3F); + + if (needed > 1) { // needed == 1 means 2 bytes total + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + d = _inputBuffer[ptr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, ptr); + } + c = (c << 6) | (d & 0x3F); + if (needed > 2) { // 4 bytes? (need surrogates) + if (ptr >= _inputEnd) { + loadMoreGuaranteed(); + ptr = _inputPtr; + } + d = _inputBuffer[ptr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, ptr); + } + c = (c << 6) | (d & 0x3F); + /* Need to signal such pair differently (to make comparison + * easier) + */ + c = -c; + } + } + _inputPtr = ptr; + return c; + } + + private int decodeUtf8_2(int c) throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + return ((c & 0x1F) << 6) | (d & 0x3F); + } + + private int decodeUtf8_3(int c1) throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + c1 &= 0x0F; + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + int c = (c1 << 6) | (d & 0x3F); + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + c = (c << 6) | (d & 0x3F); + if (c1 >= 0xD) { // 0xD800-0xDFFF, 0xFFFE-0xFFFF illegal + if (c >= 0xD800) { // surrogates illegal, as well as 0xFFFE/0xFFFF + if (c < 0xE000 || c >= 0xFFFE) { + c = handleInvalidXmlChar(c); + } + } + } + return c; + } + + private int decodeUtf8_3fast(int c1) throws XMLStreamException { + c1 &= 0x0F; + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + int c = (c1 << 6) | (d & 0x3F); + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + c = (c << 6) | (d & 0x3F); + if (c1 >= 0xD) { // 0xD800-0xDFFF, 0xFFFE-0xFFFF illegal + if (c >= 0xD800) { // surrogates illegal, as well as 0xFFFE/0xFFFF + if (c < 0xE000 || c >= 0xFFFE) { + c = handleInvalidXmlChar(c); + } + } + } + return c; + } + + /** + * @return Character value minus 0x10000; this so that caller + * can readily expand it to actual surrogates + */ + private int decodeUtf8_4(int c) throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + int d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + c = ((c & 0x07) << 6) | (d & 0x3F); + + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + d = _inputBuffer[_inputPtr++]; + if ((d & 0xC0) != 0x080) { + reportInvalidOther(d & 0xFF, _inputPtr); + } + c = (c << 6) | (d & 0x3F); + if (_inputPtr >= _inputEnd) { + loadMoreGuaranteed(); + } + d = _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; + } + + /* + /********************************************************************** + /* Internal methods, error reporting + /********************************************************************** + */ + + /** + * Method called called to decode a full UTF-8 characters, given + * its first byte. Note: does not do any validity checks, since this + * is only to be used for informational purposes (often when an error + * has already been encountered) + */ + public int decodeCharForError(byte b) throws XMLStreamException { + int c = b; + if (c >= 0) { // ascii? fine as is... + return c; + } + 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; + } + + private void reportInvalidOther(int mask, int ptr) throws XMLStreamException { + _inputPtr = ptr; + reportInvalidOther(mask); + } + + /* + /********************************************************************** + /* Internal methods, secondary parsing + /********************************************************************** + */ + + @Override + protected void finishToken() throws XMLStreamException { + _tokenIncomplete = false; + switch (_currToken) { + case PROCESSING_INSTRUCTION: + finishPI(); + break; + + case CHARACTERS: + finishCharacters(); + break; + + case COMMENT: + finishComment(); + break; + + case SPACE: + finishSpace(); + break; + + case DTD: + finishDTD(true); // true -> get text + break; + + case CDATA: + finishCData(); + break; + + default: + ErrorConsts.throwInternalError(); + } + } + + private byte nextByte() throws XMLStreamException { + if (_inputPtr >= _inputEnd) { + if (!loadMore()) { + reportInputProblem( + "Unexpected end-of-input when trying to parse " + ErrorConsts.tokenTypeDesc(_currToken)); + } + } return _inputBuffer[_inputPtr++]; } - protected final byte loadOne() throws XMLStreamException { + private byte loadOne() throws XMLStreamException { if (!loadMore()) { reportInputProblem("Unexpected end-of-input when trying to parse " + ErrorConsts.tokenTypeDesc(_currToken)); } return _inputBuffer[_inputPtr++]; } - protected final byte loadOne(int type) throws XMLStreamException { + private byte loadOne(int type) throws XMLStreamException { if (!loadMore()) { reportInputProblem("Unexpected end-of-input when trying to parse " + ErrorConsts.tokenTypeDesc(type)); } return _inputBuffer[_inputPtr++]; } - protected final boolean loadAndRetain() throws XMLStreamException { + private boolean loadAndRetain() throws XMLStreamException { /* first: can't move, if we were handed an immutable block * (alternative to handing InputStream as _in) */ @@ -1343,7 +4034,246 @@ protected final boolean loadAndRetain() throws XMLStreamException { } while (_inputEnd < 3); return true; } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); + } + } + + /** + * Conceptually, this method really does NOT belong here. However, + * currently it is quite hard to refactor it, so it'll have to + * stay here until better place is found + */ + private PName addUTFPName(ByteBasedPNameTable symbols, XmlCharTypes charTypes, int hash, int[] quads, int qlen, + int lastQuadBytes) throws XMLStreamException { + // 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; + } + + // Let's handle first char separately (different validation): + int ch = (quads[0] >>> 24); + boolean ok; + int ix = 1; + char[] cbuf = _nameBuffer; + int cix = 0; + final int[] TYPES = charTypes.NAME_CHARS; + + switch (TYPES[ch]) { + case XmlCharTypes.CT_NAME_NONE: + case XmlCharTypes.CT_NAME_COLON: // not ok as first + case XmlCharTypes.CT_NAME_NONFIRST: + case InputCharTypes.CT_INPUT_NAME_MB_N: + ok = false; + break; + + case XmlCharTypes.CT_NAME_ANY: + ok = true; + break; + + default: // multi-byte (UTF-8) chars: + { + 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) { + reportEofInName(); + } + ix += needed; + + int q = quads[0]; + // Always need at least one more right away: + int ch2 = (q >> 16) & 0xFF; + if ((ch2 & 0xC0) != 0x080) { + reportInvalidOther(ch2); + } + ch = (ch << 6) | (ch2 & 0x3F); + + /* And then may need more. Note: here we do not do all the + * checks that UTF-8 text decoder might do. Reason is that + * name validity checking methods handle most of such checks + */ + if (needed > 1) { + ch2 = (q >> 8) & 0xFF; + if ((ch2 & 0xC0) != 0x080) { + reportInvalidOther(ch2); + } + ch = (ch << 6) | (ch2 & 0x3F); + if (needed > 2) { // 4 bytes? (need surrogates on output) + ch2 = q & 0xFF; + if ((ch2 & 0xC0) != 0x080) { + reportInvalidOther(ch2 & 0xFF); + } + ch = (ch << 6) | (ch2 & 0x3F); + } + } + ok = XmlChars.is10NameStartChar(ch); + if (needed > 2) { // outside of basic 16-bit range? need surrogates + /* so, let's first output first char (high surrogate), + * let second be output by later code + */ + ch -= 0x10000; // to normalize it starting with 0x0 + cbuf[cix++] = (char) (0xD800 + (ch >> 10)); + ch = (0xDC00 | (ch & 0x03FF)); + } + } + } + + if (!ok) { // 0 to indicate it's first char, even with surrogates + reportInvalidNameChar(ch, 0); + } + + cbuf[cix++] = (char) ch; // the only char, or second (low) surrogate + + /* Whoa! Tons of code for just the start char. But now we get to + * decode the name proper, at last! + */ + int last_colon = -1; + + while (ix < byteLen) { + ch = quads[ix >> 2]; // current quad, need to shift+mask + int byteIx = (ix & 3); + ch = (ch >> ((3 - byteIx) << 3)) & 0xFF; + ++ix; + + // Ascii? + switch (TYPES[ch]) { + case XmlCharTypes.CT_NAME_NONE: + case XmlCharTypes.CT_MULTIBYTE_N: + ok = false; + break; + + case XmlCharTypes.CT_NAME_COLON: // not ok as first + if (last_colon >= 0) { + reportMultipleColonsInName(); + } + last_colon = cix; + ok = true; + break; + + case XmlCharTypes.CT_NAME_NONFIRST: + case XmlCharTypes.CT_NAME_ANY: + ok = true; + break; + + default: { + 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) { + reportEofInName(); + } + + // 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); + + // Once again, some of validation deferred to name char validator + 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); + } + } + ok = XmlChars.is10NameChar(ch); + 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) { + _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); + } + cbuf[cix++] = (char) (0xD800 + (ch >> 10)); + ch = 0xDC00 | (ch & 0x03FF); + } + } + } + if (!ok) { + reportInvalidNameChar(ch, cix); + } + if (cix >= cbuf.length) { + _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); + } + cbuf[cix++] = (char) ch; } + + /* Ok. Now we have the character array, and can construct the + * String (as well as check proper composition of semicolons + * for ns-aware mode...) + */ + String baseName = new String(cbuf, 0, cix); + // And finally, unalign if necessary + if (lastQuadBytes < 4) { + quads[qlen - 1] = lastQuad; + } + return symbols.addSymbol(hash, baseName, last_colon, quads, qlen); + } + + /* + /********************************************************************** + /* Error reporting + /********************************************************************** + */ + + private void reportInvalidInitial(int mask) throws XMLStreamException { + reportInputProblem("Invalid UTF-8 start byte 0x" + Integer.toHexString(mask)); + } + + private void reportInvalidOther(int mask) throws XMLStreamException { + reportInputProblem("Invalid UTF-8 middle byte 0x" + Integer.toHexString(mask)); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf32Reader.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf32Reader.java index 84f0de150e89..d9067b5cc2e6 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf32Reader.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf32Reader.java @@ -24,36 +24,36 @@ * Since JDK does not come with UTF-32/UCS-4, let's implement a simple * decoder to use. */ -public class Utf32Reader extends Reader { +public final class Utf32Reader extends Reader { private final static char NULL_CHAR = (char) 0; - protected final ReaderConfig mConfig; + private final ReaderConfig mConfig; - protected InputStream mIn; + private InputStream mIn; - protected byte[] mBuffer; + private byte[] mBuffer; - protected int mPtr; - protected int mLength; + private int mPtr; + private int mLength; - protected final boolean mBigEndian; + private final boolean mBigEndian; /** * 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 mSurrogate = NULL_CHAR; + private char mSurrogate = NULL_CHAR; /** * Total read character count; used for error reporting purposes */ - protected int mCharCount = 0; + private int mCharCount = 0; /** * Total read byte count; used for error reporting purposes */ - protected int mByteCount = 0; + private int mByteCount = 0; /* /********************************************************************** @@ -250,7 +250,7 @@ private boolean loadMore(int available) throws IOException { return true; } - public final void freeBuffers() { + public void freeBuffers() { byte[] buf = mBuffer; if (buf != null) { mBuffer = null; @@ -282,11 +282,11 @@ private void reportInvalid(int value, int offset, String msg) throws IOException + " at char #" + charPos + ", byte #" + bytePos + ")"); } - protected void reportBounds(char[] cbuf, int start, int len) { + private void reportBounds(char[] cbuf, int start, int len) { throw new ArrayIndexOutOfBoundsException("read(buf," + start + "," + len + "), cbuf[" + cbuf.length + "]"); } - protected void reportStrangeStream() throws IOException { + private void reportStrangeStream() throws IOException { throw new IOException("Strange I/O stream, returned 0 bytes on read"); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf8Scanner.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf8Scanner.java deleted file mode 100644 index 2c7162f75cb2..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/Utf8Scanner.java +++ /dev/null @@ -1,2653 +0,0 @@ -// Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. -/* Aalto XML processor - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in the file LICENSE which is - * included with the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.azure.xml.implementation.aalto.in; - -import java.io.*; -import java.util.Objects; - -import javax.xml.stream.XMLStreamException; - -import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.util.DataUtil; -import com.azure.xml.implementation.aalto.util.XmlCharTypes; -import com.azure.xml.implementation.aalto.util.XmlChars; - -/** - * Scanner for tokenizing XML content from a byte stream encoding using - * UTF-8 encoding, or something suitably close it for decoding purposes - * (including ISO-Latin1 and US-ASCII). - */ -@SuppressWarnings("fallthrough") -public final class Utf8Scanner extends StreamScanner { - /* - /********************************************************************** - /* Life-cycle - /********************************************************************** - */ - - public Utf8Scanner(ReaderConfig cfg, InputStream in, byte[] buffer, int ptr, int last) { - super(cfg, in, buffer, ptr, last); - } - - /* - /********************************************************************** - /* Internal methods, secondary parsing - /********************************************************************** - */ - - @Override - protected void finishToken() throws XMLStreamException { - _tokenIncomplete = false; - switch (_currToken) { - case PROCESSING_INSTRUCTION: - finishPI(); - break; - - case CHARACTERS: - finishCharacters(); - break; - - case COMMENT: - finishComment(); - break; - - case SPACE: - finishSpace(); - break; - - case DTD: - finishDTD(true); // true -> get text - break; - - case CDATA: - finishCData(); - break; - - default: - ErrorConsts.throwInternalError(); - } - } - - @Override - protected int handleStartElement(byte b) throws XMLStreamException { - _currToken = START_ELEMENT; - _currNsCount = 0; - PName elemName = parsePName(b); - - /* Ok. Need to create a qualified name. Simplest for element - * in default ns (no extra work -- expressed as null binding); - * otherwise need to find binding - */ - String prefix = elemName.getPrefix(); - boolean allBound; // flag to check 'late' bindings - - if (prefix == null) { // element in default ns - allBound = true; // which need not be bound - } else { - elemName = bindName(elemName, prefix); - allBound = elemName.isBound(); - } - - _tokenName = elemName; - _currElem = new ElementScope(elemName, _currElem); - - // And then attribute parsing loop: - int attrPtr = 0; - - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr++]; - int c = (int) b & 0xFF; - // Intervening space to skip? - if (c <= INT_SPACE) { - do { - if (c == INT_LF) { - markLF(); - } else if (c == INT_CR) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - } else if (c != INT_SPACE && c != INT_TAB) { - throwInvalidSpace(c); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr++]; - c = (int) b & 0xFF; - } while (c <= INT_SPACE); - } else if (c != INT_SLASH && c != INT_GT) { - c = decodeCharForError(b); - throwUnexpectedChar(c, " expected space, or '>' or \"/>\""); - } - - // Ok; either need to get an attribute name, or end marker: - if (c == INT_SLASH) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr++]; - if (b != BYTE_GT) { - c = decodeCharForError(b); - throwUnexpectedChar(c, " expected '>'"); - } - _isEmptyTag = true; - break; - } else if (c == INT_GT) { - _isEmptyTag = false; - break; - } else if (c == INT_LT) { - reportInputProblem("Unexpected '<' character in element (missing closing '>'?)"); - } - - // Ok, an attr name: - PName attrName = parsePName(b); - prefix = attrName.getPrefix(); - - boolean isNsDecl; - - if (prefix == null) { // can be default ns decl: - isNsDecl = (Objects.equals(attrName.getLocalName(), "xmlns")); - } else { - // May be a namespace decl though? - if (prefix.equals("xmlns")) { - isNsDecl = true; - } else { - attrName = bindName(attrName, prefix); - if (allBound) { - allBound = attrName.isBound(); - } - isNsDecl = false; - } - } - - // Optional space to skip again - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr++]; - c = (int) b & 0xFF; - if (c > INT_SPACE) { - break; - } - if (c == INT_LF) { - markLF(); - } else if (c == INT_CR) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - } else if (c != INT_SPACE && c != INT_TAB) { - throwInvalidSpace(c); - } - } - - if (c != INT_EQ) { - c = decodeCharForError(b); - throwUnexpectedChar(c, " expected '='"); - } - - // Optional space to skip again - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr++]; - c = (int) b & 0xFF; - if (c > INT_SPACE) { - break; - } - if (c == INT_LF) { - markLF(); - } else if (c == INT_CR) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - } else if (c != INT_SPACE && c != INT_TAB) { - throwInvalidSpace(c); - } - } - - if (c != INT_QUOTE && c != INT_APOS) { - c = decodeCharForError(b); - throwUnexpectedChar(c, " Expected a quote"); - } - - /* Ok, finally: value parsing. However, ns URIs are to be handled - * different from attribute values... let's offline URIs, since - * they should be less common than attribute values. - */ - if (isNsDecl) { // default ns, or explicit? - handleNsDeclaration(attrName, b); - ++_currNsCount; - } else { // nope, a 'real' attribute: - attrPtr = collectValue(attrPtr, b, attrName); - } - } - { - // Note: this call also checks attribute uniqueness - int act = _attrCollector.finishLastValue(attrPtr); - if (act < 0) { // error, dup attr indicated by -1 - act = _attrCollector.getCount(); // let's get correct count - reportInputProblem(_attrCollector.getErrorMsg()); - } - _attrCount = act; - } - ++_depth; - - /* Was there any prefix that wasn't bound prior to use? - * That's legal, assuming declaration was found later on... - * let's check - */ - if (!allBound) { - if (!elemName.isBound()) { // element itself unbound - reportUnboundPrefix(_tokenName, false); - } - for (int i = 0, len = _attrCount; i < len; ++i) { - PName attrName = _attrCollector.getName(i); - if (!attrName.isBound()) { - reportUnboundPrefix(attrName, true); - } - } - } - return START_ELEMENT; - } - - /** - * This method implements the tight loop for parsing attribute - * values. It's off-lined from the main start element method to - * simplify main method, which makes code more maintainable - * and possibly easier for JIT/HotSpot to optimize. - */ - private int collectValue(int attrPtr, byte quoteByte, PName attrName) throws XMLStreamException { - char[] attrBuffer = _attrCollector.startNewValue(attrName, attrPtr); - final int[] TYPES = _charTypes.ATTR_CHARS; - - value_loop: while (true) { - int c; - - ascii_loop: while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - if (attrPtr >= attrBuffer.length) { - attrBuffer = _attrCollector.valueBufferFull(); - } - int max = _inputEnd; - { - int max2 = ptr + (attrBuffer.length - attrPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) _inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - attrBuffer[attrPtr++] = (char) c; - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - // fall through - case XmlCharTypes.CT_WS_LF: - markLF(); - // fall through - case XmlCharTypes.CT_WS_TAB: - // Plus, need to convert these all to simple space - c = INT_SPACE; - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - if (attrPtr >= attrBuffer.length) { - attrBuffer = _attrCollector.valueBufferFull(); - } - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_LT: - throwUnexpectedChar(c, "'<' not allowed in attribute value"); - case XmlCharTypes.CT_AMP: - c = handleEntityInText(); - if (c == 0) { // unexpanded general entity... not good - reportUnexpandedEntityInAttr(false); - } - // Ok; does it need a surrogate though? (over 16 bits) - if ((c >> 16) != 0) { - c -= 0x10000; - attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - if (attrPtr >= attrBuffer.length) { - attrBuffer = _attrCollector.valueBufferFull(); - } - } - break; - - case XmlCharTypes.CT_ATTR_QUOTE: - if (c == (int) quoteByte) { - break value_loop; - } - - // default: - // Other chars are not important here... - } - // We know there's room for at least one char without checking - attrBuffer[attrPtr++] = (char) c; - } - - return attrPtr; - } - - /** - * Method called from the main START_ELEMENT handling loop, to - * parse namespace URI values. - */ - private void handleNsDeclaration(PName name, byte quoteByte) throws XMLStreamException { - int attrPtr = 0; - char[] attrBuffer = _nameBuffer; - - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - byte b = _inputBuffer[_inputPtr++]; - if (b == quoteByte) { - break; - } - int c; - if (b == BYTE_AMP) { // entity - c = handleEntityInText(); - if (c == 0) { // general entity; should never happen - reportUnexpandedEntityInAttr(true); - } - // Ok; does it need a surrogate though? (over 16 bits) - if ((c >> 16) != 0) { - if (attrPtr >= attrBuffer.length) { - _nameBuffer = attrBuffer = DataUtil.growArrayBy(attrBuffer, attrBuffer.length); - } - c -= 0x10000; - attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - } - } else if (b == BYTE_LT) { // error - c = b; - throwUnexpectedChar(c, "'<' not allowed in attribute value"); - } else { - c = (int) b & 0xFF; - if (c < INT_SPACE) { - if (c == INT_LF) { - markLF(); - } else if (c == INT_CR) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - } else if (c != INT_TAB) { - throwInvalidSpace(c); - } - } else if (c > 0x7F) { - c = decodeMultiByteChar(c, _inputPtr); - if (c < 0) { // surrogate pair - c = -c; - // Let's add first part right away: - if (attrPtr >= attrBuffer.length) { - _nameBuffer = attrBuffer = DataUtil.growArrayBy(attrBuffer, attrBuffer.length); - } - c -= 0x10000; - attrBuffer[attrPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - } - } - } - if (attrPtr >= attrBuffer.length) { - _nameBuffer = attrBuffer = DataUtil.growArrayBy(attrBuffer, attrBuffer.length); - } - attrBuffer[attrPtr++] = (char) c; - } - - /* Simple optimization: for default ns removal (or, with - * ns 1.1, any other as well), will use empty value... no - * need to try to intern: - */ - if (attrPtr == 0) { - bindNs(name, ""); - } else { - String uri = _config.canonicalizeURI(attrBuffer, attrPtr); - bindNs(name, uri); - } - } - - /** - * Method called when an ampersand is encounter in text segment. - * Method needs to determine whether it is a pre-defined or character - * entity (in which case it will be expanded into a single char or - * surrogate pair), or a general - * entity (in which case it will most likely be returned as - * ENTITY_REFERENCE event) - * - * @return 0 if a general parsed entity encountered; integer - * value of a (valid) XML content character otherwise - */ - @Override - protected int handleEntityInText() throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - byte b = _inputBuffer[_inputPtr++]; - if (b == BYTE_HASH) { - return handleCharEntity(); - } - String start; - if (b == BYTE_a) { // amp or apos? - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_m) { // amp? - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_p) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_SEMICOLON) { - return INT_AMP; - } - start = "amp"; - } else { - start = "am"; - } - } else if (b == BYTE_p) { // apos? - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_o) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_s) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_SEMICOLON) { - return INT_APOS; - } - start = "apos"; - } else { - start = "apo"; - } - } else { - start = "ap"; - } - } else { - start = "a"; - } - } else if (b == BYTE_l) { // lt? - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_t) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_SEMICOLON) { - return INT_LT; - } - start = "lt"; - } else { - start = "l"; - } - } else if (b == BYTE_g) { // gt? - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_t) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_SEMICOLON) { - return INT_GT; - } - start = "gt"; - } else { - start = "g"; - } - } else if (b == BYTE_q) { // quot? - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_u) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_o) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_t) { - b = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : loadOne(); - if (b == BYTE_SEMICOLON) { - return INT_QUOTE; - } - start = "quot"; - } else { - start = "quo"; - } - } else { - start = "qu"; - } - } else { - start = "q"; - } - } else { - start = ""; - } - - final int[] TYPES = _charTypes.NAME_CHARS; - - /* All righty: we have the beginning of the name, plus the first - * byte too. So let's see what we can do with it. - */ - char[] cbuf = _nameBuffer; - int cix = 0; - for (int len = start.length(); cix < len; ++cix) { - cbuf[cix] = start.charAt(cix); - } - //int colon = -1; - while (b != BYTE_SEMICOLON) { - boolean ok; - int c = (int) b & 0xFF; - - // Has to be a valid name start char though: - switch (TYPES[c]) { - case XmlCharTypes.CT_NAME_NONE: - case XmlCharTypes.CT_NAME_COLON: // not ok for entities? - case XmlCharTypes.CT_NAME_NONFIRST: - ok = (cix > 0); - break; - - case XmlCharTypes.CT_NAME_ANY: - ok = true; - break; - - case InputCharTypes.CT_INPUT_NAME_MB_2: - c = decodeUtf8_2(c); - ok = XmlChars.is10NameStartChar(c); - break; - - case InputCharTypes.CT_INPUT_NAME_MB_3: - c = decodeUtf8_3(c); - ok = XmlChars.is10NameStartChar(c); - break; - - case InputCharTypes.CT_INPUT_NAME_MB_4: - c = decodeUtf8_4(c); - ok = XmlChars.is10NameStartChar(c); - if (ok) { - if (cix >= cbuf.length) { - _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); - } - // Let's add first part right away: - c -= 0x10000; - cbuf[cix++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - } - break; - - case InputCharTypes.CT_INPUT_NAME_MB_N: - default: - ok = false; - break; - } - if (!ok) { - reportInvalidNameChar(c, cix); - } - if (cix >= cbuf.length) { - _nameBuffer = cbuf = DataUtil.growArrayBy(cbuf, cbuf.length); - } - cbuf[cix++] = (char) c; - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr++]; - } - - // Ok, let's construct a (temporary) entity name, then: - String pname = new String(cbuf, 0, cix); - // (note: hash is dummy... not to be compared to anything etc) - _tokenName = new PNameC(pname, null, pname, 0); - - /* One more thing: do we actually allow entities in this mode - * and with this event? - */ - if (_config.willExpandEntities()) { - reportInputProblem("General entity reference (&" + pname - + ";) encountered in entity expanding mode: operation not (yet) implemented"); - } - return 0; - } - - /* - /********************************************************************** - /* Internal methods, name parsing: - /********************************************************************** - */ - - /** - * Parsing of public ids is bit more complicated than that of system - * ids, since white space is to be coalesced. - */ - @Override - protected String parsePublicId(byte quoteChar) throws XMLStreamException { - char[] outputBuffer = _nameBuffer; - int outPtr = 0; - final int[] TYPES = XmlCharTypes.PUBID_CHARS; - boolean addSpace = false; - - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - // Easier to check without char type table, first: - byte b = _inputBuffer[_inputPtr++]; - if (b == quoteChar) { - break; - } - int c = (int) b & 0xFF; - if (TYPES[c] != XmlCharTypes.PUBID_OK) { - throwUnexpectedChar(c, " in public identifier"); - } - - // White space? Needs to be coalesced - if (c <= INT_SPACE) { - addSpace = true; - continue; - } - if (addSpace) { - if (outPtr >= outputBuffer.length) { - _nameBuffer = outputBuffer = DataUtil.growArrayBy(outputBuffer, outputBuffer.length); - outPtr = 0; - } - outputBuffer[outPtr++] = ' '; - addSpace = false; - } - if (outPtr >= outputBuffer.length) { - _nameBuffer = outputBuffer = DataUtil.growArrayBy(outputBuffer, outputBuffer.length); - outPtr = 0; - } - outputBuffer[outPtr++] = (char) c; - } - return new String(outputBuffer, 0, outPtr); - } - - @Override - protected String parseSystemId(byte quoteChar) throws XMLStreamException { - // caller has init'ed the buffer... - char[] outputBuffer = _nameBuffer; - int outPtr = 0; - // attribute types are closest matches, so let's use them - final int[] TYPES = _charTypes.ATTR_CHARS; - //boolean spaceToAdd = false; - - main_loop: while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int c = (int) _inputBuffer[_inputPtr++] & 0xFF; - if (TYPES[c] != 0) { - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - - case XmlCharTypes.CT_ATTR_QUOTE: - if (c == (int) quoteChar) { - break main_loop; - } - } - - } - - if (outPtr >= outputBuffer.length) { - _nameBuffer = outputBuffer = DataUtil.growArrayBy(outputBuffer, outputBuffer.length); - outPtr = 0; - } - outputBuffer[outPtr++] = (char) c; - } - return new String(outputBuffer, 0, outPtr); - } - - /* - /********************************************************************** - /* Content skipping - /********************************************************************** - */ - - @Override - protected boolean skipCharacters() throws XMLStreamException { - final int[] TYPES = _charTypes.TEXT_CHARS; - final byte[] inputBuffer = _inputBuffer; - - while (true) { - int c; - - // Then the tight ascii non-funny-char loop: - 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 (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - skipUtf8_2(); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - skipUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - skipUtf8_4(); - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_LT: - --_inputPtr; - return false; - - case XmlCharTypes.CT_AMP: - c = handleEntityInText(); - if (c == 0) { // unexpandable general parsed entity - return true; - } - break; - - case XmlCharTypes.CT_RBRACKET: // ']]>'? - { - // Let's then just count number of brackets -- - // in case they are not followed by '>' - int count = 1; - byte b; - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = inputBuffer[_inputPtr]; - if (b != BYTE_RBRACKET) { - break; - } - ++_inputPtr; // to skip past bracket - ++count; - } - if (b == BYTE_GT && count > 1) { - reportIllegalCDataEnd(); - } - } - break; - - // default: - // Other types are not important here... - } - } - } - - @Override - protected void skipComment() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - - while (true) { - int c; - - // Then the tight ascii non-funny-char loop: - 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 (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - skipUtf8_2(); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - skipUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - skipUtf8_4(); - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_HYPHEN: // '-->'? - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_HYPHEN) { // ok, must be end then - ++_inputPtr; - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr++] != BYTE_GT) { - reportDoubleHyphenInComments(); - } - return; - } - break; - - // default: - // Other types are not important here... - } - } - } - - @Override - protected void skipCData() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - - while (true) { - int c; - - // Then the tight ascii non-funny-char loop: - 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 (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - skipUtf8_2(); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - skipUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - skipUtf8_4(); - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_RBRACKET: // ']]>'? - { - // end is nigh? - int count = 0; - byte b; - - do { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - ++count; - b = _inputBuffer[_inputPtr++]; - } while (b == BYTE_RBRACKET); - - if (b == BYTE_GT) { - if (count > 1) { // gotcha - return; - } - // can still skip plain ']>'... - } else { - --_inputPtr; // need to push back last char - } - } - break; - - // default: - // Other types are not important here... - } - } - } - - @Override - protected void skipPI() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - - while (true) { - int c; - - // Then the tight ascii non-funny-char loop: - 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 (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - skipUtf8_2(); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - skipUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - skipUtf8_4(); - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_QMARK: // '?>'? - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_GT) { - ++_inputPtr; - return; - } - break; - - // default: - // Other types are not important here... - } - } - } - - @Override - protected void skipSpace() throws XMLStreamException { - // mTmpChar has a space, but it's been checked, can ignore - int ptr = _inputPtr; - - while (true) { - if (ptr >= _inputEnd) { - if (!loadMore()) { - break; - } - ptr = _inputPtr; - } - int c = (int) _inputBuffer[ptr] & 0xFF; - if (c > INT_SPACE) { // !!! TODO: xml 1.1 ws - break; - } - ++ptr; - - if (c == INT_LF) { - markLF(ptr); - } else if (c == INT_CR) { - if (ptr >= _inputEnd) { - if (!loadMore()) { - break; - } - ptr = _inputPtr; - } - if (_inputBuffer[ptr] == BYTE_LF) { - ++ptr; - } - markLF(ptr); - } else if (c != INT_SPACE && c != INT_TAB) { - _inputPtr = ptr; - throwInvalidSpace(c); - } - } - - _inputPtr = ptr; - } - - private void skipUtf8_2() throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int c = _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 void skipUtf8_3(int c) throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c &= 0x0F; - if (c >= 0xD) { // have to check - c <<= 6; - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - c |= (d & 0x3F); - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - // 0xD800-0xDFFF, 0xFFFE-0xFFFF illegal - if (c >= 0xD800) { // surrogates illegal, as well as 0xFFFE/0xFFFF - if (c < 0xE000 || c >= 0xFFFE) { - handleInvalidXmlChar(c); - } - } - } else { // no checks, can discard - c = _inputBuffer[_inputPtr++]; - if ((c & 0xC0) != 0x080) { - reportInvalidOther(c & 0xFF, _inputPtr); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c = _inputBuffer[_inputPtr++]; - if ((c & 0xC0) != 0x080) { - reportInvalidOther(c & 0xFF, _inputPtr); - } - } - } - - private void skipUtf8_4() throws XMLStreamException { - if ((_inputPtr + 4) > _inputEnd) { - skipUtf8_4Slow(); - return; - } - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - } - - private void skipUtf8_4Slow() throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - } - - /* - /********************************************************************** - /* Content parsing - /********************************************************************** - */ - - @Override - protected void finishCData() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - char[] outputBuffer = _textBuilder.resetWithEmpty(); - int outPtr = 0; - - /* At this point, space (if any) has been skipped, and we are - * to parse and store the contents - */ - main_loop: while (true) { - int c; - // Then the tight ascii non-funny-char loop: - ascii_loop: while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outputBuffer[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - // And then exceptions: - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_RBRACKET: // close ']]>' marker? - /* Ok: let's just parse all consequtive right brackets, - * and see if followed by greater-than char. This because - * we can only push back at most one char at a time, and - * thus can't easily just check a subset - */ - int count = 0; // ignoring first one - byte b; - - do { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr]; - if (b != BYTE_RBRACKET) { - break; - } - ++_inputPtr; - ++count; - } while (true); - - // Was the marker found? - boolean ok = (b == BYTE_GT && count >= 1); - if (ok) { - --count; - } - // Brackets to copy to output? - for (; count > 0; --count) { - outputBuffer[outPtr++] = ']'; - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - } - if (ok) { - ++_inputPtr; // to consume '>' - break main_loop; - } - break; - } - // Ok, can output the char; there's room for one char at least - outputBuffer[outPtr++] = (char) c; - } - - _textBuilder.setCurrentLength(outPtr); - /* 03-Feb-2009, tatu: To support coalescing mode, may need to - * do some extra work - */ - if (_cfgCoalescing && !_entityPending) { - finishCoalescedText(); - } - } - - @Override - protected void finishCharacters() throws XMLStreamException { - int outPtr; - int c; - char[] outputBuffer; - - // Ok, so what was the first char / entity? - c = _tmpChar; - if (c < 0) { // from entity; can just copy as is - c = -c; - outputBuffer = _textBuilder.resetWithEmpty(); - outPtr = 0; - if ((c >> 16) != 0) { // surrogate pair? - c -= 0x10000; - /* Note: after resetting the buffer, it's known to have - * space for more than 2 chars we need to add - */ - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - } - outputBuffer[outPtr++] = (char) c; - } else { // white space that we are interested in? - if (c == INT_CR || c == INT_LF) { - ++_inputPtr; // wasn't advanced yet, in this case - outPtr = checkInTreeIndentation(c); - if (outPtr < 0) { - return; - } - // Above call also initializes the text builder appropriately - outputBuffer = _textBuilder.getBufferWithoutReset(); - } else { - outputBuffer = _textBuilder.resetWithEmpty(); - outPtr = 0; - } - } - - final int[] TYPES = _charTypes.TEXT_CHARS; - 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 >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outputBuffer[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - // And then fallback for funny chars / UTF-8 multibytes: - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - if ((_inputEnd - _inputPtr) >= 2) { - c = decodeUtf8_3fast(c); - } else { - c = decodeUtf8_3(c); - } - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_LT: - --_inputPtr; - break main_loop; - - case XmlCharTypes.CT_AMP: - c = handleEntityInText(); - if (c == 0) { // unexpandable general parsed entity - // _inputPtr set by entity expansion method - _entityPending = true; - break main_loop; - } - // Ok; does it need a surrogate though? (over 16 bits) - if ((c >> 16) != 0) { - c -= 0x10000; - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - // Need to ensure room for one more char - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - } - break; - - case XmlCharTypes.CT_RBRACKET: // ']]>'? - { - // Let's then just count number of brackets -- - // in case they are not followed by '>' - int count = 1; - byte b; - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = inputBuffer[_inputPtr]; - if (b != BYTE_RBRACKET) { - break; - } - ++_inputPtr; // to skip past bracket - ++count; - } - if (b == BYTE_GT && count > 1) { - reportIllegalCDataEnd(); - } - // Nope. Need to output all brackets, then; except - // for one that can be left for normal output - while (count > 1) { - outputBuffer[outPtr++] = ']'; - // Need to ensure room for one more char - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - --count; - } - } - // Can just output the first ']' along normal output - break; - - // default: - // Other types are not important here... - } - // We know there's room for one more: - outputBuffer[outPtr++] = (char) c; - } - - _textBuilder.setCurrentLength(outPtr); - - /* 03-Feb-2009, tatu: To support coalescing mode, may need to - * do some extra work - */ - if (_cfgCoalescing && !_entityPending) { - finishCoalescedText(); - } - } - - @Override - protected void finishComment() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - char[] outputBuffer = _textBuilder.resetWithEmpty(); - int outPtr = 0; - - main_loop: while (true) { - int c; - // Then the tight ascii non-funny-char loop: - ascii_loop: while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outputBuffer[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_HYPHEN: // '-->'? - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_HYPHEN) { // ok, must be end then - ++_inputPtr; - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr++] != BYTE_GT) { - reportDoubleHyphenInComments(); - } - break main_loop; - } - break; - // default: - // Other types are not important here... - } - - // Ok, can output the char (we know there's room for one more) - outputBuffer[outPtr++] = (char) c; - } - _textBuilder.setCurrentLength(outPtr); - } - - /** - * When this method gets called we know that we have an internal subset, - * and that the opening '[' has already been read. - */ - @Override - protected void finishDTD(boolean copyContents) throws XMLStreamException { - char[] outputBuffer = copyContents ? _textBuilder.resetWithEmpty() : null; - int outPtr = 0; - - final int[] TYPES = _charTypes.DTD_CHARS; - boolean inDecl = false; // in declaration/directive? - int quoteChar = 0; // inside quoted string? - - main_loop: while (true) { - int c; - - /* First we'll have a quickie loop for speeding through - * uneventful chars... - */ - ascii_loop: while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - int max = _inputEnd; - if (outputBuffer != null) { - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - } - while (ptr < max) { - c = (int) _inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - if (outputBuffer != null) { - outputBuffer[outPtr++] = (char) c; - } - } - _inputPtr = ptr; - } - - switch (TYPES[c]) { - - // First, common types - - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - if (outputBuffer != null) { - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - c = 0xDC00 | (c & 0x3FF); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - // And let the other char output down below - } - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - - // Then DTD-specific types: - - case XmlCharTypes.CT_DTD_QUOTE: // apos or quot - if (quoteChar == 0) { - quoteChar = c; - } else { - if (quoteChar == c) { - quoteChar = 0; - } - } - break; - - case XmlCharTypes.CT_DTD_LT: - if (!inDecl) { - inDecl = true; - } - break; - - case XmlCharTypes.CT_DTD_GT: - if (quoteChar == 0) { - inDecl = false; - } - break; - - case XmlCharTypes.CT_DTD_RBRACKET: - if (!inDecl && quoteChar == 0) { - break main_loop; - } - break; - - // default: - // Other types are not important here... - } - - if (outputBuffer != null) { // will have room for one more - outputBuffer[outPtr++] = (char) c; - } - } - if (outputBuffer != null) { - _textBuilder.setCurrentLength(outPtr); - } - - // but still need to match the '>'... - byte b = skipInternalWs(false, null); - if (b != BYTE_GT) { - throwUnexpectedChar(decodeCharForError(b), " expected '>' after the internal subset"); - } - } - - @Override - protected void finishPI() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - char[] outputBuffer = _textBuilder.resetWithEmpty(); - int outPtr = 0; - - /* At this point, space (if any) has been skipped, and we are - * to parse and store the contents - */ - main_loop: while (true) { - int c; - // Then the tight ascii non-funny-char loop: - ascii_loop: while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outputBuffer[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - // And then exceptions: - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_QMARK: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (_inputBuffer[_inputPtr] == BYTE_GT) { // ok, the end! - ++_inputPtr; - break main_loop; - } - // Not end mark, just need to reprocess the second char - // default: - // Other types are not important here... - } - // Ok, can output the char (we know there's room for one more) - outputBuffer[outPtr++] = (char) c; - } - _textBuilder.setCurrentLength(outPtr); - } - - /** - * Note: this method is only called in cases where it is known - * that only space chars are legal. Thus, encountering a non-space - * is an error (WFC or VC). However, an end-of-input is ok. - */ - @Override - protected void finishSpace() throws XMLStreamException { - /* Ok: so, mTmpChar contains first space char. If it looks - * like indentation, we can probably optimize a bit... - */ - int tmp = _tmpChar; - char[] outputBuffer; - int outPtr; - - if (tmp == BYTE_CR || tmp == BYTE_LF) { - outPtr = checkPrologIndentation(tmp); - if (outPtr < 0) { - return; - } - // Above call also initializes the text builder appropriately - outputBuffer = _textBuilder.getBufferWithoutReset(); - } else { - outputBuffer = _textBuilder.resetWithEmpty(); - outputBuffer[0] = (char) tmp; - outPtr = 1; - } - - int ptr = _inputPtr; - - while (true) { - if (ptr >= _inputEnd) { - if (!loadMore()) { - break; - } - ptr = _inputPtr; - } - int c = (int) _inputBuffer[ptr] & 0xFF; - // !!! TODO: check for xml 1.1 whitespace? - if (c > INT_SPACE) { - break; - } - ++ptr; - - if (c == INT_LF) { - markLF(ptr); - } else if (c == INT_CR) { - if (ptr >= _inputEnd) { - if (!loadMore()) { // still need to output the lf - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - outputBuffer[outPtr++] = '\n'; - break; - } - ptr = _inputPtr; - } - if (_inputBuffer[ptr] == BYTE_LF) { - ++ptr; - } - markLF(ptr); - c = INT_LF; // need to convert to canonical lf - } else if (c != INT_SPACE && c != INT_TAB) { - _inputPtr = ptr; - throwInvalidSpace(c); - } - - // Ok, can output the char - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - outputBuffer[outPtr++] = (char) c; - } - - _inputPtr = ptr; - _textBuilder.setCurrentLength(outPtr); - } - - /* - /********************************************************************** - /* 2nd level parsing/skipping for coalesced text - /********************************************************************** - */ - - /** - * Method that gets called after a primary text segment (of type - * CHARACTERS or CDATA, not applicable to SPACE) has been read in - * text buffer. Method has to see if the following event would - * be textual as well, and if so, read it (and any other following - * textual segments). - */ - private void finishCoalescedText() throws XMLStreamException { - while (true) { - // no matter what, will need (and can get) one char - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { // most likely an error, will be handled later on - return; - } - } - - if (_inputBuffer[_inputPtr] == BYTE_LT) { // markup of some kind - /* In worst case, need 3 chars ("= _inputEnd) { - if (!loadAndRetain()) { - // probably an error, but will be handled later - return; - } - } - if (_inputBuffer[_inputPtr + 1] != BYTE_EXCL || _inputBuffer[_inputPtr + 2] != BYTE_LBRACKET) { - // can't be CDATA, we are done here - return; - } - // but let's verify it still: - _inputPtr += 3; - for (int i = 0; i < 6; ++i) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - byte b = _inputBuffer[_inputPtr++]; - if (b != (byte) CDATA_STR.charAt(i)) { - int ch = decodeCharForError(b); - reportTreeUnexpChar(ch, " (expected '" + CDATA_STR.charAt(i) + "' for CDATA section)"); - } - } - finishCoalescedCData(); - } else { // textual (or entity, error etc) - finishCoalescedCharacters(); - if (_entityPending) { - break; - } - } - } - } - - // note: code mostly copied from 'finishCharacters', just simplified - // in some places - private void finishCoalescedCharacters() throws XMLStreamException { - // first char can't be from (char) entity (wrt finishCharacters) - - final int[] TYPES = _charTypes.TEXT_CHARS; - final byte[] inputBuffer = _inputBuffer; - - char[] outputBuffer = _textBuilder.getBufferWithoutReset(); - int outPtr = _textBuilder.getCurrentLength(); - - int c; - - 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 >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outputBuffer[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - // And then fallback for funny chars / UTF-8 multibytes: - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - if ((_inputEnd - _inputPtr) >= 2) { - c = decodeUtf8_3fast(c); - } else { - c = decodeUtf8_3(c); - } - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_LT: - --_inputPtr; - break main_loop; - - case XmlCharTypes.CT_AMP: - c = handleEntityInText(); - if (c == 0) { // unexpandable general parsed entity - // _inputPtr set by entity expansion method - _entityPending = true; - break main_loop; - } - // Ok; does it need a surrogate though? (over 16 bits) - if ((c >> 16) != 0) { - c -= 0x10000; - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - // Need to ensure room for one more char - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - } - break; - - case XmlCharTypes.CT_RBRACKET: // ']]>'? - { - // Let's then just count number of brackets -- - // in case they are not followed by '>' - int count = 1; - byte b; - while (true) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = inputBuffer[_inputPtr]; - if (b != BYTE_RBRACKET) { - break; - } - ++_inputPtr; // to skip past bracket - ++count; - } - if (b == BYTE_GT && count > 1) { - reportIllegalCDataEnd(); - } - // Nope. Need to output all brackets, then; except - // for one that can be left for normal output - while (count > 1) { - outputBuffer[outPtr++] = ']'; - // Need to ensure room for one more char - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - --count; - } - } - // Can just output the first ']' along normal output - break; - - // default: - // Other types are not important here... - } - // We know there's room for one more: - outputBuffer[outPtr++] = (char) c; - } - - _textBuilder.setCurrentLength(outPtr); - } - - // note: code mostly copied from 'finishCharacters', just simplified - // in some places - private void finishCoalescedCData() throws XMLStreamException { - final int[] TYPES = _charTypes.OTHER_CHARS; - final byte[] inputBuffer = _inputBuffer; - - char[] outputBuffer = _textBuilder.getBufferWithoutReset(); - int outPtr = _textBuilder.getCurrentLength(); - - /* At this point, space (if any) has been skipped, and we are - * to parse and store the contents - */ - main_loop: while (true) { - int c; - // Then the tight ascii non-funny-char loop: - ascii_loop: while (true) { - int ptr = _inputPtr; - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - int max = _inputEnd; - { - int max2 = ptr + (outputBuffer.length - outPtr); - if (max2 < max) { - max = max2; - } - } - while (ptr < max) { - c = (int) inputBuffer[ptr++] & 0xFF; - if (TYPES[c] != 0) { - _inputPtr = ptr; - break ascii_loop; - } - outputBuffer[outPtr++] = (char) c; - } - _inputPtr = ptr; - } - // And then exceptions: - switch (TYPES[c]) { - case XmlCharTypes.CT_INVALID: - handleInvalidXmlChar(c); - case XmlCharTypes.CT_WS_CR: - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - if (inputBuffer[_inputPtr] == BYTE_LF) { - ++_inputPtr; - } - markLF(); - c = INT_LF; - break; - - case XmlCharTypes.CT_WS_LF: - markLF(); - break; - - case XmlCharTypes.CT_MULTIBYTE_2: - c = decodeUtf8_2(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_3: - c = decodeUtf8_3(c); - break; - - case XmlCharTypes.CT_MULTIBYTE_4: - c = decodeUtf8_4(c); - // Let's add first part right away: - outputBuffer[outPtr++] = (char) (0xD800 | (c >> 10)); - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - c = 0xDC00 | (c & 0x3FF); - // And let the other char output down below - break; - - case XmlCharTypes.CT_MULTIBYTE_N: - reportInvalidInitial(c); - case XmlCharTypes.CT_RBRACKET: // close ']]>' marker? - /* Ok: let's just parse all consequtive right brackets, - * and see if followed by greater-than char. This because - * we can only push back at most one char at a time, and - * thus can't easily just check a subset - */ - int count = 0; // ignoring first one - byte b; - - do { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - b = _inputBuffer[_inputPtr]; - if (b != BYTE_RBRACKET) { - break; - } - ++_inputPtr; - ++count; - } while (true); - - // Was the marker found? - boolean ok = (b == BYTE_GT && count >= 1); - if (ok) { - --count; - } - // Brackets to copy to output? - for (; count > 0; --count) { - outputBuffer[outPtr++] = ']'; - if (outPtr >= outputBuffer.length) { - outputBuffer = _textBuilder.finishCurrentSegment(); - outPtr = 0; - } - } - if (ok) { - ++_inputPtr; // to consume '>' - break main_loop; - } - break; - } - // Ok, can output the char; there's room for one char at least - outputBuffer[outPtr++] = (char) c; - } - - _textBuilder.setCurrentLength(outPtr); - } - - /** - * Method that gets called after a primary text segment (of type - * CHARACTERS or CDATA, not applicable to SPACE) has been skipped. - * Method has to see if the following event would - * be textual as well, and if so, skip it (and any other following - * textual segments). - * - * @return True if we encountered an unexpandable entity - */ - @Override - protected boolean skipCoalescedText() throws XMLStreamException { - while (true) { - // no matter what, will need (and can get) one char - if (_inputPtr >= _inputEnd) { - if (!loadMore()) { // most likely an error, will be handled later on - return false; - } - } - - if (_inputBuffer[_inputPtr] == BYTE_LT) { // markup of some kind - /* In worst case, need 3 chars ("= _inputEnd) { - if (!loadAndRetain()) { // probably an error, but will be handled later - return false; - } - } - if (_inputBuffer[_inputPtr + 1] != BYTE_EXCL || _inputBuffer[_inputPtr + 2] != BYTE_LBRACKET) { - // can't be CDATA, we are done here - return false; - } - // but let's verify it still: - _inputPtr += 3; - for (int i = 0; i < 6; ++i) { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - byte b = _inputBuffer[_inputPtr++]; - if (b != (byte) CDATA_STR.charAt(i)) { - int ch = decodeCharForError(b); - reportTreeUnexpChar(ch, " (expected '" + CDATA_STR.charAt(i) + "' for CDATA section)"); - } - } - skipCData(); - } else { // textual (or entity, error etc) - if (skipCharacters()) { - return true; - } - } - } - } - - /* - /********************************************************************** - /* Other methods, utf-decoding - /********************************************************************** - */ - - /** - * @return Either decoded character (if positive int); or negated - * value of a high-order char (one that needs surrogate pair) - */ - private int decodeMultiByteChar(int c, int ptr) throws XMLStreamException { - int needed; - - 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 - } - - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - int d = _inputBuffer[ptr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, ptr); - } - c = (c << 6) | (d & 0x3F); - - if (needed > 1) { // needed == 1 means 2 bytes total - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - d = _inputBuffer[ptr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, ptr); - } - c = (c << 6) | (d & 0x3F); - if (needed > 2) { // 4 bytes? (need surrogates) - if (ptr >= _inputEnd) { - loadMoreGuaranteed(); - ptr = _inputPtr; - } - d = _inputBuffer[ptr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, ptr); - } - c = (c << 6) | (d & 0x3F); - /* Need to signal such pair differently (to make comparison - * easier) - */ - c = -c; - } - } - _inputPtr = ptr; - return c; - } - - private int decodeUtf8_2(int c) throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - return ((c & 0x1F) << 6) | (d & 0x3F); - } - - private int decodeUtf8_3(int c1) throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - c1 &= 0x0F; - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - int c = (c1 << 6) | (d & 0x3F); - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - if (c1 >= 0xD) { // 0xD800-0xDFFF, 0xFFFE-0xFFFF illegal - if (c >= 0xD800) { // surrogates illegal, as well as 0xFFFE/0xFFFF - if (c < 0xE000 || c >= 0xFFFE) { - c = handleInvalidXmlChar(c); - } - } - } - return c; - } - - private int decodeUtf8_3fast(int c1) throws XMLStreamException { - c1 &= 0x0F; - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - int c = (c1 << 6) | (d & 0x3F); - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - if (c1 >= 0xD) { // 0xD800-0xDFFF, 0xFFFE-0xFFFF illegal - if (c >= 0xD800) { // surrogates illegal, as well as 0xFFFE/0xFFFF - if (c < 0xE000 || c >= 0xFFFE) { - c = handleInvalidXmlChar(c); - } - } - } - return c; - } - - /** - * @return Character value minus 0x10000; this so that caller - * can readily expand it to actual surrogates - */ - private int decodeUtf8_4(int c) throws XMLStreamException { - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - int d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - c = ((c & 0x07) << 6) | (d & 0x3F); - - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = _inputBuffer[_inputPtr++]; - if ((d & 0xC0) != 0x080) { - reportInvalidOther(d & 0xFF, _inputPtr); - } - c = (c << 6) | (d & 0x3F); - if (_inputPtr >= _inputEnd) { - loadMoreGuaranteed(); - } - d = _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; - } - - /* - /********************************************************************** - /* Internal methods, error reporting - /********************************************************************** - */ - - /** - * Method called called to decode a full UTF-8 characters, given - * its first byte. Note: does not do any validity checks, since this - * is only to be used for informational purposes (often when an error - * has already been encountered) - */ - @Override - public int decodeCharForError(byte b) throws XMLStreamException { - int c = b; - if (c >= 0) { // ascii? fine as is... - return c; - } - 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; - } - - private void reportInvalidOther(int mask, int ptr) throws XMLStreamException { - _inputPtr = ptr; - reportInvalidOther(mask); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/XmlScanner.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/XmlScanner.java index 9a7a0785c423..0e0d7628fcad 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/XmlScanner.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/in/XmlScanner.java @@ -1,10 +1,9 @@ // Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. package com.azure.xml.implementation.aalto.in; -import com.azure.xml.implementation.aalto.WFCException; import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.impl.IoStreamException; import com.azure.xml.implementation.aalto.impl.LocationImpl; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; import com.azure.xml.implementation.aalto.util.DataUtil; import com.azure.xml.implementation.aalto.util.TextBuilder; import com.azure.xml.implementation.aalto.util.XmlChars; @@ -29,7 +28,7 @@ * Scanners are encoding and input type (byte, char / stream, block) * specific, so there are many implementations. */ -public abstract class XmlScanner implements XmlConsts, XMLStreamConstants, NamespaceContext { +public abstract class XmlScanner implements XMLStreamConstants, NamespaceContext { // // // Constants: @@ -300,7 +299,7 @@ public final void close(boolean forceCloseSource) throws XMLStreamException { try { _closeSource(); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } } @@ -322,7 +321,7 @@ protected void _releaseBuffers() { /********************************************************************** */ - public ReaderConfig getConfig() { + public final ReaderConfig getConfig() { return _config; } @@ -597,7 +596,7 @@ public final String getNamespaceURI() { */ @Override - public String getNamespaceURI(String prefix) { + public final String getNamespaceURI(String prefix) { if (prefix == null) { throw new IllegalArgumentException(ErrorConsts.ERR_NULL_ARG); } @@ -625,7 +624,7 @@ public String getNamespaceURI(String prefix) { } @Override - public String getPrefix(String nsURI) { + public final String getPrefix(String nsURI) { /* As per JDK 1.5 JavaDocs, null is illegal; but no mention * about empty String (""). But that should */ @@ -664,7 +663,7 @@ public String getPrefix(String nsURI) { } @Override - public Iterator getPrefixes(String nsURI) { + public final Iterator getPrefixes(String nsURI) { if (nsURI == null) { throw new IllegalArgumentException(ErrorConsts.ERR_NULL_ARG); } @@ -854,7 +853,7 @@ private NsBinding createNewBinding(String prefix) { if (_nsBindingCount == 0) { _nsBindings = new NsBinding[16]; } else if (_nsBindingCount >= _nsBindings.length) { - _nsBindings = (NsBinding[]) DataUtil.growAnyArrayBy(_nsBindings, _nsBindings.length); + _nsBindings = DataUtil.growAnyArrayBy(_nsBindings, _nsBindings.length); } _nsBindings[_nsBindingCount] = b; ++_nsBindingCount; @@ -962,7 +961,7 @@ protected void reportInputProblem(String msg) throws XMLStreamException { /* 29-Mar-2008, tatus: Not sure if these are all Well-Formedness * Constraint (WFC) violations? They should be... ? */ - throw new WFCException(msg, getCurrentLocation()); + throw new StreamExceptionBase(msg, getCurrentLocation()); } /** @@ -1115,7 +1114,7 @@ protected void throwNullChar() throws XMLStreamException { protected char handleInvalidXmlChar(int i) throws XMLStreamException { char c = (char) i; - if (c == CHAR_NULL) { + if (c == XmlConsts.CHAR_NULL) { throwNullChar(); } @@ -1127,7 +1126,7 @@ protected char handleInvalidXmlChar(int i) throws XMLStreamException { protected void throwInvalidSpace(int i) throws XMLStreamException { char c = (char) i; - if (c == CHAR_NULL) { + if (c == XmlConsts.CHAR_NULL) { throwNullChar(); } reportInputProblem("Illegal character (" + XmlChars.getCharDesc(c) + ")"); diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/ByteXmlWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/ByteXmlWriter.java index e260109c33d5..404c56d74c43 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/ByteXmlWriter.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/ByteXmlWriter.java @@ -53,13 +53,11 @@ public abstract class ByteXmlWriter extends XmlWriter { final static byte BYTE_SPACE = (byte) ' '; final static byte BYTE_COLON = (byte) ':'; - final static byte BYTE_SEMICOLON = (byte) ';'; final static byte BYTE_RBRACKET = (byte) ']'; final static byte BYTE_QMARK = (byte) '?'; final static byte BYTE_EQ = (byte) '='; final static byte BYTE_SLASH = (byte) '/'; final static byte BYTE_HASH = (byte) '#'; - final static byte BYTE_HYPHEN = (byte) '-'; final static byte BYTE_LT = (byte) '<'; final static byte BYTE_GT = (byte) '>'; @@ -80,8 +78,6 @@ public abstract class ByteXmlWriter extends XmlWriter { final static byte[] BYTES_CDATA_START = getAscii(""); - final static byte[] BYTES_COMMENT_START = getAscii(""); final static byte[] BYTES_XMLDECL_START = getAscii(" _outputBufferLen) { - flushBuffer(); - // name longer than the buffer? can write it straight out - if (len >= _outputBufferLen) { - name.writeBytes(_out); - return; - } - ptr = _outputPtr; - } - ptr += name.appendBytes(_outputBuffer, ptr); - _outputPtr = ptr; - } - protected final void writeName(byte preChar, WName name) throws IOException { flushBuffer(); // name longer than the buffer? Need to write it straight out @@ -650,7 +623,7 @@ protected final void writeName(byte preChar, WName name) throws IOException { * mode) */ @Override - public int writeCData(String data) throws IOException, XMLStreamException { + public final int writeCData(String data) throws IOException, XMLStreamException { writeCDataStart(); // will check surrogates int len = data.length(); int offset = 0; @@ -973,247 +946,12 @@ private void writeSplitCharacters(char[] cbuf, int offset, int len) throws IOExc } } - /* - /********************************************************************** - /* Write methods, typed (element) content - /********************************************************************** - */ - /* /********************************************************************** /* Write methods, other /********************************************************************** */ - /** - * Method that will try to output the content as specified. If - * the content passed in has embedded "--" in it, it will either - * add an intervening space between consequtive hyphens (if content - * fixing is enabled), or return the offset of the first hyphen in - * multi-hyphen sequence. - */ - @Override - public int writeComment(String data) throws IOException, XMLStreamException { - writeCommentStart(); - - int len = data.length(); - int offset = 0; - while (len > 0) { - char[] buf = _copyBuffer; - final int blen = buf.length; - int len2 = Math.min(len, blen); - // Nope, can only do part - data.getChars(offset, offset + len2, buf, 0); - int cix = writeCommentContents(buf, 0, len2); - if (cix >= 0) { - return offset + cix; - } - offset += blen; - len -= blen; - } - writeCommentEnd(); - return -1; - } - - /** - * Note: the only way to fix comment contents is to inject a space - * to split up consecutive '--' (or '-' that ends a comment). - */ - protected int writeCommentContents(char[] cbuf, int offset, int len) throws IOException, XMLStreamException { - if (_surrogate != 0) { - outputSurrogates(_surrogate, cbuf[offset]); - // reset the temporary surrogate storage - _surrogate = 0; - ++offset; - --len; - } - - // Unlike with writeCharacters() and fastWriteName(), let's not - // worry about split buffers here: this is unlikely to become - // performance bottleneck. This allows keeping it simple; and - // should it matter, we could start doing fast version here as well. - len += offset; // now marks the end - - main_loop: while (offset < len) { - final int[] charTypes = _charTypes.OTHER_CHARS; - - while (true) { - int ch = cbuf[offset]; - if (ch >= OutputCharTypes.MAIN_TABLE_SIZE) { - break; - } - if (charTypes[ch] != XmlCharTypes.CT_OK) { - break; - } - if (_outputPtr >= _outputBufferLen) { - flushBuffer(); - } - _outputBuffer[_outputPtr++] = (byte) ch; - if (++offset >= len) { - break main_loop; - } - } - - // Ok, so what did we hit? - int ch = cbuf[offset++]; - if (ch < OutputCharTypes.MAIN_TABLE_SIZE) { - switch (charTypes[ch]) { - case CT_INVALID: - reportInvalidChar(ch); - case CT_WS_CR: // No way to escape within CDATA - case CT_WS_LF: - ++_locRowNr; - break; - - case CT_OUTPUT_MUST_QUOTE: // == MULTIBYTE_N value - reportFailedEscaping("comment", ch); - case CT_MULTIBYTE_2: - // To off-line or not? - output2ByteChar(ch); - continue; - - case CT_HYPHEN: - // No need if followed by non hyphen - if (offset < len && cbuf[offset] != '-') { - break; - } - // Two hyphens, or hyphen at end; must append a space - writeRaw(BYTE_HYPHEN, BYTE_SPACE); - continue; - - default: // Everything else should be outputtable as is - break; - } - if (_outputPtr >= _outputBufferLen) { - flushBuffer(); - } - _outputBuffer[_outputPtr++] = (byte) ch; - } else { // beyond 2-byte encodables; 3-byte, surrogates? - offset = outputMultiByteChar(ch, cbuf, offset, len); - } - } - return -1; - } - - @Override - public void writeDTD(String data) throws IOException, XMLStreamException { - // !!! TBI: Check for char validity, similar to other methods? - writeRaw(data, 0, data.length()); - } - - protected int writePIData(char[] cbuf, int offset, int len) throws IOException, XMLStreamException { - if (_surrogate != 0) { - outputSurrogates(_surrogate, cbuf[offset]); - // reset the temporary surrogate storage - _surrogate = 0; - ++offset; - --len; - } - - // Unlike with writeCharacters() and fastWriteName(), let's not - // worry about split buffers here: this is unlikely to become - // performance bottleneck. This allows keeping it simple; and - // should it matter, we could start doing fast version here as well. - len += offset; // now marks the end - - main_loop: while (offset < len) { - final int[] charTypes = _charTypes.OTHER_CHARS; - - while (true) { - int ch = cbuf[offset]; - if (ch >= OutputCharTypes.MAIN_TABLE_SIZE) { - break; - } - if (charTypes[ch] != XmlCharTypes.CT_OK) { - break; - } - if (_outputPtr >= _outputBufferLen) { - flushBuffer(); - } - _outputBuffer[_outputPtr++] = (byte) ch; - if (++offset >= len) { - break main_loop; - } - } - - // Ok, so what did we hit? - int ch = cbuf[offset++]; - if (ch < OutputCharTypes.MAIN_TABLE_SIZE) { - switch (charTypes[ch]) { - case CT_INVALID: - reportInvalidChar(ch); - case CT_WS_CR: // No way to escape within CDATA - case CT_WS_LF: - ++_locRowNr; - break; - - case CT_OUTPUT_MUST_QUOTE: // == MULTIBYTE_N value - reportFailedEscaping("processing instruction", ch); - case CT_MULTIBYTE_2: - // To off-line or not? - output2ByteChar(ch); - continue; - - case CT_QMARK: - // Problem, if we have '?>' - if (offset < len && cbuf[offset] == '>') { - return offset; - } - break; - - default: // Everything else should be outputtable as is - break; - } - if (_outputPtr >= _outputBufferLen) { - flushBuffer(); - } - _outputBuffer[_outputPtr++] = (byte) ch; - } else { // beyond 2-byte encodables; 3-byte, surrogates? - offset = outputMultiByteChar(ch, cbuf, offset, len); - } - } - return -1; - } - - @Override - public void writeEntityReference(WName name) throws IOException { - writeRaw(BYTE_AMP); // will check surrogates - writeName(name); - writeRaw(BYTE_SEMICOLON); - } - - @Override - public int writePI(WName target, String data) throws IOException, XMLStreamException { - writeRaw(BYTE_LT, BYTE_QMARK); - writeName(target); - if (data != null) { - // Need to split etc - writeRaw(BYTE_SPACE); - - int len = data.length(); - int offset = 0; - while (len > 0) { - char[] buf = _copyBuffer; - int blen = buf.length; - - // Can write all the rest? - if (blen > len) { - blen = len; - } - // Nope, can only do part - data.getChars(offset, offset + blen, buf, 0); - int cix = writePIData(buf, 0, blen); - if (cix >= 0) { - return offset + cix; - } - offset += blen; - len -= blen; - } - } - writeRaw(BYTE_QMARK, BYTE_GT); - return -1; - } - @Override public final void writeSpace(String data) throws IOException, XMLStreamException { int len = data.length(); @@ -1231,7 +969,7 @@ public final void writeSpace(String data) throws IOException, XMLStreamException } @Override - public void writeSpace(char[] cbuf, int offset, int len) throws IOException, XMLStreamException { + public final void writeSpace(char[] cbuf, int offset, int len) throws IOException, XMLStreamException { if (_out == null) { return; } @@ -1254,7 +992,7 @@ public void writeSpace(char[] cbuf, int offset, int len) throws IOException, XML } @Override - public void writeXmlDeclaration(String version, String encoding, String standalone) + public final void writeXmlDeclaration(String version, String encoding, String standalone) throws IOException, XMLStreamException { writeRaw(BYTES_XMLDECL_START); // will check surrogates // !!! TBI: check validity @@ -1290,14 +1028,6 @@ protected final void writeCDataEnd() throws IOException { writeRaw(BYTES_CDATA_END); } - protected final void writeCommentStart() throws IOException { - writeRaw(BYTES_COMMENT_START); - } - - protected final void writeCommentEnd() throws IOException { - writeRaw(BYTES_COMMENT_END); - } - /* /********************************************************************** /* Write methods, raw (unprocessed) output @@ -1326,10 +1056,10 @@ protected final void writeRaw(byte b1, byte b2) throws IOException { } protected final void writeRaw(byte[] buf) throws IOException { - writeRaw(buf, 0, buf.length); + writeRaw(buf, buf.length); } - protected final void writeRaw(byte[] buf, int offset, int len) throws IOException { + protected final void writeRaw(byte[] buf, int len) throws IOException { if (_surrogate != 0) { throwUnpairedSurrogate(); } @@ -1337,7 +1067,7 @@ protected final void writeRaw(byte[] buf, int offset, int len) throws IOExceptio int ptr = _outputPtr; // Common case: fits right in the buffer if ((ptr + len) <= _outputBufferLen) { - System.arraycopy(buf, offset, _outputBuffer, ptr, len); + System.arraycopy(buf, 0, _outputBuffer, ptr, len); _outputPtr += len; return; } @@ -1348,10 +1078,10 @@ protected final void writeRaw(byte[] buf, int offset, int len) throws IOExceptio ptr = _outputPtr; } if (len < SMALL_WRITE) { - System.arraycopy(buf, offset, _outputBuffer, ptr, len); + System.arraycopy(buf, 0, _outputBuffer, ptr, len); _outputPtr += len; } else { - _out.write(buf, offset, len); + _out.write(buf, 0, len); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/CharXmlWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/CharXmlWriter.java index b716a7602b88..665b9a6f6698 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/CharXmlWriter.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/CharXmlWriter.java @@ -546,52 +546,6 @@ public void writeSpace(char[] cbuf, int offset, int len) throws IOException, XML } } - /** - * Method that will try to output the content as specified. If - * the content passed in has embedded "--" in it, it will either - * add an intervening space between consequtive hyphens (if content - * fixing is enabled), or return the offset of the first hyphen in - * multi-hyphen sequence. - */ - @Override - public int writeComment(String data) throws IOException, XMLStreamException { - if (_out == null) { - return -1; - } - - writeCommentStart(); - /* Ok, let's just copy into a temporary buffer. While copying - * to the output buffer would be faster, it gets pretty - * complicated; so let's not bother (yet?) - */ - int len = data.length(); - int offset = 0; - int cix = -1; - - while (len > 0) { - char[] buf = _copyBuffer; - int blen = buf.length; - - // Can write all the rest? - if (blen > len) { - blen = len; - } - // Nope, can only do part - data.getChars(offset, offset + blen, buf, 0); - cix = writeCommentContents(buf, 0, blen); - if (cix >= 0) { - break; - } - offset += blen; - len -= blen; - } - if (cix >= 0) { - return (offset + cix); - } - writeCommentEnd(); - return -1; - } - /** * Note: the only way to fix comment contents is to inject a space * to split up consequtive '--' (or '-' that ends a comment). @@ -658,19 +612,6 @@ private int writeCommentContents(char[] cbuf, int offset, int len) throws IOExce return -1; } - @Override - public void writeDTD(String data) throws IOException { - // !!! TBI: Check for char validity, similar to other methods? - writeRaw(data, 0, data.length()); - } - - @Override - public void writeEntityReference(WName name) throws IOException { - fastWriteRaw('&'); - writeName(name); - fastWriteRaw(';'); - } - @Override public void writeXmlDeclaration(String version, String encoding, String standalone) throws IOException { fastWriteRaw("'); } - @Override - public int writePI(WName target, String data) throws IOException, XMLStreamException { - fastWriteRaw('<', '?'); - writeName(target); - - if (data != null && !data.isEmpty()) { - int len = data.length(); - int offset = 0; - int cix = -1; - - fastWriteRaw(' '); - - // !!! TODO: copy straight to output buffer - while (len > 0) { - char[] buf = _copyBuffer; - int blen = buf.length; - - // Can write all the rest? - if (blen > len) { - blen = len; - } - data.getChars(offset, offset + blen, buf, 0); - cix = writePIContents(buf, 0, blen); - if (cix >= 0) { - break; - } - offset += blen; - len -= blen; - } - if (cix >= 0) { - return offset + cix; - } - } - fastWriteRaw('?', '>'); - return -1; - } - private int writePIContents(char[] cbuf, int offset, int len) throws IOException, XMLStreamException { len += offset; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NonRepairingStreamWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NonRepairingStreamWriter.java deleted file mode 100644 index eff0ac6171ff..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NonRepairingStreamWriter.java +++ /dev/null @@ -1,173 +0,0 @@ -// Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. -/* Aalto XML processor - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in the file LICENSE which is - * included with the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.azure.xml.implementation.aalto.out; - -import javax.xml.stream.*; - -import com.azure.xml.implementation.aalto.impl.ErrorConsts; - -/** - * Concrete implementation of {@link StreamWriterBase}, which - * implements basic namespace-aware, non repairing functionality. - */ -public final class NonRepairingStreamWriter extends StreamWriterBase { - /* - /********************************************************************** - /* Construction, init - /********************************************************************** - */ - - public NonRepairingStreamWriter(WriterConfig cfg, XmlWriter writer, WNameTable symbols) { - super(cfg, writer, symbols); - } - - /* - /********************************************************************** - /* Implementations of abstract methods from base class, Stax 1.0 methods - /********************************************************************** - */ - - @Override - public void setDefaultNamespace(String uri) { - _currElem.setDefaultNsURI(uri); - } - - @Override - public void _setPrefix(String prefix, String uri) { - _currElem.addPrefix(prefix, uri); - } - - //public void writeAttribute(String localName, String value) - - @Override - public void writeAttribute(String nsURI, String localName, String value) throws XMLStreamException { - if (!_stateStartElementOpen) { - throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM); - } - WName name; - if (nsURI == null || nsURI.isEmpty()) { - name = _symbols.findSymbol(localName); - } else { - String prefix = _currElem.getExplicitPrefix(nsURI, _rootNsContext); - if (prefix == null) { - throwOutputError("Unbound namespace URI '" + nsURI + "'"); - } - name = _symbols.findSymbol(prefix, localName); - } - _writeAttribute(name, value); - } - - @Override - public void writeAttribute(String prefix, String nsURI, String localName, String value) throws XMLStreamException { - if (!_stateStartElementOpen) { - throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM); - } - WName name = (prefix == null || prefix.isEmpty()) - ? _symbols.findSymbol(localName) - : _symbols.findSymbol(prefix, localName); - _writeAttribute(name, value); - } - - @Override - public void writeDefaultNamespace(String nsURI) throws XMLStreamException { - if (!_stateStartElementOpen) { - throwOutputError(ErrorConsts.WERR_NS_NO_ELEM); - } - _writeDefaultNamespace(nsURI); - /* 31-Jan-2008, tatus: Stax TCK expects an implicit prefix - * addition binding. So let's do that, then - */ - setDefaultNamespace(nsURI); - } - - //public void writeEmptyElement(String localName) - - @Override - public void writeEmptyElement(String nsURI, String localName) throws XMLStreamException { - String prefix = _currElem.getPrefix(nsURI); - if (prefix == null) { - throwOutputError("Unbound namespace URI '" + nsURI + "'"); - } - WName name; - if (prefix.isEmpty()) { - name = _symbols.findSymbol(localName); - prefix = null; - } else { - name = _symbols.findSymbol(prefix, localName); - } - _verifyStartElement(prefix, localName); - _writeStartTag(name, true, nsURI); - } - - @Override - public void writeEmptyElement(String prefix, String localName, String nsURI) throws XMLStreamException { - _verifyStartElement(prefix, localName); - WName name; - if (prefix == null || prefix.isEmpty()) { - name = _symbols.findSymbol(localName); - } else { - name = _symbols.findSymbol(prefix, localName); - } - _writeStartTag(name, true, nsURI); - } - - @Override - public void writeNamespace(String prefix, String nsURI) throws XMLStreamException { - if (prefix == null || prefix.isEmpty()) { - writeDefaultNamespace(nsURI); - return; - } - if (!_stateStartElementOpen) { - throwOutputError(ErrorConsts.WERR_NS_NO_ELEM); - } - _writeNamespace(prefix, nsURI); - // 31-Jan-2008, tatus: Stax TCK expects an implicit prefix - // addition binding. So let's do that, then - setPrefix(prefix, nsURI); - } - - //public void writeStartElement(String localName) - - @Override - public void writeStartElement(String nsURI, String localName) throws XMLStreamException { - String prefix = _currElem.getPrefix(nsURI); - if (prefix == null) { - throwOutputError("Unbound namespace URI '" + nsURI + "'"); - } - WName name; - if (prefix.isEmpty()) { - name = _symbols.findSymbol(localName); - prefix = null; - } else { - name = _symbols.findSymbol(prefix, localName); - } - _verifyStartElement(prefix, localName); - _writeStartTag(name, false); - } - - @Override - public void writeStartElement(String prefix, String localName, String nsURI) throws XMLStreamException { - _verifyStartElement(prefix, localName); - WName name; - if (prefix == null || prefix.isEmpty()) { - name = _symbols.findSymbol(localName); - } else { - name = _symbols.findSymbol(prefix, localName); - } - _writeStartTag(name, false, nsURI); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NsBinder.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NsBinder.java index 9d6abafc96ac..7a1d49c768fe 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NsBinder.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/NsBinder.java @@ -98,11 +98,10 @@ public String findUriByPrefix(String prefix) { */ String[] strs = _nsStrings; // Hash code should differentiate cheaply (beyond length checks) - int phash = prefix.hashCode(); for (int ix = _scopeEnd - 2; ix >= 0; ix -= 2) { String thisP = strs[ix]; - if (Objects.equals(thisP, prefix) || (thisP.hashCode() == phash && thisP.equals(prefix))) { + if (Objects.equals(thisP, prefix)) { return strs[ix + 1]; } } @@ -117,21 +116,19 @@ public String findPrefixByUri(String uri) { * and so on. */ String[] strs = _nsStrings; - int uhash = uri.hashCode(); main_loop: for (int ix = _scopeEnd - 1; ix > 0; ix -= 2) { String thisU = strs[ix]; - if (Objects.equals(thisU, uri) || (thisU.hashCode() == uhash && thisU.equals(uri))) { + if (Objects.equals(thisU, uri)) { // match, but has it been masked? String prefix = strs[ix - 1]; /* only need to check, if it wasn't within current scope * (no masking allowed within scopes) */ if (ix < _scopeStart) { - int phash = prefix.hashCode(); for (int j = ix - 1, end = _scopeEnd; j < end; j += 2) { String thisP = strs[ix]; - if (Objects.equals(thisP, prefix) || (thisP.hashCode() == phash && thisP.equals(prefix))) { + if (Objects.equals(thisP, prefix)) { // Masking, can't use continue main_loop; } @@ -148,17 +145,15 @@ public List getPrefixesBoundToUri(String uri, List l) { * findPrefixByUri... */ String[] strs = _nsStrings; - int uhash = uri.hashCode(); main_loop: for (int ix = _scopeEnd - 1; ix > 0; ix -= 2) { String thisU = strs[ix]; - if (Objects.equals(thisU, uri) || (thisU.hashCode() == uhash && thisU.equals(uri))) { + if (Objects.equals(thisU, uri)) { String prefix = strs[ix - 1]; if (ix < _scopeStart) { - int phash = prefix.hashCode(); for (int j = ix - 1, end = _scopeEnd; j < end; j += 2) { String thisP = strs[ix]; - if (Objects.equals(thisP, prefix) || (thisP.hashCode() == phash && thisP.equals(prefix))) { + if (Objects.equals(thisP, prefix)) { // Masking... got to continue the main loop: continue main_loop; } @@ -197,11 +192,10 @@ public int localSize() { */ void addMapping(String prefix, String uri) { String[] strs = _nsStrings; - int phash = prefix.hashCode(); for (int ix = _scopeStart, end = _scopeEnd; ix < end; ix += 2) { String thisP = strs[ix]; - if (Objects.equals(thisP, prefix) || (thisP.hashCode() == phash && thisP.equals(prefix))) { + if (Objects.equals(thisP, prefix)) { // Overriding an existing mapping strs[ix + 1] = uri; return; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/SingleByteXmlWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/SingleByteXmlWriter.java index 3e72b1df945e..6f2a1ba5cf17 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/SingleByteXmlWriter.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/SingleByteXmlWriter.java @@ -31,18 +31,6 @@ public SingleByteXmlWriter(WriterConfig cfg, OutputStream out, XmlCharTypes char super(cfg, out, charTypes); } - /* - /********************************************************************** - /* Abstract methods for sub-classes - /********************************************************************** - */ - - @Override - public abstract int getHighestEncodable(); - - @Override - public abstract void writeRaw(char[] cbuf, int offset, int len) throws IOException, XMLStreamException; - /* /********************************************************************** /* Internal methods, low-level writes diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/StreamWriterBase.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/StreamWriterBase.java index 0f27e53f20d0..93d412f8f466 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/StreamWriterBase.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/StreamWriterBase.java @@ -17,17 +17,16 @@ package com.azure.xml.implementation.aalto.out; import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.impl.IoStreamException; import com.azure.xml.implementation.aalto.impl.LocationImpl; import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; import com.azure.xml.implementation.aalto.util.XmlConsts; -import com.azure.xml.implementation.stax2.ri.Stax2WriterImpl; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; import java.io.IOException; import java.text.MessageFormat; import java.util.Iterator; @@ -35,7 +34,7 @@ /** * Base class for {@link XMLStreamReader} implementations. */ -public abstract class StreamWriterBase extends Stax2WriterImpl implements NamespaceContext { +public final class StreamWriterBase implements NamespaceContext, XMLStreamWriter { protected enum State { PROLOG, TREE, EPILOG } @@ -46,12 +45,12 @@ protected enum State { /********************************************************************** */ - protected final WriterConfig _config; + private final WriterConfig _config; /** * Root namespace context defined for this writer, if any. */ - protected NamespaceContext _rootNsContext; + private NamespaceContext _rootNsContext; // // Custom: @@ -61,7 +60,7 @@ protected enum State { /********************************************************************** */ - protected WNameTable _symbols; + private final WNameTable _symbols; /* /********************************************************************** @@ -72,7 +71,7 @@ protected enum State { /** * Actual physical writer to output serialized XML content to */ - protected final XmlWriter _xmlWriter; + private final XmlWriter _xmlWriter; /* /********************************************************************** @@ -80,7 +79,7 @@ protected enum State { /********************************************************************** */ - protected State _state = State.PROLOG; + private State _state = State.PROLOG; /** * We'll use a virtual root element (like a document node of sort), @@ -88,14 +87,14 @@ protected enum State { * always a current output element instance, even when in prolog * or epilog. */ - protected OutputElement _currElem = OutputElement.createRoot(); + private OutputElement _currElem = OutputElement.createRoot(); /** * Flag that is set to true first time something has been output. * Generally needed to keep track of whether XML declaration * (START_DOCUMENT) can be output or not. */ - protected boolean _stateAnyOutput = false; + private boolean _stateAnyOutput = false; /** * Flag that is set during time that a start element is "open", ie. @@ -103,7 +102,7 @@ protected enum State { * space declarations and attributes), before other main-level * constructs have been output. */ - protected boolean _stateStartElementOpen = false; + private boolean _stateStartElementOpen = false; /** * Flag that indicates that current element is an empty element (one @@ -113,7 +112,7 @@ protected enum State { * is output; normally a new context is opened, but for empty * elements not. */ - protected boolean _stateEmptyElement = false; + private boolean _stateEmptyElement = false; /** * Value passed as the expected root element, when using the multiple @@ -122,7 +121,7 @@ protected enum State { * enables structural validation as well, to pre-filter well-formedness * errors that validators might have trouble dealing with). */ - protected String _dtdRootElemName = null; + private final String _dtdRootElemName = null; /* /********************************************************************** @@ -136,7 +135,7 @@ protected enum State { /********************************************************************** */ - protected OutputElement _outputElemPool = null; + private OutputElement _outputElemPool = null; /** * Although pooled objects are small, let's limit the pool size @@ -146,7 +145,7 @@ protected enum State { */ final static int MAX_POOL_SIZE = 8; - protected int _poolSize = 0; + private int _poolSize = 0; /* /********************************************************************** @@ -154,7 +153,7 @@ protected enum State { /********************************************************************** */ - protected StreamWriterBase(WriterConfig cfg, XmlWriter writer, WNameTable symbols) { + public StreamWriterBase(WriterConfig cfg, XmlWriter writer, WNameTable symbols) { _config = cfg; _xmlWriter = writer; _symbols = symbols; @@ -176,12 +175,12 @@ public void flush() throws XMLStreamException { try { _xmlWriter.flush(); } catch (IOException ie) { - throw new IoStreamException(ie); + throw new StreamExceptionBase(ie); } } @Override - public final NamespaceContext getNamespaceContext() { + public NamespaceContext getNamespaceContext() { return this; } @@ -195,19 +194,17 @@ public Object getProperty(String name) { } @Override - public abstract void setDefaultNamespace(String uri) throws XMLStreamException; + public void setDefaultNamespace(String uri) { + _currElem.setDefaultNsURI(uri); + } @Override - public void setNamespaceContext(NamespaceContext ctxt) throws XMLStreamException { - // This is only allowed before root element output: - if (_state != State.PROLOG) { - throwOutputError("Called setNamespaceContext() after having already output root element."); - } - _rootNsContext = ctxt; + public void setNamespaceContext(NamespaceContext ctxt) { + throw new UnsupportedOperationException(); } @Override - public final void setPrefix(String prefix, String uri) throws XMLStreamException { + public void setPrefix(String prefix, String uri) throws XMLStreamException { if (prefix == null) { throw new NullPointerException(); } @@ -246,10 +243,12 @@ public final void setPrefix(String prefix, String uri) throws XMLStreamException _setPrefix(prefix, uri); } - protected abstract void _setPrefix(String prefix, String uri); + public void _setPrefix(String prefix, String uri) { + _currElem.addPrefix(prefix, uri); + } @Override - public final void writeAttribute(String localName, String value) throws XMLStreamException { + public void writeAttribute(String localName, String value) throws XMLStreamException { if (!_stateStartElementOpen) { throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM); } @@ -258,11 +257,33 @@ public final void writeAttribute(String localName, String value) throws XMLStrea } @Override - public abstract void writeAttribute(String nsURI, String localName, String value) throws XMLStreamException; + public void writeAttribute(String nsURI, String localName, String value) throws XMLStreamException { + if (!_stateStartElementOpen) { + throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM); + } + WName name; + if (nsURI == null || nsURI.isEmpty()) { + name = _symbols.findSymbol(localName); + } else { + String prefix = _currElem.getExplicitPrefix(nsURI, _rootNsContext); + if (prefix == null) { + throwOutputError("Unbound namespace URI '" + nsURI + "'"); + } + name = _symbols.findSymbol(prefix, localName); + } + _writeAttribute(name, value); + } @Override - public abstract void writeAttribute(String prefix, String nsURI, String localName, String value) - throws XMLStreamException; + public void writeAttribute(String prefix, String nsURI, String localName, String value) throws XMLStreamException { + if (!_stateStartElementOpen) { + throwOutputError(ErrorConsts.WERR_ATTR_NO_ELEM); + } + WName name = (prefix == null || prefix.isEmpty()) + ? _symbols.findSymbol(localName) + : _symbols.findSymbol(prefix, localName); + _writeAttribute(name, value); + } @Override public void writeCData(String data) throws XMLStreamException { @@ -274,7 +295,7 @@ public void writeCData(String data) throws XMLStreamException { _reportNwfContent(ErrorConsts.WERR_CDATA_CONTENT, ix); } } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } @@ -296,7 +317,7 @@ public void writeCharacters(char[] text, int start, int len) throws XMLStreamExc try { _xmlWriter.writeCharacters(text, start, len); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } } @@ -316,43 +337,30 @@ public void writeCharacters(String text) throws XMLStreamException { try { _xmlWriter.writeCharacters(text); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } @Override - public void writeComment(String data) throws XMLStreamException { - _stateAnyOutput = true; - if (_stateStartElementOpen) { - _closeStartElement(_stateEmptyElement); - } - - /* No structural validation needed per se, for comments; they are - * allowed anywhere in XML content. However, content may need to - * be checked (by XmlWriter) - */ - try { - int ix = _xmlWriter.writeComment(data); - if (ix >= 0) { - _reportNwfContent(ErrorConsts.WERR_COMMENT_CONTENT, ix); - } - } catch (IOException ioe) { - throw new IoStreamException(ioe); - } + public void writeComment(String data) { + throw new UnsupportedOperationException(); } @Override - public abstract void writeDefaultNamespace(String nsURI) throws XMLStreamException; + public void writeDefaultNamespace(String nsURI) throws XMLStreamException { + if (!_stateStartElementOpen) { + throwOutputError(ErrorConsts.WERR_NS_NO_ELEM); + } + _writeDefaultNamespace(nsURI); + /* 31-Jan-2008, tatus: Stax TCK expects an implicit prefix + * addition binding. So let's do that, then + */ + setDefaultNamespace(nsURI); + } @Override - public final void writeDTD(String dtd) throws XMLStreamException { - _verifyWriteDTD(); - _dtdRootElemName = ""; // marker to verify only one is output - try { - _xmlWriter.writeDTD(dtd); - } catch (IOException ioe) { - throw new IoStreamException(ioe); - } + public void writeDTD(String dtd) { + throw new UnsupportedOperationException(); } /** @@ -369,10 +377,33 @@ public void writeEmptyElement(String localName) throws XMLStreamException { } @Override - public abstract void writeEmptyElement(String nsURI, String localName) throws XMLStreamException; + public void writeEmptyElement(String nsURI, String localName) throws XMLStreamException { + String prefix = _currElem.getPrefix(nsURI); + if (prefix == null) { + throwOutputError("Unbound namespace URI '" + nsURI + "'"); + } + WName name; + if (prefix.isEmpty()) { + name = _symbols.findSymbol(localName); + prefix = null; + } else { + name = _symbols.findSymbol(prefix, localName); + } + _verifyStartElement(prefix, localName); + _writeStartTag(name, true, nsURI); + } @Override - public abstract void writeEmptyElement(String prefix, String localName, String nsURI) throws XMLStreamException; + public void writeEmptyElement(String prefix, String localName, String nsURI) throws XMLStreamException { + _verifyStartElement(prefix, localName); + WName name; + if (prefix == null || prefix.isEmpty()) { + name = _symbols.findSymbol(localName); + } else { + name = _symbols.findSymbol(prefix, localName); + } + _writeStartTag(name, true, nsURI); + } @Override public void writeEndDocument() throws XMLStreamException { @@ -417,7 +448,7 @@ public void writeEndElement() throws XMLStreamException { _xmlWriter.writeEndTag(thisElem.getName()); } } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } if (_currElem.isRoot()) { // (note: we have dummy placeholder elem that contains doc) _state = State.EPILOG; @@ -425,46 +456,33 @@ public void writeEndElement() throws XMLStreamException { } @Override - public void writeEntityRef(String name) throws XMLStreamException { - _stateAnyOutput = true; - if (_stateStartElementOpen) { - _closeStartElement(_stateEmptyElement); - } + public void writeEntityRef(String name) { + throw new UnsupportedOperationException(); + } - // Structurally, need to check we are not in prolog/epilog. - if (inPrologOrEpilog()) { - _reportNwfStructure(ErrorConsts.WERR_PROLOG_ENTITY); + @Override + public void writeNamespace(String prefix, String nsURI) throws XMLStreamException { + if (prefix == null || prefix.isEmpty()) { + writeDefaultNamespace(nsURI); + return; } - try { - _xmlWriter.writeEntityReference(_symbols.findSymbol(name)); - } catch (IOException ioe) { - throw new IoStreamException(ioe); + if (!_stateStartElementOpen) { + throwOutputError(ErrorConsts.WERR_NS_NO_ELEM); } + _writeNamespace(prefix, nsURI); + // 31-Jan-2008, tatus: Stax TCK expects an implicit prefix + // addition binding. So let's do that, then + setPrefix(prefix, nsURI); } @Override - public abstract void writeNamespace(String prefix, String nsURI) throws XMLStreamException; - - @Override - public void writeProcessingInstruction(String target) throws XMLStreamException { - writeProcessingInstruction(target, null); + public void writeProcessingInstruction(String target) { + throw new UnsupportedOperationException(); } @Override - public void writeProcessingInstruction(String target, String data) throws XMLStreamException { - _stateAnyOutput = true; - if (_stateStartElementOpen) { - _closeStartElement(_stateEmptyElement); - } - - try { - int ix = _xmlWriter.writePI(_symbols.findSymbol(target), data); - if (ix >= 0) { - _reportNwfContent(ErrorConsts.WERR_PI_CONTENT, ix); - } - } catch (IOException ioe) { - throw new IoStreamException(ioe); - } + public void writeProcessingInstruction(String target, String data) { + throw new UnsupportedOperationException(); } @Override @@ -501,10 +519,33 @@ public void writeStartElement(String localName) throws XMLStreamException { } @Override - public abstract void writeStartElement(String nsURI, String localName) throws XMLStreamException; + public void writeStartElement(String nsURI, String localName) throws XMLStreamException { + String prefix = _currElem.getPrefix(nsURI); + if (prefix == null) { + throwOutputError("Unbound namespace URI '" + nsURI + "'"); + } + WName name; + if (prefix.isEmpty()) { + name = _symbols.findSymbol(localName); + prefix = null; + } else { + name = _symbols.findSymbol(prefix, localName); + } + _verifyStartElement(prefix, localName); + _writeStartTag(name, false); + } @Override - public abstract void writeStartElement(String prefix, String localName, String nsURI) throws XMLStreamException; + public void writeStartElement(String prefix, String localName, String nsURI) throws XMLStreamException { + _verifyStartElement(prefix, localName); + WName name; + if (prefix == null || prefix.isEmpty()) { + name = _symbols.findSymbol(localName); + } else { + name = _symbols.findSymbol(prefix, localName); + } + _writeStartTag(name, false, nsURI); + } /* /********************************************************************** @@ -545,21 +586,39 @@ public Iterator getPrefixes(String uri) { /********************************************************************** */ - @Override + /** + * Method that can be called to write whitespace-only content. + * If so, it is to be written as is (with no escaping), and does + * not contain non-whitespace characters (writer may validate this, + * and throw an exception if it does). + *

+ * This method is useful for things like outputting indentation. + * + * @since 3.0 + */ public void writeSpace(String text) throws XMLStreamException { try { _xmlWriter.writeSpace(text); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } - @Override + /** + * Method that can be called to write whitespace-only content. + * If so, it is to be written as is (with no escaping), and does + * not contain non-whitespace characters (writer may validate this, + * and throw an exception if it does). + *

+ * This method is useful for things like outputting indentation. + * + * @since 3.0 + */ public void writeSpace(char[] cbuf, int offset, int len) throws XMLStreamException { try { _xmlWriter.writeSpace(cbuf, offset, len); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } @@ -569,57 +628,15 @@ public void writeSpace(char[] cbuf, int offset, int len) throws XMLStreamExcepti /********************************************************************** */ - @Override + /** + * Method that should return current output location, if the writer + * keeps track of it; null if it does not. + */ public Location getLocation() { return new LocationImpl( // pub/sys ids not yet known _xmlWriter.getAbsOffset(), _xmlWriter.getRow(), _xmlWriter.getColumn()); } - /* - /********************************************************************** - /* StAX2, output methods - /********************************************************************** - */ - - @Override - public void writeRaw(String text) throws XMLStreamException { - _stateAnyOutput = true; - if (_stateStartElementOpen) { - _closeStartElement(_stateEmptyElement); - } - try { - _xmlWriter.writeRaw(text, 0, text.length()); - } catch (IOException ioe) { - throw new IoStreamException(ioe); - } - } - - @Override - public void writeRaw(String text, int start, int offset) throws XMLStreamException { - _stateAnyOutput = true; - if (_stateStartElementOpen) { - _closeStartElement(_stateEmptyElement); - } - try { - _xmlWriter.writeRaw(text, start, offset); - } catch (IOException ioe) { - throw new IoStreamException(ioe); - } - } - - @Override - public void writeRaw(char[] text, int offset, int length) throws XMLStreamException { - _stateAnyOutput = true; - if (_stateStartElementOpen) { - _closeStartElement(_stateEmptyElement); - } - try { - _xmlWriter.writeRaw(text, offset, length); - } catch (IOException ioe) { - throw new IoStreamException(ioe); - } - } - /* /********************************************************************** /* Package methods (ie not part of public API) @@ -631,7 +648,7 @@ public void writeRaw(char[] text, int offset, int length) throws XMLStreamExcept * main-level element (not namespace declaration or attribute) * is being output; except for end element which is handled differently. */ - protected void _closeStartElement(boolean emptyElem) throws XMLStreamException { + private void _closeStartElement(boolean emptyElem) throws XMLStreamException { _stateStartElementOpen = false; try { if (emptyElem) { @@ -640,7 +657,7 @@ protected void _closeStartElement(boolean emptyElem) throws XMLStreamException { _xmlWriter.writeStartTagEnd(); } } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } // Need bit more special handling for empty elements... @@ -658,7 +675,7 @@ protected void _closeStartElement(boolean emptyElem) throws XMLStreamException { } } - protected final boolean inPrologOrEpilog() { + private boolean inPrologOrEpilog() { return (_state != State.TREE); } @@ -668,33 +685,33 @@ protected final boolean inPrologOrEpilog() { /********************************************************************** */ - protected final void _writeAttribute(WName name, String value) throws XMLStreamException { + private void _writeAttribute(WName name, String value) throws XMLStreamException { try { _xmlWriter.writeAttribute(name, value); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } - protected final void _writeDefaultNamespace(String uri) throws XMLStreamException { + private void _writeDefaultNamespace(String uri) throws XMLStreamException { WName name = _symbols.findSymbol("xmlns"); try { _xmlWriter.writeAttribute(name, uri); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } - protected final void _writeNamespace(String prefix, String uri) throws XMLStreamException { + private void _writeNamespace(String prefix, String uri) throws XMLStreamException { WName name = _symbols.findSymbol("xmlns", prefix); try { _xmlWriter.writeAttribute(name, uri); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } - protected void _writeStartDocument(String version, String encoding) throws XMLStreamException { + private void _writeStartDocument(String version, String encoding) throws XMLStreamException { /* Not legal to output XML declaration if there has been ANY * output prior... that is, if we validate the structure. */ @@ -729,11 +746,11 @@ protected void _writeStartDocument(String version, String encoding) throws XMLSt try { _xmlWriter.writeXmlDeclaration(version, encoding, null); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } } - protected void _writeStartTag(WName name, boolean isEmpty) throws XMLStreamException { + private void _writeStartTag(WName name, boolean isEmpty) throws XMLStreamException { _stateAnyOutput = true; _stateStartElementOpen = true; @@ -748,12 +765,12 @@ protected void _writeStartTag(WName name, boolean isEmpty) throws XMLStreamExcep try { _xmlWriter.writeStartTagStart(name); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } _stateEmptyElement = isEmpty; } - protected void _writeStartTag(WName name, boolean isEmpty, String uri) throws XMLStreamException { + private void _writeStartTag(WName name, boolean isEmpty, String uri) throws XMLStreamException { _stateAnyOutput = true; _stateStartElementOpen = true; @@ -772,7 +789,7 @@ protected void _writeStartTag(WName name, boolean isEmpty, String uri) throws XM try { _xmlWriter.writeStartTagStart(name); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } _stateEmptyElement = isEmpty; } @@ -791,7 +808,7 @@ protected void _writeStartTag(WName name, boolean isEmpty, String uri) throws XM * bindings have been (or can be) output, and hence given prefix * may not be one that actually gets used. */ - protected void _verifyStartElement(String prefix, String localName) throws XMLStreamException { + private void _verifyStartElement(String prefix, String localName) throws XMLStreamException { // Need to finish an open start element? if (_stateStartElementOpen) { _closeStartElement(_stateEmptyElement); @@ -807,7 +824,7 @@ protected void _verifyStartElement(String prefix, String localName) throws XMLSt } } - protected final void _verifyWriteCData() throws XMLStreamException { + private void _verifyWriteCData() throws XMLStreamException { _stateAnyOutput = true; if (_stateStartElementOpen) { _closeStartElement(_stateEmptyElement); @@ -819,7 +836,7 @@ protected final void _verifyWriteCData() throws XMLStreamException { } } - protected final void _verifyWriteDTD() throws XMLStreamException { + private void _verifyWriteDTD() throws XMLStreamException { if (_state != State.PROLOG) { throw new XMLStreamException("Can not write DOCTYPE declaration (DTD) when not in prolog any more (state " + _state + "; start element(s) written)"); @@ -830,7 +847,7 @@ protected final void _verifyWriteDTD() throws XMLStreamException { } } - protected void _verifyRootElement() { + private void _verifyRootElement() { // !!! TBI: only relevant if we are actually validating? _state = State.TREE; @@ -842,11 +859,11 @@ protected void _verifyRootElement() { /********************************************************************** */ - protected static void throwOutputError(String msg) throws XMLStreamException { + private static void throwOutputError(String msg) throws XMLStreamException { throw new StreamExceptionBase(msg); } - protected static void throwOutputError(String format, Object arg) throws XMLStreamException { + private static void throwOutputError(String format, Object arg) throws XMLStreamException { String msg = MessageFormat.format(format, arg); throwOutputError(msg); } @@ -857,11 +874,11 @@ protected static void throwOutputError(String format, Object arg) throws XMLStre * and structural checking * is enabled. */ - protected static void _reportNwfStructure(String msg) throws XMLStreamException { + private static void _reportNwfStructure(String msg) throws XMLStreamException { throwOutputError(msg); } - protected static void _reportNwfStructure(String msg, Object arg) throws XMLStreamException { + private static void _reportNwfStructure(String msg, Object arg) throws XMLStreamException { throwOutputError(msg, arg); } @@ -871,11 +888,11 @@ protected static void _reportNwfStructure(String msg, Object arg) throws XMLStre * and content validation * is enabled. */ - protected static void _reportNwfContent(String msg) throws XMLStreamException { + private static void _reportNwfContent(String msg) throws XMLStreamException { throwOutputError(msg); } - protected static void _reportNwfContent(String msg, Object arg) throws XMLStreamException { + private static void _reportNwfContent(String msg, Object arg) throws XMLStreamException { throwOutputError(msg, arg); } @@ -913,7 +930,7 @@ private void _finishDocument() throws XMLStreamException { try { _xmlWriter.close(false); } catch (IOException ie) { - throw new IoStreamException(ie); + throw new StreamExceptionBase(ie); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WName.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WName.java index 19871385cba0..d0d8a2c019a9 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WName.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WName.java @@ -166,6 +166,6 @@ public final boolean hasName(String prefix, String localName) { return false; } } - return _localName.equals(localName); + return false; } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameFactory.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameFactory.java index 58dfc12183f1..86dcddd3cccd 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameFactory.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameFactory.java @@ -23,8 +23,8 @@ * that are needed by {@link WNameTable} instances, to be able to * construct {@link WName} instances for element and attribute names. */ -public abstract class WNameFactory { - public abstract WName constructName(String localName) throws XMLStreamException; +public interface WNameFactory { + WName constructName(String localName) throws XMLStreamException; - public abstract WName constructName(String prefix, String localName) throws XMLStreamException; + WName constructName(String prefix, String localName) throws XMLStreamException; } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameTable.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameTable.java index 9ef90e31025a..db01da9f18b1 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameTable.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WNameTable.java @@ -24,7 +24,7 @@ * This is a symbol table implementation used for storing byte-based * WNames. */ -public final class WNameTable extends NameTable { +public final class WNameTable implements NameTable { final static int MIN_HASH_SIZE = 16; final static int INITIAL_COLLISION_LEN = 32; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WriterConfig.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WriterConfig.java index 2ed5c589f4f5..5720bd5339b8 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WriterConfig.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/WriterConfig.java @@ -1,17 +1,14 @@ // Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. package com.azure.xml.implementation.aalto.out; -import java.util.*; -import java.lang.ref.SoftReference; - -import javax.xml.stream.XMLOutputFactory; // to get constants - -import com.azure.xml.implementation.stax2.XMLOutputFactory2; -import com.azure.xml.implementation.stax2.XMLStreamProperties; - import com.azure.xml.implementation.aalto.impl.CommonConfig; +import com.azure.xml.implementation.aalto.stax.OutputFactoryImpl; import com.azure.xml.implementation.aalto.util.BufferRecycler; +import javax.xml.stream.XMLOutputFactory; +import java.lang.ref.SoftReference; +import java.util.HashMap; + /** * This is the shared configuration object passed by the factory to writer. */ @@ -43,17 +40,17 @@ public final class WriterConfig extends CommonConfig { // Stax2: // not configurable, but are recognized - sProperties.put(XMLStreamProperties.XSP_NAMESPACE_AWARE, F_NS_AWARE); - sProperties.put(XMLStreamProperties.XSP_PROBLEM_REPORTER, null); + sProperties.put(XSP_NAMESPACE_AWARE, F_NS_AWARE); + sProperties.put(XSP_PROBLEM_REPORTER, null); // and then writer-side properties, mostly unsupported but recognized - sProperties.put(XMLOutputFactory2.P_AUTO_CLOSE_OUTPUT, F_AUTO_CLOSE_OUTPUT); + sProperties.put(OutputFactoryImpl.P_AUTO_CLOSE_OUTPUT, F_AUTO_CLOSE_OUTPUT); - sProperties.put(XMLOutputFactory2.P_AUTOMATIC_EMPTY_ELEMENTS, F_AUTO_EMPTY_ELEMS); - sProperties.put(XMLOutputFactory2.P_AUTOMATIC_NS_PREFIX, PROP_AUTO_NS_PREFIX); - sProperties.put(XMLOutputFactory2.P_TEXT_ESCAPER, null); - sProperties.put(XMLOutputFactory2.P_ATTR_VALUE_ESCAPER, null); + sProperties.put(OutputFactoryImpl.P_AUTOMATIC_EMPTY_ELEMENTS, F_AUTO_EMPTY_ELEMS); + sProperties.put(OutputFactoryImpl.P_AUTOMATIC_NS_PREFIX, PROP_AUTO_NS_PREFIX); + sProperties.put(OutputFactoryImpl.P_TEXT_ESCAPER, null); + sProperties.put(OutputFactoryImpl.P_ATTR_VALUE_ESCAPER, null); } /* @@ -150,14 +147,6 @@ public WriterConfig createNonShared() { return new WriterConfig(_encoding, _flags, _flagMods, _encodingContext, _propAutoNsPrefix); } - @Override - public String getExternalEncoding() { - /* !!! 01-Jan-2007, tatus: Can we distinguish this from the - * actual encoding? Should we be able to? - */ - return getActualEncoding(); - } - @Override public String getActualEncoding() { return _encoding; diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/XmlWriter.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/XmlWriter.java index 3f903dc747c6..ef3e9972e6b9 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/XmlWriter.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/out/XmlWriter.java @@ -16,18 +16,17 @@ package com.azure.xml.implementation.aalto.out; -import java.io.*; -import java.text.MessageFormat; -import java.util.Objects; - -import javax.xml.stream.*; - import com.azure.xml.implementation.aalto.impl.ErrorConsts; -import com.azure.xml.implementation.aalto.impl.IoStreamException; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; import com.azure.xml.implementation.aalto.util.CharsetNames; import com.azure.xml.implementation.aalto.util.XmlChars; import com.azure.xml.implementation.aalto.util.XmlConsts; +import javax.xml.stream.XMLStreamException; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Objects; + /** * Base class for output type / encoding-specific serializers * used to do actual physical output of serialized xml content. @@ -35,7 +34,7 @@ * checks directly related to encoding (including optional validity * checks for xml content) are implemented. */ -public abstract class XmlWriter extends WNameFactory { +public abstract class XmlWriter implements WNameFactory { protected final static int SURR1_FIRST = 0xD800; protected final static int SURR2_FIRST = 0xDC00; protected final static int SURR2_LAST = 0xDFFF; @@ -95,18 +94,6 @@ protected XmlWriter(WriterConfig cfg) { _copyBufferLen = _copyBuffer.length; } - /* - /********************************************************************** - /* Abstract methods for WNameFactory - /********************************************************************** - */ - - @Override - public abstract WName constructName(String localName) throws XMLStreamException; - - @Override - public abstract WName constructName(String prefix, String localName) throws XMLStreamException; - /* /********************************************************************** /* Extra configuration @@ -179,26 +166,6 @@ public void _releaseBuffers() { public abstract void writeSpace(char[] cbuf, int offset, int len) throws IOException, XMLStreamException; - /** - * Method that will try to output the content as specified. If - * the content passed in has embedded "--" in it, it will either - * add an intervening space between consequtive hyphens (if content - * fixing is enabled), or return the offset of the first hyphen in - * multi-hyphen sequence. - */ - public abstract int writeComment(String data) throws IOException, XMLStreamException; - - /** - * Older "legacy" output method for outputting DOCTYPE declaration. - * Assumes that the passed-in String contains a complete DOCTYPE - * declaration properly quoted. - */ - public abstract void writeDTD(String data) throws IOException, XMLStreamException; - - public abstract void writeEntityReference(WName name) throws IOException, XMLStreamException; - - public abstract int writePI(WName target, String data) throws IOException, XMLStreamException; - public abstract void writeRaw(String str, int offset, int len) throws IOException, XMLStreamException; public abstract void writeRaw(char[] cbuf, int offset, int len) throws IOException, XMLStreamException; @@ -344,7 +311,7 @@ protected void reportInvalidChar(int c) throws XMLStreamException { try { flush(); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } if (c == 0) { @@ -378,7 +345,7 @@ protected void throwOutputError(String msg) throws XMLStreamException { try { flush(); } catch (IOException ioe) { - throw new IoStreamException(ioe); + throw new StreamExceptionBase(ioe); } throw new XMLStreamException(msg); } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/InputFactoryImpl.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/InputFactoryImpl.java index a1471d3ebe8b..e8be83793b5e 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/InputFactoryImpl.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/InputFactoryImpl.java @@ -19,11 +19,11 @@ import com.azure.xml.implementation.aalto.in.ByteSourceBootstrapper; import com.azure.xml.implementation.aalto.in.CharSourceBootstrapper; import com.azure.xml.implementation.aalto.in.ReaderConfig; -import com.azure.xml.implementation.stax2.XMLInputFactory2; import javax.xml.stream.EventFilter; import javax.xml.stream.StreamFilter; import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLReporter; import javax.xml.stream.XMLResolver; import javax.xml.stream.XMLStreamException; @@ -33,12 +33,139 @@ import java.io.Reader; /** - * Aalto implementation of basic Stax factory (both - * {@link javax.xml.stream.XMLInputFactory} and {@link com.azure.xml.implementation.stax2.XMLInputFactory2}) + * Aalto implementation of basic Stax factory ({@link javax.xml.stream.XMLInputFactory}) * * @author Tatu Saloranta */ -public final class InputFactoryImpl extends XMLInputFactory2 { +public final class InputFactoryImpl extends XMLInputFactory { + /* + /********************************************************************** + /* Additional standard configuration properties + /********************************************************************** + */ + + // // // Parsing settings + + /** + * Whether reader will generate 'ignorable white space' events during + * prolog and epilog (before and after the main XML root element); + * if true, will generate those events; if false, + * will just ignore white space in these parts of the parsed document. + *

+ * Turning this feature off may give slight performance improvement, + * although usually effect should be negligible. This option is usually + * only turned on when round-trip output should be as similar to input + * as possible. + *

+ * Default value for this setting is implementation dependant. + */ + public final static String P_REPORT_PROLOG_WHITESPACE = "com.azure.xml.implementation.stax2.reportPrologWhitespace"; + + /** + * Whether cursor-based reader will ever generate CDATA events; if true, + * CDATA events may be generated for non-coalesced CDATA sections. If + * false, all CDATA sections are reported as CHARACTERS types. It may + * still be possible for event methods to distinguish between underlying + * type, but event type code will be reported as CHARACTERS. + *

+ * State of property does not have any effect on performance. + *

+ * Default value for this setting is implementation dependant. + */ + public final static String P_REPORT_CDATA = "http://java.sun.com/xml/stream/properties/report-cdata-event"; + + /** + * Whether stream readers are allowed to do lazy parsing, meaning + * to parse minimal part of the event when + * {@link XMLStreamReader#next} is called, and only parse the rest + * as needed (or skip remainder of no extra information is needed). + * Alternative to lazy parsing is called "eager parsing", and is + * what most xml parsers use by default. + *

+ * Enabling lazy parsing can improve performance for tasks where + * number of textual events are skipped. The downside is that + * not all well-formedness problems are reported when + * {@link XMLStreamReader#next} is called, but only when the + * rest of event are read or skipped. + *

+ * Default value for this setting is implementation dependant. + */ + public final static String P_LAZY_PARSING = "com.ctc.wstx.lazyParsing"; + + // // // Optimization settings + + /** + * Whether name symbols (element, attribute, entity and notation names, + * namespace prefixes) + * stream reader returns are guaranteed to have been String.intern()ed. + * Interning generally makes access faster (both internal and externally), + * and saves memory, but can add some overhead for processing. + * It may also be problematic for large symbol spaces; especially + * if xml content has unbounded value space for names. + *

+ * Default value for this setting is implementation dependant. + * Additionally implementations may have use different default for + * different types of stream readers. + */ + public final static String P_INTERN_NAMES = "com.azure.xml.implementation.stax2.internNames"; + + /** + * Whether namespace URIs + * stream reader returns are guaranteed to have been String.intern()ed. + * Interning can make access by fully-qualified name faster as well + * as save memory, but it can also add + * some overhead when encountering a namespace URI for the first + * time. + *

+ * Default value for this setting is implementation dependant. + */ + public final static String P_INTERN_NS_URIS = "com.azure.xml.implementation.stax2.internNsUris"; + + /** + * Property that determines whether stream reader instances are required + * to try to keep track of the parser Location in the input documents. + *

+ * When turned on, the stream reader should try to do its best to keep + * track of the locations, to be able to properly create + * XMLEvent objects with accurate Location information. + * Similarly, implementation should keep track of the location for + * error reporting purposes, and include this information within + * XMLStreamException instances. + *

+ * When turned off, implementations are allowed to optimize things, + * and only keep/pass partial Location information, or even none at + * all. Implementations are still encouraged to keep some location + * information for error reporting purposes, even if they do not + * maintain accurate + * XMLEvent locations, or exact byte/character offsets. + *

+ * Default value for this setting is true. + */ + public final static String P_PRESERVE_LOCATION = "com.azure.xml.implementation.stax2.preserveLocation"; + + // // // Input source settings + + /** + * Whether stream reader is to close the underlying input source (input + * stream, reader) when stream reader is closed. Basic StAX2 + * specification mandates this feature to be set to false by default + * (for sources that are passed by the application). + *

+ * Note: if set to true, readers are also allowed (but not required) to + * close the underlying input source when they do not need it any more, + * for example when encountering EOF, or when throwing an unrecoverable + * parsing exception + */ + public final static String P_AUTO_CLOSE_INPUT = "com.azure.xml.implementation.stax2.closeInputSource"; + + // // // Validation settings + + /** + * Property used to specify the source for DTD external subset to use + * instead of DTD specified by the XML document itself (if any). + */ + public final static String P_DTD_OVERRIDE = "com.azure.xml.implementation.stax2.propDtdOverride"; + /** * This is the currently active configuration that will be used * for readers created by this factory. @@ -126,12 +253,12 @@ public XMLEventReader createXMLEventReader(XMLStreamReader sr) { @Override public XMLStreamReader createXMLStreamReader(InputStream in) throws XMLStreamException { - return constructSR(in, null); + return constructSR(in); } @Override public XMLStreamReader createXMLStreamReader(InputStream in, String enc) throws XMLStreamException { - return constructSR(in, enc); + return constructSR(in); } @Override @@ -216,18 +343,18 @@ public void setXMLResolver(XMLResolver r) { * Method called when a non-shared copy of the current configuration * is needed. This is usually done when a new reader is constructed. */ - public ReaderConfig getNonSharedConfig(String extEncoding) { - return _config.createNonShared(extEncoding); + public ReaderConfig getNonSharedConfig() { + return _config.createNonShared(); } - private XMLStreamReader constructSR(InputStream in, String enc) throws XMLStreamException { - ReaderConfig cfg = getNonSharedConfig(enc); - return StreamReaderImpl.construct(ByteSourceBootstrapper.construct(cfg, in)); + private XMLStreamReader constructSR(InputStream in) throws XMLStreamException { + getNonSharedConfig(); + return StreamReaderImpl.construct(ByteSourceBootstrapper.construct(getNonSharedConfig(), in)); } private XMLStreamReader constructSR(Reader r) throws XMLStreamException { - ReaderConfig cfg = getNonSharedConfig(null); - return StreamReaderImpl.construct(CharSourceBootstrapper.construct(cfg, r)); + getNonSharedConfig(); + return StreamReaderImpl.construct(CharSourceBootstrapper.construct(getNonSharedConfig(), r)); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/OutputFactoryImpl.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/OutputFactoryImpl.java index a1cdc8862063..a66c8ac21c20 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/OutputFactoryImpl.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/OutputFactoryImpl.java @@ -18,15 +18,13 @@ import com.azure.xml.implementation.aalto.out.AsciiXmlWriter; import com.azure.xml.implementation.aalto.out.CharXmlWriter; import com.azure.xml.implementation.aalto.out.Latin1XmlWriter; -import com.azure.xml.implementation.aalto.out.NonRepairingStreamWriter; +import com.azure.xml.implementation.aalto.out.StreamWriterBase; import com.azure.xml.implementation.aalto.out.Utf8XmlWriter; import com.azure.xml.implementation.aalto.out.WNameTable; import com.azure.xml.implementation.aalto.out.WriterConfig; import com.azure.xml.implementation.aalto.out.XmlWriter; import com.azure.xml.implementation.aalto.util.CharsetNames; import com.azure.xml.implementation.aalto.util.XmlConsts; -import com.azure.xml.implementation.stax2.XMLOutputFactory2; -import com.azure.xml.implementation.stax2.XMLStreamWriter2; import javax.xml.stream.XMLEventWriter; import javax.xml.stream.XMLOutputFactory; @@ -42,7 +40,81 @@ * * @author Tatu Saloranta */ -public final class OutputFactoryImpl extends XMLOutputFactory2 { +public final class OutputFactoryImpl extends XMLOutputFactory { + /* + /********************************************************************** + /* Additional standard configuration properties + /********************************************************************** + */ + + // // General output options: + + /** + * Whether stream writers are allowed to automatically output empty + * elements, when a start element is immediately followed by matching + * end element. + * If true, will output empty elements; if false, will always create + * separate end element (unless a specific method that produces empty + * elements is called). + *

+ * Default value for implementations should be 'true'; both values should + * be recognized, and 'false' must be honored. However, 'true' value + * is only a suggestion, and need not be implemented (since there is + * the explicit 'writeEmptyElement()' method). + */ + public final static String P_AUTOMATIC_EMPTY_ELEMENTS = "com.azure.xml.implementation.stax2.automaticEmptyElements"; + + // // // Output stream/writer settings + + /** + * Whether stream writer is to close the underlying output + * destination (output stream, reader) when stream writer is closed. + * Basic StAX2 specification mandates this feature to be set to + * false by default + * (for destinations that are passed by the application and for which + * it has access to). + *

+ * Note: if set to true, writers are also allowed (but not required) to + * close the underlying destination when they do not need it any more, + * for example when throwing an (unrecoverable) exception + */ + public final static String P_AUTO_CLOSE_OUTPUT = "com.azure.xml.implementation.stax2.autoCloseOutput"; + + // // Namespace options: + + /** + * Prefix to use for automatically created namespace prefixes, when + * namespace support is enabled, the writer is in "repairing" + * mode, and a new prefix name is needed. The value is a String, + * and needs to be a valid namespace prefix in itself, as defined + * by the namespace specification. Will be prepended by a trailing + * part (often a sequence number), in order to make it unique to + * be usable as a temporary non-colliding prefix. + */ + public final static String P_AUTOMATIC_NS_PREFIX = "com.azure.xml.implementation.stax2.automaticNsPrefix"; + + // // Text/attribute value escaping options: + + /** + * Property that can be set if a custom output escaping for textual + * content is needed. + * The value set needs to be of type {@code EscapingWriterFactory}. + * When set, the factory will be used to create a per-writer + * instance used to escape all textual content written, both + * via explicit {@link XMLStreamWriter#writeCharacters} methods. + */ + public final static String P_TEXT_ESCAPER = "com.azure.xml.implementation.stax2.textEscaper"; + + /** + * Property that can be set if a custom output escaping for attribute + * value content is needed. + * The value set needs to be of type {@code EscapingWriterFactory}. + * When set, the factory will be used to create a per-writer + * instance used to escape all attribute values written, both + * via explicit {@link XMLStreamWriter#writeAttribute} methods. + */ + public final static String P_ATTR_VALUE_ESCAPER = "com.azure.xml.implementation.stax2.attrValueEscaper"; + /* /********************************************************************** /* Actual storage of configuration settings @@ -134,7 +206,7 @@ public void setProperty(String name, Object value) { // // @param forceAutoClose Whether writer should automatically close the // output stream or Writer, when close() is called on stream writer. - private XMLStreamWriter2 createSW(OutputStream out, Writer w, String enc) throws XMLStreamException { + private StreamWriterBase createSW(OutputStream out, Writer w, String enc) throws XMLStreamException { // Need to ensure that the configuration object is not shared // any more; otherwise later changes via factory could be // visible half-way through output... @@ -194,7 +266,7 @@ private XMLStreamWriter2 createSW(OutputStream out, Writer w, String enc) throws symbols = _config.getCharSymbols(xw); } - return new NonRepairingStreamWriter(cfg, xw, symbols); + return new StreamWriterBase(cfg, xw, symbols); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/StreamReaderImpl.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/StreamReaderImpl.java index a474901c6cab..b465df27697b 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/StreamReaderImpl.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/stax/StreamReaderImpl.java @@ -16,30 +16,29 @@ package com.azure.xml.implementation.aalto.stax; -import java.util.Collections; -import java.util.Objects; - -import javax.xml.namespace.NamespaceContext; -import javax.xml.namespace.QName; -import javax.xml.stream.Location; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - import com.azure.xml.implementation.aalto.UncheckedStreamException; -import com.azure.xml.implementation.aalto.WFCException; import com.azure.xml.implementation.aalto.impl.ErrorConsts; +import com.azure.xml.implementation.aalto.impl.StreamExceptionBase; import com.azure.xml.implementation.aalto.in.InputBootstrapper; import com.azure.xml.implementation.aalto.in.PName; import com.azure.xml.implementation.aalto.in.ReaderConfig; import com.azure.xml.implementation.aalto.in.XmlScanner; import com.azure.xml.implementation.aalto.util.TextAccumulator; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.util.Collections; +import java.util.Objects; + /** * Basic backend-independent {@link XMLStreamReader} implementation. * While the read implements Stax API, most of real work is delegated * to input (and thereby, encoding) specific backend implementations. */ -public class StreamReaderImpl implements XMLStreamReader { +public final class StreamReaderImpl implements XMLStreamReader { // // // Main state constants final static int STATE_PROLOG = 0; // Before root element @@ -56,11 +55,11 @@ public class StreamReaderImpl implements XMLStreamReader { /** * Underlying XML scanner */ - protected final XmlScanner _scanner; + private final XmlScanner _scanner; // // // Config flags: - protected final boolean _cfgCoalesceText; + private final boolean _cfgCoalesceText; /* /********************************************************************** @@ -68,17 +67,17 @@ public class StreamReaderImpl implements XMLStreamReader { /********************************************************************** */ - protected int _currToken; + private int _currToken; /** * Main parsing/tokenization state (STATE_xxx) */ - protected int _parseState; + private int _parseState; /** * Prefixed name associated with the current event, if any. */ - protected PName _currName; + private PName _currName; /** * If the current event is START_ELEMENT, number @@ -86,7 +85,7 @@ public class StreamReaderImpl implements XMLStreamReader { * Updated by reader, to make index checks for other attribute * access methods simpler. */ - protected int _attrCount; + private int _attrCount; /* /********************************************************************** @@ -98,7 +97,7 @@ public class StreamReaderImpl implements XMLStreamReader { * Prefixed root-name DOCTYPE declaration gave us, if any (note: also * serves as a marker to know if we have seen DOCTYPE yet) */ - protected PName _dtdRootName; + private PName _dtdRootName; /* /********************************************************************** @@ -153,7 +152,7 @@ public static StreamReaderImpl construct(InputBootstrapper bs) throws XMLStreamE * Note: method name is rather confusing (compare to {@link #getEncoding}). */ @Override - public final String getCharacterEncodingScheme() { + public String getCharacterEncodingScheme() { return _scanner.getConfig().getXmlDeclEncoding(); } @@ -164,7 +163,7 @@ public final String getCharacterEncodingScheme() { * {@link java.io.Reader}), it should return null. */ @Override - public final String getEncoding() { + public String getEncoding() { return _scanner.getConfig().getActualEncoding(); } @@ -174,12 +173,12 @@ public String getVersion() { } @Override - public final boolean isStandalone() { + public boolean isStandalone() { return (_scanner.getConfig().getXmlDeclStandalone() == ReaderConfig.STANDALONE_YES); } @Override - public final boolean standaloneSet() { + public boolean standaloneSet() { return (_scanner.getConfig().getXmlDeclStandalone() != ReaderConfig.STANDALONE_UNKNOWN); } @@ -212,7 +211,7 @@ public Object getProperty(String name) { // // // Attribute access: @Override - public final int getAttributeCount() { + public int getAttributeCount() { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -220,7 +219,7 @@ public final int getAttributeCount() { } @Override - public final String getAttributeLocalName(int index) { + public String getAttributeLocalName(int index) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -231,7 +230,7 @@ public final String getAttributeLocalName(int index) { } @Override - public final QName getAttributeName(int index) { + public QName getAttributeName(int index) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -242,7 +241,7 @@ public final QName getAttributeName(int index) { } @Override - public final String getAttributeNamespace(int index) { + public String getAttributeNamespace(int index) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -254,7 +253,7 @@ public final String getAttributeNamespace(int index) { } @Override - public final String getAttributePrefix(int index) { + public String getAttributePrefix(int index) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -266,7 +265,7 @@ public final String getAttributePrefix(int index) { } @Override - public final String getAttributeType(int index) { + public String getAttributeType(int index) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -277,7 +276,7 @@ public final String getAttributeType(int index) { } @Override - public final String getAttributeValue(int index) { + public String getAttributeValue(int index) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -288,7 +287,7 @@ public final String getAttributeValue(int index) { } @Override - public final String getAttributeValue(String nsURI, String localName) { + public String getAttributeValue(String nsURI, String localName) { if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -307,7 +306,7 @@ public final String getAttributeValue(String nsURI, String localName) { * */ @Override - public final String getElementText() throws XMLStreamException { + public String getElementText() throws XMLStreamException { if (_currToken != START_ELEMENT) { throwWfe(ErrorConsts.ERR_STATE_NOT_STELEM); } @@ -351,7 +350,7 @@ public final String getElementText() throws XMLStreamException { * any events has been explicitly returned. */ @Override - public final int getEventType() { + public int getEventType() { /* Only complication -- multi-part coalesced text is to be reported * as CHARACTERS always, never as CDATA (StAX specs). */ @@ -364,7 +363,7 @@ public final int getEventType() { } @Override - public final String getLocalName() { + public String getLocalName() { // Note: for this we need not (yet) finish reading element if (_currToken == START_ELEMENT || _currToken == END_ELEMENT || _currToken == ENTITY_REFERENCE) { return _currName.getLocalName(); @@ -375,7 +374,7 @@ public final String getLocalName() { // // // getLocation() defined in StreamScanner @Override - public final QName getName() { + public QName getName() { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -385,7 +384,7 @@ public final QName getName() { // // // Namespace access @Override - public final NamespaceContext getNamespaceContext() { + public NamespaceContext getNamespaceContext() { /* Unlike other getNamespaceXxx methods, this is available * for all events. * Note that the context is "live", ie. remains active (but not @@ -396,7 +395,7 @@ public final NamespaceContext getNamespaceContext() { } @Override - public final int getNamespaceCount() { + public int getNamespaceCount() { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -404,7 +403,7 @@ public final int getNamespaceCount() { } @Override - public final String getNamespacePrefix(int index) { + public String getNamespacePrefix(int index) { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -413,7 +412,7 @@ public final String getNamespacePrefix(int index) { } @Override - public final String getNamespaceURI() { + public String getNamespaceURI() { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -422,7 +421,7 @@ public final String getNamespaceURI() { } @Override - public final String getNamespaceURI(int index) { + public String getNamespaceURI(int index) { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -431,7 +430,7 @@ public final String getNamespaceURI(int index) { } @Override - public final String getNamespaceURI(String prefix) { + public String getNamespaceURI(String prefix) { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -442,27 +441,17 @@ public final String getNamespaceURI(String prefix) { } @Override - public final String getPIData() { - if (_currToken != PROCESSING_INSTRUCTION) { - throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_PI); - } - try { - return _scanner.getText(); - } catch (XMLStreamException sex) { - throw UncheckedStreamException.createFrom(sex); - } + public String getPIData() { + throw new UnsupportedOperationException(); } @Override - public final String getPITarget() { - if (_currToken != PROCESSING_INSTRUCTION) { - throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_PI); - } - return _currName.getLocalName(); + public String getPITarget() { + throw new UnsupportedOperationException(); } @Override - public final String getPrefix() { + public String getPrefix() { if (_currToken != START_ELEMENT && _currToken != END_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_ELEM); } @@ -472,7 +461,7 @@ public final String getPrefix() { } @Override - public final String getText() { + public String getText() { if (((1 << _currToken) & MASK_GET_TEXT) == 0) { throwNotTextual(); } @@ -484,7 +473,7 @@ public final String getText() { } @Override - public final char[] getTextCharacters() { + public char[] getTextCharacters() { if (((1 << _currToken) & MASK_GET_TEXT_XXX) == 0) { throwNotTextXxx(); } @@ -496,7 +485,7 @@ public final char[] getTextCharacters() { } @Override - public final int getTextCharacters(int srcStart, char[] target, int targetStart, int len) { + public int getTextCharacters(int srcStart, char[] target, int targetStart, int len) { if (((1 << _currToken) & MASK_GET_TEXT_XXX) == 0) { throwNotTextXxx(); } @@ -508,7 +497,7 @@ public final int getTextCharacters(int srcStart, char[] target, int targetStart, } @Override - public final int getTextLength() { + public int getTextLength() { if (((1 << _currToken) & MASK_GET_TEXT_XXX) == 0) { throwNotTextXxx(); } @@ -520,7 +509,7 @@ public final int getTextLength() { } @Override - public final int getTextStart() { + public int getTextStart() { if (((1 << _currToken) & MASK_GET_TEXT_XXX) == 0) { throwNotTextXxx(); } @@ -531,22 +520,22 @@ public final int getTextStart() { } @Override - public final boolean hasName() { + public boolean hasName() { return (_currToken == START_ELEMENT) || (_currToken == END_ELEMENT); } @Override - public final boolean hasNext() { + public boolean hasNext() { return (_currToken != END_DOCUMENT); } @Override - public final boolean hasText() { + public boolean hasText() { return (((1 << _currToken) & MASK_GET_TEXT) != 0); } @Override - public final boolean isAttributeSpecified(int index) { + public boolean isAttributeSpecified(int index) { // No need to check for ATTRIBUTE since we never return that... if (_currToken != START_ELEMENT) { throw new IllegalStateException(ErrorConsts.ERR_STATE_NOT_STELEM); @@ -555,22 +544,22 @@ public final boolean isAttributeSpecified(int index) { } @Override - public final boolean isCharacters() { + public boolean isCharacters() { return (getEventType() == CHARACTERS); } @Override - public final boolean isEndElement() { + public boolean isEndElement() { return (_currToken == END_ELEMENT); } @Override - public final boolean isStartElement() { + public boolean isStartElement() { return (_currToken == START_ELEMENT); } @Override - public final boolean isWhiteSpace() { + public boolean isWhiteSpace() { if (_currToken == CHARACTERS || _currToken == CDATA) { try { return _scanner.isTextWhitespace(); @@ -582,7 +571,7 @@ public final boolean isWhiteSpace() { } @Override - public final void require(int type, String nsUri, String localName) throws XMLStreamException { + public void require(int type, String nsUri, String localName) throws XMLStreamException { int curr = _currToken; /* There are some special cases; specifically, CDATA @@ -609,7 +598,7 @@ public final void require(int type, String nsUri, String localName) throws XMLSt + ErrorConsts.tokenTypeDesc(_currToken) + ")"); } String n = getLocalName(); - if (!Objects.equals(n, localName) && !n.equals(localName)) { + if (!Objects.equals(n, localName)) { throwWfe("Expected local name '" + localName + "'; current local name '" + n + "'."); } } @@ -640,7 +629,7 @@ public final void require(int type, String nsUri, String localName) throws XMLSt */ @Override - public final int next() throws XMLStreamException { + public int next() throws XMLStreamException { if (_parseState == STATE_TREE) { int type = _scanner.nextFromTree(); if (type == XmlScanner.TOKEN_EOI) { // Not allowed here... @@ -699,7 +688,7 @@ public final int next() throws XMLStreamException { } @Override - public final int nextTag() throws XMLStreamException { + public int nextTag() throws XMLStreamException { while (true) { int next = next(); @@ -734,12 +723,12 @@ public final int nextTag() throws XMLStreamException { * set to true). */ @Override - public final void close() throws XMLStreamException { + public void close() throws XMLStreamException { _closeScanner(); } @Override - public final Location getLocation() { + public Location getLocation() { return _scanner.getStartLocation(); } @@ -753,16 +742,16 @@ public final Location getLocation() { * Helper method called when {@link #getElementText} (et al) method encounters * a token type it should not, during text coalescing */ - protected void _reportNonTextEvent(int type) throws XMLStreamException { + private void _reportNonTextEvent(int type) throws XMLStreamException { throwWfe("Expected a text token, got " + ErrorConsts.tokenTypeDesc(type) + "."); } - protected Location getLastCharLocation() { + private Location getLastCharLocation() { // !!! TBI return _scanner.getCurrentLocation(); } - protected int handlePrologEoi(boolean isProlog) throws XMLStreamException { + private int handlePrologEoi(boolean isProlog) throws XMLStreamException { // Either way, we can now close the reader close(); @@ -777,7 +766,7 @@ protected int handlePrologEoi(boolean isProlog) throws XMLStreamException { * Method called when hitting an end-of-input within tree, after * a valid token */ - protected void handleTreeEoi() throws XMLStreamException { + private void handleTreeEoi() throws XMLStreamException { _currToken = END_DOCUMENT; // !!! Should indicate open tree etc. throwUnexpectedEOI(ErrorConsts.SUFFIX_IN_TREE); @@ -787,8 +776,8 @@ protected void handleTreeEoi() throws XMLStreamException { * Throws generic parse error with specified message and current parsing * location. */ - protected void throwWfe(String msg) throws XMLStreamException { - throw new WFCException(msg, getLastCharLocation()); + private void throwWfe(String msg) throws XMLStreamException { + throw new StreamExceptionBase(msg, getLastCharLocation()); } private void throwNotTextual() { @@ -800,11 +789,11 @@ private void throwNotTextXxx() { "getTextXxx() methods can not be called on " + ErrorConsts.tokenTypeDesc(_currToken)); } - protected void throwUnexpectedEOI(String msg) throws XMLStreamException { + private void throwUnexpectedEOI(String msg) throws XMLStreamException { throwWfe("Unexpected End-of-input" + msg); } - protected void reportInvalidAttrIndex(int index) { + private void reportInvalidAttrIndex(int index) { /* 24-Jun-2006, tatus: Stax API doesn't specify what (if anything) * should be thrown. Although RI throws IndexOutOfBounds * let's throw IllegalArgumentException: that's what StaxTest @@ -824,7 +813,7 @@ protected void reportInvalidAttrIndex(int index) { * Method called to close scanner, by asking it to release resource * it has, and potentially also close the underlying stream. */ - protected void _closeScanner() throws XMLStreamException { + private void _closeScanner() throws XMLStreamException { if (_parseState != STATE_CLOSED) { _parseState = STATE_CLOSED; if (_currToken != END_DOCUMENT) { @@ -841,7 +830,7 @@ protected void _closeScanner() throws XMLStreamException { */ @Override - public final String toString() { + public String toString() { return "[Aalto stream reader, scanner: " + _scanner + "]"; } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/CharsetNames.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/CharsetNames.java index c85d05d5bfd1..2660a807fc73 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/CharsetNames.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/CharsetNames.java @@ -8,7 +8,7 @@ * Simple utility class that normalizes given character input character * set names into canonical (within context of this processor) names */ -public final class CharsetNames implements XmlConsts { +public final class CharsetNames { /* /********************************************************** /* Canonical names used internally @@ -273,10 +273,10 @@ public static boolean equalEncodings(String str1, String str2) { } // if not equal, maybe there are WS/hyphen/underscores to skip - while (c1 <= CHAR_SPACE || c1 == '_' || c1 == '-') { + while (c1 <= XmlConsts.CHAR_SPACE || c1 == '_' || c1 == '-') { c1 = (i1 >= len1) ? EOS : str1.charAt(i1++); } - while (c2 <= CHAR_SPACE || c2 == '_' || c2 == '-') { + while (c2 <= XmlConsts.CHAR_SPACE || c2 == '_' || c2 == '-') { c2 = (i2 >= len2) ? EOS : str2.charAt(i2++); } // Ok, how about case differences, then? @@ -312,10 +312,10 @@ public static boolean encodingStartsWith(String enc, String prefix) { } // if not equal, maybe there are WS/hyphen/underscores to skip - while (c1 <= CHAR_SPACE || c1 == '_' || c1 == '-') { + while (c1 <= XmlConsts.CHAR_SPACE || c1 == '_' || c1 == '-') { c1 = (i1 >= len1) ? EOS : enc.charAt(i1++); } - while (c2 <= CHAR_SPACE || c2 == '_' || c2 == '-') { + while (c2 <= XmlConsts.CHAR_SPACE || c2 == '_' || c2 == '-') { c2 = (i2 >= len2) ? EOS : prefix.charAt(i2++); } // Ok, how about case differences, then? diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/DataUtil.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/DataUtil.java index 04aac90c8e16..2f8a18de859e 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/DataUtil.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/DataUtil.java @@ -1,7 +1,7 @@ // Original file from https://github.com/FasterXML/aalto-xml under Apache-2.0 license. package com.azure.xml.implementation.aalto.util; -import java.lang.reflect.Array; +import java.util.Arrays; public final class DataUtil { private DataUtil() { @@ -17,32 +17,20 @@ public static int[] growArrayBy(int[] arr, int more) { if (arr == null) { return new int[more]; } - int[] old = arr; - int len = arr.length; - arr = new int[len + more]; - System.arraycopy(old, 0, arr, 0, len); - return arr; + return Arrays.copyOf(arr, arr.length + more); } public static char[] growArrayBy(char[] arr, int more) { if (arr == null) { return new char[more]; } - char[] old = arr; - int len = arr.length; - arr = new char[len + more]; - System.arraycopy(old, 0, arr, 0, len); - return arr; + return Arrays.copyOf(arr, arr.length + more); } - public static Object growAnyArrayBy(Object arr, int more) { + public static T[] growAnyArrayBy(T[] arr, int more) { if (arr == null) { throw new IllegalArgumentException("Null array"); } - Object old = arr; - int len = Array.getLength(arr); - arr = Array.newInstance(arr.getClass().getComponentType(), len + more); - System.arraycopy(old, 0, arr, 0, len); - return arr; + return Arrays.copyOf(arr, arr.length + more); } } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/NameTable.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/NameTable.java index 75b6401107ce..41a794b7c30a 100644 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/NameTable.java +++ b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/aalto/util/NameTable.java @@ -22,16 +22,13 @@ * reused. Most of actual use functionality is in sub-classes, since * access details depend on how symbols are handled at low level. */ -public abstract class NameTable { - protected NameTable() { - } - - public abstract int size(); +public interface NameTable { + int size(); /** * Method called to check to quickly see if a child symbol table * may have gotten additional entries. Used for checking to see * if a child table should be merged into shared table. */ - public abstract boolean maybeDirty(); + boolean maybeDirty(); } diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLInputFactory2.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLInputFactory2.java deleted file mode 100644 index c747555082f6..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLInputFactory2.java +++ /dev/null @@ -1,161 +0,0 @@ -// Original file from https://github.com/FasterXML/stax2-api under BSD 2-Clause "Simplified" License -package com.azure.xml.implementation.stax2; - -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLStreamReader; - -/** - * Extension of {@link XMLInputFactory} that adds some convenience factory - * methods as new standard properties that conforming stream - * reader factory and instance implementations need to - * recognize, and preferably support. There are also some profile-based - * configuration methods which allow implementations to set proper goal-based - * values for custom properties. - *
- * NOTE: although actual values for the property names are - * visible, implementations should try to use the symbolic constants - * defined here instead, to avoid typos. - * - * @version 3.0 01/21/2007 - * @author Tatu Saloranta (tatu.saloranta@iki.fi) - */ -public abstract class XMLInputFactory2 extends XMLInputFactory implements XMLStreamProperties { - - /* - /********************************************************************** - /* Additional standard configuration properties - /********************************************************************** - */ - - // // // Parsing settings - - /** - * Whether reader will generate 'ignorable white space' events during - * prolog and epilog (before and after the main XML root element); - * if true, will generate those events; if false, - * will just ignore white space in these parts of the parsed document. - *

- * Turning this feature off may give slight performance improvement, - * although usually effect should be negligible. This option is usually - * only turned on when round-trip output should be as similar to input - * as possible. - *

- * Default value for this setting is implementation dependant. - */ - public final static String P_REPORT_PROLOG_WHITESPACE = "com.azure.xml.implementation.stax2.reportPrologWhitespace"; - - /** - * Whether cursor-based reader will ever generate CDATA events; if true, - * CDATA events may be generated for non-coalesced CDATA sections. If - * false, all CDATA sections are reported as CHARACTERS types. It may - * still be possible for event methods to distinguish between underlying - * type, but event type code will be reported as CHARACTERS. - *

- * State of property does not have any effect on performance. - *

- * Default value for this setting is implementation dependant. - */ - public final static String P_REPORT_CDATA = "http://java.sun.com/xml/stream/properties/report-cdata-event"; - - /** - * Whether stream readers are allowed to do lazy parsing, meaning - * to parse minimal part of the event when - * {@link XMLStreamReader#next} is called, and only parse the rest - * as needed (or skip remainder of no extra information is needed). - * Alternative to lazy parsing is called "eager parsing", and is - * what most xml parsers use by default. - *

- * Enabling lazy parsing can improve performance for tasks where - * number of textual events are skipped. The downside is that - * not all well-formedness problems are reported when - * {@link XMLStreamReader#next} is called, but only when the - * rest of event are read or skipped. - *

- * Default value for this setting is implementation dependant. - */ - public final static String P_LAZY_PARSING = "com.ctc.wstx.lazyParsing"; - - // // // Optimization settings - - /** - * Whether name symbols (element, attribute, entity and notation names, - * namespace prefixes) - * stream reader returns are guaranteed to have been String.intern()ed. - * Interning generally makes access faster (both internal and externally), - * and saves memory, but can add some overhead for processing. - * It may also be problematic for large symbol spaces; especially - * if xml content has unbounded value space for names. - *

- * Default value for this setting is implementation dependant. - * Additionally implementations may have use different default for - * different types of stream readers. - */ - public final static String P_INTERN_NAMES = "com.azure.xml.implementation.stax2.internNames"; - - /** - * Whether namespace URIs - * stream reader returns are guaranteed to have been String.intern()ed. - * Interning can make access by fully-qualified name faster as well - * as save memory, but it can also add - * some overhead when encountering a namespace URI for the first - * time. - *

- * Default value for this setting is implementation dependant. - */ - public final static String P_INTERN_NS_URIS = "com.azure.xml.implementation.stax2.internNsUris"; - - /** - * Property that determines whether stream reader instances are required - * to try to keep track of the parser Location in the input documents. - *

- * When turned on, the stream reader should try to do its best to keep - * track of the locations, to be able to properly create - * XMLEvent objects with accurate Location information. - * Similarly, implementation should keep track of the location for - * error reporting purposes, and include this information within - * XMLStreamException instances. - *

- * When turned off, implementations are allowed to optimize things, - * and only keep/pass partial Location information, or even none at - * all. Implementations are still encouraged to keep some location - * information for error reporting purposes, even if they do not - * maintain accurate - * XMLEvent locations, or exact byte/character offsets. - *

- * Default value for this setting is true. - */ - public final static String P_PRESERVE_LOCATION = "com.azure.xml.implementation.stax2.preserveLocation"; - - // // // Input source settings - - /** - * Whether stream reader is to close the underlying input source (input - * stream, reader) when stream reader is closed. Basic StAX2 - * specification mandates this feature to be set to false by default - * (for sources that are passed by the application). - *

- * Note: if set to true, readers are also allowed (but not required) to - * close the underlying input source when they do not need it any more, - * for example when encountering EOF, or when throwing an unrecoverable - * parsing exception - */ - public final static String P_AUTO_CLOSE_INPUT = "com.azure.xml.implementation.stax2.closeInputSource"; - - // // // Validation settings - - /** - * Property used to specify the source for DTD external subset to use - * instead of DTD specified by the XML document itself (if any). - */ - public final static String P_DTD_OVERRIDE = "com.azure.xml.implementation.stax2.propDtdOverride"; - - /* - /********************************************************************** - /* Life-cycle - /********************************************************************** - */ - - protected XMLInputFactory2() { - super(); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLOutputFactory2.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLOutputFactory2.java deleted file mode 100644 index dff008dfdd10..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLOutputFactory2.java +++ /dev/null @@ -1,128 +0,0 @@ -// Original file from https://github.com/FasterXML/stax2-api under BSD 2-Clause "Simplified" License -package com.azure.xml.implementation.stax2; - -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamWriter; // only for javadoc - -/** - * Extension of {@link javax.xml.stream.XMLInputFactory} to add - * missing functionality. - *

- * Also contains extended standard properties that conforming stream - * writer factory and instance implementations should at least - * recognize, and preferably support. - *
- * NOTE: although actual values for the property names are - * visible, implementations should try to use the symbolic constants - * defined here instead, to avoid typos. - *

- * Notes about properties that output factories should support: - *

    - *
  • {@link XMLStreamProperties#XSP_NAMESPACE_AWARE}: - * Whether output classes should keep track of and output namespace - * information provided via write methods. - * When enabled (set to Boolean.TRUE), will use all namespace information - * provided, and does not allow colons in names (local name, prefix).
    - * What exactly is kept track - * of depends on other settings, specifically whether - * writer is in "repairing" mode or not. - * When disabled, will only make use of local name part, which - * may contain colons, and ignore prefix and namespace URI if any - * are passed.
    - * Turning this option off may improve performance if no namespace - * handling is needed.
    - * Default value for implementations should be 'true'; implementations - * are not required to implement 'false'. - *
  • - *
  • {@link XMLStreamProperties#XSP_PROBLEM_REPORTER}: - *
  • - *
- * - * @version 3.0 01/21/2007 - * @author Tatu Saloranta (tatu.saloranta@iki.fi) - */ -public abstract class XMLOutputFactory2 extends XMLOutputFactory implements XMLStreamProperties { - /* - /********************************************************************** - /* Additional standard configuration properties - /********************************************************************** - */ - - // // General output options: - - /** - * Whether stream writers are allowed to automatically output empty - * elements, when a start element is immediately followed by matching - * end element. - * If true, will output empty elements; if false, will always create - * separate end element (unless a specific method that produces empty - * elements is called). - *

- * Default value for implementations should be 'true'; both values should - * be recognized, and 'false' must be honored. However, 'true' value - * is only a suggestion, and need not be implemented (since there is - * the explicit 'writeEmptyElement()' method). - */ - public final static String P_AUTOMATIC_EMPTY_ELEMENTS = "com.azure.xml.implementation.stax2.automaticEmptyElements"; - - // // // Output stream/writer settings - - /** - * Whether stream writer is to close the underlying output - * destination (output stream, reader) when stream writer is closed. - * Basic StAX2 specification mandates this feature to be set to - * false by default - * (for destinations that are passed by the application and for which - * it has access to). - *

- * Note: if set to true, writers are also allowed (but not required) to - * close the underlying destination when they do not need it any more, - * for example when throwing an (unrecoverable) exception - */ - public final static String P_AUTO_CLOSE_OUTPUT = "com.azure.xml.implementation.stax2.autoCloseOutput"; - - // // Namespace options: - - /** - * Prefix to use for automatically created namespace prefixes, when - * namespace support is enabled, the writer is in "repairing" - * mode, and a new prefix name is needed. The value is a String, - * and needs to be a valid namespace prefix in itself, as defined - * by the namespace specification. Will be prepended by a trailing - * part (often a sequence number), in order to make it unique to - * be usable as a temporary non-colliding prefix. - */ - public final static String P_AUTOMATIC_NS_PREFIX = "com.azure.xml.implementation.stax2.automaticNsPrefix"; - - // // Text/attribute value escaping options: - - /** - * Property that can be set if a custom output escaping for textual - * content is needed. - * The value set needs to be of type {@code EscapingWriterFactory}. - * When set, the factory will be used to create a per-writer - * instance used to escape all textual content written, both - * via explicit {@link XMLStreamWriter#writeCharacters} methods. - */ - public final static String P_TEXT_ESCAPER = "com.azure.xml.implementation.stax2.textEscaper"; - - /** - * Property that can be set if a custom output escaping for attribute - * value content is needed. - * The value set needs to be of type {@code EscapingWriterFactory}. - * When set, the factory will be used to create a per-writer - * instance used to escape all attribute values written, both - * via explicit {@link XMLStreamWriter#writeAttribute} methods. - */ - public final static String P_ATTR_VALUE_ESCAPER = "com.azure.xml.implementation.stax2.attrValueEscaper"; - - /* - /********************************************************************** - /* Life-cycle - /********************************************************************** - */ - - protected XMLOutputFactory2() { - super(); - } -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLStreamProperties.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLStreamProperties.java deleted file mode 100644 index 255acdea1acf..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLStreamProperties.java +++ /dev/null @@ -1,77 +0,0 @@ -// Original file from https://github.com/FasterXML/stax2-api under BSD 2-Clause "Simplified" License -package com.azure.xml.implementation.stax2; - -/** - * This interface defines configuration properties shared by multiple - * kinds of factories (input, output, validation) or instances produces - * (readers, writers, validators). - *

- * Some of the properties here are same as ones earlier defined in - * {@link javax.xml.stream.XMLInputFactory} and - * {@link javax.xml.stream.XMLOutputFactory}, and are redeclared here - * to emphasize the fact they are usable with broader context (esp. - * properties that use to be only used with input factories but can - * now be used with output or validation factories). - */ -public interface XMLStreamProperties { - // // // Information about implementation - - /** - * This read-only property returns name of the implementation. It - * can be used to determine implementation-specific feature sets, - * in case other methods (calling isPropertySupported) - * does not work adequately. - */ - String XSP_IMPLEMENTATION_NAME = "com.azure.xml.implementation.stax2.implName"; - - /** - * This read-only property returns the version of the implementation, - * and is to be used with implementation name - * ({@link #XSP_IMPLEMENTATION_NAME}) property. - */ - String XSP_IMPLEMENTATION_VERSION = "com.azure.xml.implementation.stax2.implVersion"; - - /** - * This read-only property indicates whether the implementation - * supports xml 1.1 content; Boolean.TRUE indicates it does, - * Boolean.FALSE that it does not. - */ - String XSP_SUPPORTS_XML11 = "com.azure.xml.implementation.stax2.supportsXml11"; - - // // // Re-declared properties from XMLInputFactory - - /** - * Property that can be set to indicate that namespace information is - * to be handled in conformance to the xml namespaces specifiation; or - * false to indicate no namespace handling should be done. - */ - String XSP_NAMESPACE_AWARE = "javax.xml.stream.isNamespaceAware"; - - /** - * Property that can be set to specify a problem handler which will get - * notified of non-fatal problem (validation errors in non-validating mode, - * warnings). Its value has to be of type - * {@link javax.xml.stream.XMLReporter} - */ - String XSP_PROBLEM_REPORTER = "javax.xml.stream.reporter"; - - // // // Generic XML feature support: - - /** - * Read/write property that can be set to change the level of xml:id - * specification support, if the implementation implements xml:id - * specification. - *

- * Default value is implementation-specific, but recommended default - * value is XSP_V_XMLID_TYPING for implementations - * that do support Xml:id specification: those that do not, have to - * default to XSP_V_XMLID_NONE. - * For Xml:id-enabled implementations, typing support is the most - * logical default, since it - * provides the intuitive behavior of xml:id functionality, as well - * as reasonable performance (very little overhead in non-validating - * mode; usual id checking overhead for validating mode). - */ - String XSP_SUPPORT_XMLID = "com.azure.xml.implementation.stax2.supportXmlId"; - -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLStreamWriter2.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLStreamWriter2.java deleted file mode 100644 index fb3d8fe3b624..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/XMLStreamWriter2.java +++ /dev/null @@ -1,122 +0,0 @@ -// Original file from https://github.com/FasterXML/stax2-api under BSD 2-Clause "Simplified" License -package com.azure.xml.implementation.stax2; - -import javax.xml.stream.Location; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - -/** - * Extended interface that implements functionality that is necessary - * to properly build event API on top of {@link XMLStreamWriter}, - * as well as to configure individual instances. - * It also adds limited number of methods that are important for - * efficient pass-through processing (such as one needed when routing - * SOAP-messages). - *

- * Since version 3.0, stream writer will also implement "Typed Access API" - * on output side. - * - * @version 3.0.1 06-Nov-2008 - * @author Tatu Saloranta (tatu.saloranta@iki.fi) - */ -public interface XMLStreamWriter2 extends XMLStreamWriter { - - /* - /********************************************************************** - /* Other accessors, mutators - /********************************************************************** - */ - - /** - * Method that should return current output location, if the writer - * keeps track of it; null if it does not. - */ - Location getLocation(); - - /* - /********************************************************************** - /* Write methods base interface is missing - /********************************************************************** - */ - - /** - * Method that can be called to write whitespace-only content. - * If so, it is to be written as is (with no escaping), and does - * not contain non-whitespace characters (writer may validate this, - * and throw an exception if it does). - *

- * This method is useful for things like outputting indentation. - * - * @since 3.0 - */ - void writeSpace(String text) throws XMLStreamException; - - /** - * Method that can be called to write whitespace-only content. - * If so, it is to be written as is (with no escaping), and does - * not contain non-whitespace characters (writer may validate this, - * and throw an exception if it does). - *

- * This method is useful for things like outputting indentation. - * - * @since 3.0 - */ - void writeSpace(char[] text, int offset, int length) throws XMLStreamException; - - /* - /********************************************************************** - /* Pass-through methods - /********************************************************************** - */ - - /** - * Method that writes specified content as is, without encoding or - * deciphering it in any way. It will not update state of the writer - * (except by possibly flushing output of previous writes, like - * finishing a start element), - * nor be validated in any way. As such, care must be taken, if this - * method is used. - *

- * Method is usually used when encapsulating output from another writer - * as a sub-tree, or when passing through XML fragments. - *

- * NOTE: since text to be written may be anything, including markup, - * it can not be reliably validated. Because of this, validator(s) - * attached to the writer will NOT be informed about writes. - */ - void writeRaw(String text) throws XMLStreamException; - - /** - * Method that writes specified content as is, without encoding or - * deciphering it in any way. It will not update state of the writer - * (except by possibly flushing output of previous writes, like - * finishing a start element), - * nor be validated in any way. As such, care must be taken, if this - * method is used. - *

- * Method is usually used when encapsulating output from another writer - * as a sub-tree, or when passing through XML fragments. - *

- * NOTE: since text to be written may be anything, including markup, - * it can not be reliably validated. Because of this, validator(s) - * attached to the writer will NOT be informed about writes. - */ - void writeRaw(String text, int offset, int length) throws XMLStreamException; - - /** - * Method that writes specified content as is, without encoding or - * deciphering it in any way. It will not update state of the writer - * (except by possibly flushing output of previous writes, like - * finishing a start element), - * nor be validated in any way. As such, care must be taken, if this - * method is used. - *

- * Method is usually used when encapsulating output from another writer - * as a sub-tree, or when passing through XML fragments. - *

- * NOTE: since text to be written may be anything, including markup, - * it can not be reliably validated. Because of this, validator(s) - * attached to the writer will NOT be informed about writes. - */ - void writeRaw(char[] text, int offset, int length) throws XMLStreamException; -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/ri/Stax2Util.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/ri/Stax2Util.java deleted file mode 100644 index 2a0acfdd1d41..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/ri/Stax2Util.java +++ /dev/null @@ -1,67 +0,0 @@ -// Original file from https://github.com/FasterXML/stax2-api under BSD 2-Clause "Simplified" License -/* Stax2 API extension for Streaming Api for Xml processing (StAX). - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in the file LICENSE which is - * included with the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.azure.xml.implementation.stax2.ri; - -import javax.xml.stream.XMLStreamConstants; - -public final class Stax2Util implements XMLStreamConstants { - private Stax2Util() { - } // no instantiation - - /** - * Method that converts given standard Stax event type into - * textual representation. - */ - public static String eventTypeDesc(int type) { - switch (type) { - case START_ELEMENT: - return "START_ELEMENT"; - - case END_ELEMENT: - return "END_ELEMENT"; - - case START_DOCUMENT: - return "START_DOCUMENT"; - - case END_DOCUMENT: - return "END_DOCUMENT"; - - case CHARACTERS: - return "CHARACTERS"; - - case CDATA: - return "CDATA"; - - case SPACE: - return "SPACE"; - - case COMMENT: - return "COMMENT"; - - case PROCESSING_INSTRUCTION: - return "PROCESSING_INSTRUCTION"; - - case DTD: - return "DTD"; - - case ENTITY_REFERENCE: - return "ENTITY_REFERENCE"; - } - return "[" + type + "]"; - } - -} diff --git a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/ri/Stax2WriterImpl.java b/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/ri/Stax2WriterImpl.java deleted file mode 100644 index ae1434372c15..000000000000 --- a/sdk/serialization/azure-xml/src/main/java/com/azure/xml/implementation/stax2/ri/Stax2WriterImpl.java +++ /dev/null @@ -1,78 +0,0 @@ -// Original file from https://github.com/FasterXML/stax2-api under BSD 2-Clause "Simplified" License -/* Stax2 API extension for Streaming Api for Xml processing (StAX). - * - * Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi - * - * Licensed under the License specified in file LICENSE, included with - * the source code. - * You may not use this file except in compliance with the License. - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.azure.xml.implementation.stax2.ri; - -import javax.xml.stream.*; - -import com.azure.xml.implementation.stax2.*; - -/** - * This is a partial base implementation of {@link XMLStreamWriter2}, - * the extended stream writer that is part of Stax2. - */ -public abstract class Stax2WriterImpl implements XMLStreamWriter2 /* From Stax2 */ - , XMLStreamConstants { - /* - /////////////////////////////////////////////////////////// - // Life-cycle methods - /////////////////////////////////////////////////////////// - */ - - protected Stax2WriterImpl() { - } - - /* - /////////////////////////////////////////////////////////// - // XMLStreamWriter2 (StAX2) implementation - /////////////////////////////////////////////////////////// - */ - - @Override - public abstract Location getLocation(); - - @Override - public void writeSpace(String text) throws XMLStreamException { - /* Hmmh. Two choices: either try to write as regular characters, - * or output as is via raw calls. Latter would be safer, if we - * had access to it; former may escape incorrectly. - * While this may not be optimal, let's try former - */ - writeRaw(text); - } - - @Override - public void writeSpace(char[] text, int offset, int length) throws XMLStreamException { - // See comments above... - writeRaw(text, offset, length); - } - - /* - /////////////////////////////////////////////////////////// - // Stax2, Pass-through methods - /////////////////////////////////////////////////////////// - */ - - @Override - public void writeRaw(String text) throws XMLStreamException { - writeRaw(text, 0, text.length()); - } - - @Override - public abstract void writeRaw(String text, int offset, int len) throws XMLStreamException; - - @Override - public abstract void writeRaw(char[] text, int offset, int length) throws XMLStreamException; -}