mirror of https://github.com/M66B/FairEmail.git
1700 lines
59 KiB
Java
1700 lines
59 KiB
Java
package com.bugsnag.android.repackaged.dslplatform.json;
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
import java.io.IOException;
|
|
import java.math.BigDecimal;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"}) // suppress pre-existing warnings
|
|
public abstract class NumberConverter {
|
|
|
|
public final static short[] SHORT_EMPTY_ARRAY = new short[0];
|
|
public final static int[] INT_EMPTY_ARRAY = new int[0];
|
|
public final static long[] LONG_EMPTY_ARRAY = new long[0];
|
|
public final static float[] FLOAT_EMPTY_ARRAY = new float[0];
|
|
public final static double[] DOUBLE_EMPTY_ARRAY = new double[0];
|
|
public final static Short SHORT_ZERO = 0;
|
|
public final static Integer INT_ZERO = 0;
|
|
public final static Long LONG_ZERO = 0L;
|
|
public final static Float FLOAT_ZERO = 0f;
|
|
public final static Double DOUBLE_ZERO = 0.0;
|
|
|
|
private final static int[] DIGITS = new int[1000];
|
|
private final static int[] DIFF = {111, 222, 444, 888, 1776};
|
|
private final static int[] ERROR = {50, 100, 200, 400, 800};
|
|
private final static int[] SCALE_10 = {10000, 1000, 100, 10, 1};
|
|
private final static double[] POW_10 = {
|
|
1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
|
|
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
|
|
1e20, 1e21, 1e22, 1e23, 1e24, 1e25, 1e26, 1e27, 1e28, 1e29,
|
|
1e30, 1e31, 1e32, 1e33, 1e34, 1e35, 1e36, 1e37, 1e38, 1e39,
|
|
1e40, 1e41, 1e42, 1e43, 1e44, 1e45, 1e46, 1e47, 1e48, 1e49,
|
|
1e50, 1e51, 1e52, 1e53, 1e54, 1e55, 1e56, 1e57, 1e58, 1e59,
|
|
1e60, 1e61, 1e62, 1e63, 1e64, 1e65
|
|
};
|
|
public static final JsonReader.ReadObject<Double> DOUBLE_READER = new JsonReader.ReadObject<Double>() {
|
|
@Nullable
|
|
@Override
|
|
public Double read(JsonReader reader) throws IOException {
|
|
return deserializeDouble(reader);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Double> NULLABLE_DOUBLE_READER = new JsonReader.ReadObject<Double>() {
|
|
@Nullable
|
|
@Override
|
|
public Double read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeDouble(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<Double> DOUBLE_WRITER = new JsonWriter.WriteObject<Double>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable Double value) {
|
|
serializeNullable(value, writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<double[]> DOUBLE_ARRAY_READER = new JsonReader.ReadObject<double[]>() {
|
|
@Nullable
|
|
@Override
|
|
public double[] read(JsonReader reader) throws IOException {
|
|
if (reader.wasNull()) return null;
|
|
if (reader.last() != '[') throw reader.newParseError("Expecting '[' for double array start");
|
|
reader.getNextToken();
|
|
return deserializeDoubleArray(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<double[]> DOUBLE_ARRAY_WRITER = new JsonWriter.WriteObject<double[]>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable double[] value) {
|
|
serialize(value, writer);
|
|
}
|
|
};
|
|
|
|
public static final JsonReader.ReadObject<Float> FLOAT_READER = new JsonReader.ReadObject<Float>() {
|
|
@Override
|
|
public Float read(JsonReader reader) throws IOException {
|
|
return deserializeFloat(reader);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Float> NULLABLE_FLOAT_READER = new JsonReader.ReadObject<Float>() {
|
|
@Nullable
|
|
@Override
|
|
public Float read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeFloat(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<Float> FLOAT_WRITER = new JsonWriter.WriteObject<Float>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable Float value) {
|
|
serializeNullable(value, writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<float[]> FLOAT_ARRAY_READER = new JsonReader.ReadObject<float[]>() {
|
|
@Nullable
|
|
@Override
|
|
public float[] read(JsonReader reader) throws IOException {
|
|
if (reader.wasNull()) return null;
|
|
if (reader.last() != '[') throw reader.newParseError("Expecting '[' for float array start");
|
|
reader.getNextToken();
|
|
return deserializeFloatArray(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<float[]> FLOAT_ARRAY_WRITER = new JsonWriter.WriteObject<float[]>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable float[] value) {
|
|
serialize(value, writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Integer> INT_READER = new JsonReader.ReadObject<Integer>() {
|
|
@Override
|
|
public Integer read(JsonReader reader) throws IOException {
|
|
return deserializeInt(reader);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Integer> NULLABLE_INT_READER = new JsonReader.ReadObject<Integer>() {
|
|
@Nullable
|
|
@Override
|
|
public Integer read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeInt(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<Integer> INT_WRITER = new JsonWriter.WriteObject<Integer>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable Integer value) {
|
|
serializeNullable(value, writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<int[]> INT_ARRAY_READER = new JsonReader.ReadObject<int[]>() {
|
|
@Nullable
|
|
@Override
|
|
public int[] read(JsonReader reader) throws IOException {
|
|
if (reader.wasNull()) return null;
|
|
if (reader.last() != '[') throw reader.newParseError("Expecting '[' for int array start");
|
|
reader.getNextToken();
|
|
return deserializeIntArray(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<int[]> INT_ARRAY_WRITER = new JsonWriter.WriteObject<int[]>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable int[] value) {
|
|
serialize(value, writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Short> SHORT_READER = new JsonReader.ReadObject<Short>() {
|
|
@Override
|
|
public Short read(JsonReader reader) throws IOException {
|
|
return deserializeShort(reader);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Short> NULLABLE_SHORT_READER = new JsonReader.ReadObject<Short>() {
|
|
@Nullable
|
|
@Override
|
|
public Short read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeShort(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<Short> SHORT_WRITER = new JsonWriter.WriteObject<Short>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable Short value) {
|
|
if (value == null) writer.writeNull();
|
|
else serialize(value.intValue(), writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<short[]> SHORT_ARRAY_READER = new JsonReader.ReadObject<short[]>() {
|
|
@Nullable
|
|
@Override
|
|
public short[] read(JsonReader reader) throws IOException {
|
|
if (reader.wasNull()) return null;
|
|
if (reader.last() != '[') throw reader.newParseError("Expecting '[' for short array start");
|
|
reader.getNextToken();
|
|
return deserializeShortArray(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<short[]> SHORT_ARRAY_WRITER = new JsonWriter.WriteObject<short[]>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable short[] value) {
|
|
serialize(value, writer);
|
|
}
|
|
};
|
|
|
|
public static final JsonReader.ReadObject<Long> LONG_READER = new JsonReader.ReadObject<Long>() {
|
|
@Override
|
|
public Long read(JsonReader reader) throws IOException {
|
|
return deserializeLong(reader);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<Long> NULLABLE_LONG_READER = new JsonReader.ReadObject<Long>() {
|
|
@Nullable
|
|
@Override
|
|
public Long read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeLong(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<Long> LONG_WRITER = new JsonWriter.WriteObject<Long>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable Long value) {
|
|
serializeNullable(value, writer);
|
|
}
|
|
};
|
|
public static final JsonReader.ReadObject<long[]> LONG_ARRAY_READER = new JsonReader.ReadObject<long[]>() {
|
|
@Nullable
|
|
@Override
|
|
public long[] read(JsonReader reader) throws IOException {
|
|
if (reader.wasNull()) return null;
|
|
if (reader.last() != '[') throw reader.newParseError("Expecting '[' for long array start");
|
|
reader.getNextToken();
|
|
return deserializeLongArray(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<long[]> LONG_ARRAY_WRITER = new JsonWriter.WriteObject<long[]>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable long[] value) {
|
|
serialize(value, writer);
|
|
}
|
|
};
|
|
|
|
public static final JsonReader.ReadObject<BigDecimal> DecimalReader = new JsonReader.ReadObject<BigDecimal>() {
|
|
@Nullable
|
|
@Override
|
|
public BigDecimal read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeDecimal(reader);
|
|
}
|
|
};
|
|
public static final JsonWriter.WriteObject<BigDecimal> DecimalWriter = new JsonWriter.WriteObject<BigDecimal>() {
|
|
@Override
|
|
public void write(JsonWriter writer, @Nullable BigDecimal value) {
|
|
serializeNullable(value, writer);
|
|
}
|
|
};
|
|
static final JsonReader.ReadObject<Number> NumberReader = new JsonReader.ReadObject<Number>() {
|
|
@Nullable
|
|
@Override
|
|
public Number read(JsonReader reader) throws IOException {
|
|
return reader.wasNull() ? null : deserializeNumber(reader);
|
|
}
|
|
};
|
|
|
|
static {
|
|
for (int i = 0; i < DIGITS.length; i++) {
|
|
DIGITS[i] = (i < 10 ? (2 << 24) : i < 100 ? (1 << 24) : 0)
|
|
+ (((i / 100) + '0') << 16)
|
|
+ ((((i / 10) % 10) + '0') << 8)
|
|
+ i % 10 + '0';
|
|
}
|
|
}
|
|
|
|
static void write4(final int value, final byte[] buf, final int pos) {
|
|
if (value > 9999) {
|
|
throw new IllegalArgumentException("Only 4 digits numbers are supported. Provided: " + value);
|
|
}
|
|
final int q = value / 1000;
|
|
final int v = DIGITS[value - q * 1000];
|
|
buf[pos] = (byte) (q + '0');
|
|
buf[pos + 1] = (byte) (v >> 16);
|
|
buf[pos + 2] = (byte) (v >> 8);
|
|
buf[pos + 3] = (byte) v;
|
|
}
|
|
|
|
static void write3(final int number, final byte[] buf, int pos) {
|
|
final int v = DIGITS[number];
|
|
buf[pos] = (byte) (v >> 16);
|
|
buf[pos + 1] = (byte) (v >> 8);
|
|
buf[pos + 2] = (byte) v;
|
|
}
|
|
|
|
static void write2(final int value, final byte[] buf, final int pos) {
|
|
final int v = DIGITS[value];
|
|
buf[pos] = (byte) (v >> 8);
|
|
buf[pos + 1] = (byte) v;
|
|
}
|
|
|
|
static int read2(final char[] buf, final int pos) {
|
|
final int v1 = buf[pos] - 48;
|
|
return (v1 << 3) + (v1 << 1) + buf[pos + 1] - 48;
|
|
}
|
|
|
|
static int read4(final char[] buf, final int pos) {
|
|
final int v2 = buf[pos + 1] - 48;
|
|
final int v3 = buf[pos + 2] - 48;
|
|
return (buf[pos] - 48) * 1000
|
|
+ (v2 << 6) + (v2 << 5) + (v2 << 2)
|
|
+ (v3 << 3) + (v3 << 1)
|
|
+ buf[pos + 3] - 48;
|
|
}
|
|
|
|
static void numberException(final JsonReader reader, final int start, final int end, String message) throws ParsingException {
|
|
final int len = end - start;
|
|
if (len > reader.maxNumberDigits) {
|
|
throw reader.newParseErrorWith("Too many digits detected in number", len, "", "Too many digits detected in number", end, "");
|
|
}
|
|
throw reader.newParseErrorWith("Error parsing number", len, "", message, null, ". Error parsing number");
|
|
}
|
|
|
|
static void numberException(final JsonReader reader, final int start, final int end, String message, Object messageArgument) throws ParsingException {
|
|
final int len = end - start;
|
|
if (len > reader.maxNumberDigits) {
|
|
throw reader.newParseErrorWith("Too many digits detected in number", len, "", "Too many digits detected in number", end, "");
|
|
}
|
|
throw reader.newParseErrorWith("Error parsing number", len, "", message, messageArgument, ". Error parsing number");
|
|
}
|
|
|
|
public static void serializeNullable(@Nullable final Double value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else {
|
|
serialize(value, sw);
|
|
}
|
|
}
|
|
|
|
private static BigDecimal parseNumberGeneric(final char[] buf, final int len, final JsonReader reader, final boolean withQuotes) throws ParsingException {
|
|
int end = len;
|
|
while (end > 0 && Character.isWhitespace(buf[end - 1])) {
|
|
end--;
|
|
}
|
|
if (end > reader.maxNumberDigits) {
|
|
throw reader.newParseErrorWith("Too many digits detected in number", len, "", "Too many digits detected in number", end, "");
|
|
}
|
|
final int offset = buf[0] == '-' ? 1 : 0;
|
|
if (buf[offset] == '0' && end > offset + 1 && buf[offset + 1] >= '0' && buf[offset + 1] <= '9') {
|
|
throw reader.newParseErrorAt("Leading zero is not allowed. Error parsing number", len + (withQuotes ? 2 : 0));
|
|
}
|
|
try {
|
|
return new BigDecimal(buf, 0, end);
|
|
} catch (NumberFormatException nfe) {
|
|
throw reader.newParseErrorAt("Error parsing number", len + (withQuotes ? 2 : 0), nfe);
|
|
}
|
|
}
|
|
|
|
public static void serialize(final double value, final JsonWriter sw) {
|
|
sw.writeDouble(value);
|
|
}
|
|
|
|
public static void serialize(@Nullable final double[] value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else if (value.length == 0) {
|
|
sw.writeAscii("[]");
|
|
} else {
|
|
sw.writeByte(JsonWriter.ARRAY_START);
|
|
serialize(value[0], sw);
|
|
for (int i = 1; i < value.length; i++) {
|
|
sw.writeByte(JsonWriter.COMMA);
|
|
serialize(value[i], sw);
|
|
}
|
|
sw.writeByte(JsonWriter.ARRAY_END);
|
|
}
|
|
}
|
|
|
|
private static class NumberInfo {
|
|
final char[] buffer;
|
|
final int length;
|
|
|
|
NumberInfo(final char[] buffer, final int length) {
|
|
this.buffer = buffer;
|
|
this.length = length;
|
|
}
|
|
}
|
|
|
|
private static NumberInfo readLongNumber(final JsonReader reader, final int start) throws IOException {
|
|
int len = reader.length() - start;
|
|
char[] result = reader.prepareBuffer(start, len);
|
|
while (reader.length() == reader.getCurrentIndex()) {
|
|
if (reader.isEndOfStream()) break;
|
|
reader.scanNumber(); // peek, do not read
|
|
int end = reader.getCurrentIndex();
|
|
int oldLen = len;
|
|
len += end;
|
|
if (len > reader.maxNumberDigits) {
|
|
throw reader.newParseErrorFormat("Too many digits detected in number", len, "Number of digits larger than %d. Unable to read number", reader.maxNumberDigits);
|
|
}
|
|
char[] tmp = result;
|
|
result = new char[len];
|
|
System.arraycopy(tmp, 0, result, 0, oldLen);
|
|
System.arraycopy(reader.prepareBuffer(0, end), 0, result, oldLen, end);
|
|
}
|
|
return new NumberInfo(result, len);
|
|
}
|
|
|
|
public static double deserializeDouble(final JsonReader reader) throws IOException {
|
|
if (reader.last() == '"') {
|
|
final int position = reader.getCurrentIndex();
|
|
final char[] buf = reader.readSimpleQuote();
|
|
return parseDoubleGeneric(buf, reader.getCurrentIndex() - position - 1, reader, true);
|
|
}
|
|
final int start = reader.scanNumber();
|
|
final int end = reader.getCurrentIndex();
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
if (ch == '-') {
|
|
return -parseDouble(buf, reader, start, end, 1);
|
|
}
|
|
return parseDouble(buf, reader, start, end, 0);
|
|
}
|
|
|
|
private static double parseDouble(final byte[] buf, final JsonReader reader, final int start, final int end, final int offset) throws IOException {
|
|
if (end - start - offset > reader.doubleLengthLimit) {
|
|
if (end == reader.length()) {
|
|
final NumberInfo tmp = readLongNumber(reader, start + offset);
|
|
return parseDoubleGeneric(tmp.buffer, tmp.length, reader, false);
|
|
}
|
|
return parseDoubleGeneric(reader.prepareBuffer(start + offset, end - start - offset), end - start - offset, reader, false);
|
|
}
|
|
long value = 0;
|
|
byte ch = ' ';
|
|
int i = start + offset;
|
|
final boolean leadingZero = buf[start + offset] == 48;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == '.' || ch == 'e' || ch == 'E') break;
|
|
final int ind = buf[i] - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + offset + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start + offset && reader.allWhitespace(i, end)) return value;
|
|
numberException(reader, start, end, "Unknown digit", (char)ch);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == start + offset) numberException(reader, start, end, "Digit not found");
|
|
else if (leadingZero && ch != '.' && i > start + offset + 1) numberException(reader, start, end, "Leading zero is not allowed");
|
|
else if (i == end) return value;
|
|
else if (ch == '.') {
|
|
i++;
|
|
if (i == end) numberException(reader, start, end, "Number ends with a dot");
|
|
final int maxLen;
|
|
final double preciseDividor;
|
|
final int expDiff;
|
|
final int decPos = i;
|
|
final int decOffset;
|
|
if (value == 0) {
|
|
maxLen = i + 15;
|
|
ch = buf[i];
|
|
if (ch == '0' && end > maxLen) {
|
|
return parseDoubleGeneric(reader.prepareBuffer(start + offset, end - start - offset), end - start - offset, reader, false);
|
|
} else if (ch < '8') {
|
|
preciseDividor = 1e14;
|
|
expDiff = -1;
|
|
decOffset = 1;
|
|
} else {
|
|
preciseDividor = 1e15;
|
|
expDiff = 0;
|
|
decOffset = 0;
|
|
}
|
|
} else {
|
|
maxLen = start + offset + 16;
|
|
if (buf[start + offset] < '8') {
|
|
preciseDividor = 1e14;
|
|
expDiff = i - maxLen + 14;
|
|
decOffset = 1;
|
|
} else {
|
|
preciseDividor = 1e15;
|
|
expDiff = i - maxLen + 15;
|
|
decOffset = 0;
|
|
}
|
|
}
|
|
final int numLimit = maxLen < end ? maxLen : end;
|
|
//TODO zeros
|
|
for (; i < numLimit; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) return value / POW_10[i - decPos - 1];
|
|
numberException(reader, start, end, "Unknown digit", (char)buf[i]);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == end) return value / POW_10[i - decPos - 1];
|
|
else if (ch == 'e' || ch == 'E') {
|
|
return doubleExponent(reader, value, i - decPos,0, buf, start, end, offset, i);
|
|
}
|
|
if (reader.doublePrecision == JsonReader.DoublePrecision.HIGH) {
|
|
return parseDoubleGeneric(reader.prepareBuffer(start + offset, end - start - offset), end - start - offset, reader, false);
|
|
}
|
|
int decimals = 0;
|
|
final int decLimit = start + offset + 18 < end ? start + offset + 18 : end;
|
|
final int remPos = i;
|
|
for(;i < decLimit; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) {
|
|
return approximateDouble(decimals, value / preciseDividor, i - remPos - decOffset);
|
|
}
|
|
numberException(reader, start, end, "Unknown digit", (char)buf[i]);
|
|
}
|
|
decimals = (decimals << 3) + (decimals << 1) + ind;
|
|
}
|
|
final double number = approximateDouble(decimals, value / preciseDividor, i - remPos - decOffset);
|
|
while (i < end && ch >= '0' && ch <= '9') {
|
|
ch = buf[i++];
|
|
}
|
|
if (ch == 'e' || ch == 'E') {
|
|
return doubleExponent(reader, 0, expDiff, number, buf, start, end, offset, i);
|
|
} else if (expDiff > 0) {
|
|
return number * POW_10[expDiff - 1];
|
|
} else if (expDiff < 0) {
|
|
return number / POW_10[-expDiff - 1];
|
|
} else {
|
|
return number;
|
|
}
|
|
} else if (ch == 'e' || ch == 'E') {
|
|
return doubleExponent(reader, value, 0, 0, buf, start, end, offset, i);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private static double approximateDouble(final int decimals, final double precise, final int digits) {
|
|
final long bits = Double.doubleToRawLongBits(precise);
|
|
final int exp = (int)(bits >> 52) - 1022;
|
|
final int missing = (decimals * SCALE_10[digits + 1] + ERROR[exp]) / DIFF[exp];
|
|
return Double.longBitsToDouble(bits + missing);
|
|
}
|
|
|
|
private static double doubleExponent(JsonReader reader, final long whole, final int decimals, double fraction, byte[] buf, int start, int end, int offset, int i) throws IOException {
|
|
if (reader.doublePrecision == JsonReader.DoublePrecision.EXACT) {
|
|
return parseDoubleGeneric(reader.prepareBuffer(start + offset, end - start - offset), end - start - offset, reader, false);
|
|
}
|
|
byte ch;
|
|
ch = buf[++i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end) - decimals;
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1) - decimals;
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0) - decimals;
|
|
}
|
|
if (fraction == 0) {
|
|
if (exp == 0 || whole == 0) return whole;
|
|
else if (exp > 0 && exp < POW_10.length) return whole * POW_10[exp - 1];
|
|
else if (exp < 0 && -exp < POW_10.length) return whole / POW_10[-exp - 1];
|
|
else if (reader.doublePrecision != JsonReader.DoublePrecision.HIGH) {
|
|
if (exp > 0 && exp < 300) return whole * Math.pow(10, exp);
|
|
else if (exp > -300 && exp < 0) return whole / Math.pow(10, exp);
|
|
}
|
|
} else {
|
|
if (exp == 0) return whole + fraction;
|
|
else if (exp > 0 && exp < POW_10.length) return fraction * POW_10[exp - 1] + whole * POW_10[exp - 1];
|
|
else if (exp < 0 && -exp < POW_10.length) return fraction / POW_10[-exp - 1] + whole / POW_10[-exp - 1];
|
|
else if (reader.doublePrecision != JsonReader.DoublePrecision.HIGH) {
|
|
if (exp > 0 && exp < 300) return whole * Math.pow(10, exp);
|
|
else if (exp > -300 && exp < 0) return whole / Math.pow(10, exp);
|
|
}
|
|
}
|
|
return parseDoubleGeneric(reader.prepareBuffer(start + offset, end - start - offset), end - start - offset, reader, false);
|
|
}
|
|
|
|
private static double parseDoubleGeneric(final char[] buf, final int len, final JsonReader reader, final boolean withQuotes) throws IOException {
|
|
int end = len;
|
|
while (end > 0 && Character.isWhitespace(buf[end - 1])) {
|
|
end--;
|
|
}
|
|
if (end > reader.maxNumberDigits) {
|
|
throw reader.newParseErrorWith("Too many digits detected in number", len, "", "Too many digits detected in number", end, "");
|
|
}
|
|
final int offset = buf[0] == '-' ? 1 : 0;
|
|
if (buf[offset] == '0' && end > offset + 1 && buf[offset + 1] >= '0' && buf[offset + 1] <= '9') {
|
|
throw reader.newParseErrorAt("Leading zero is not allowed. Error parsing number", len + (withQuotes ? 2 : 0));
|
|
}
|
|
try {
|
|
return Double.parseDouble(new String(buf, 0, end));
|
|
} catch (NumberFormatException nfe) {
|
|
throw reader.newParseErrorAt("Error parsing number", len + (withQuotes ? 2 : 0), nfe);
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Double> deserializeDoubleCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeCollection(DOUBLE_READER);
|
|
}
|
|
|
|
public static void deserializeDoubleCollection(final JsonReader reader, final Collection<Double> res) throws IOException {
|
|
reader.deserializeCollection(DOUBLE_READER, res);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Double> deserializeDoubleNullableCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeNullableCollection(DOUBLE_READER);
|
|
}
|
|
|
|
public static void deserializeDoubleNullableCollection(final JsonReader reader, final Collection<Double> res) throws IOException {
|
|
reader.deserializeNullableCollection(DOUBLE_READER, res);
|
|
}
|
|
|
|
public static void serializeNullable(@Nullable final Float value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else {
|
|
serialize(value, sw);
|
|
}
|
|
}
|
|
|
|
public static void serialize(final float value, final JsonWriter sw) {
|
|
if (value == Float.POSITIVE_INFINITY) {
|
|
sw.writeAscii("\"Infinity\"");
|
|
} else if (value == Float.NEGATIVE_INFINITY) {
|
|
sw.writeAscii("\"-Infinity\"");
|
|
} else if (value != value) {
|
|
sw.writeAscii("\"NaN\"");
|
|
} else {
|
|
sw.writeAscii(Float.toString(value));//TODO: better implementation required
|
|
}
|
|
}
|
|
|
|
public static void serialize(@Nullable final float[] value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else if (value.length == 0) {
|
|
sw.writeAscii("[]");
|
|
} else {
|
|
sw.writeByte(JsonWriter.ARRAY_START);
|
|
serialize(value[0], sw);
|
|
for (int i = 1; i < value.length; i++) {
|
|
sw.writeByte(JsonWriter.COMMA);
|
|
serialize(value[i], sw);
|
|
}
|
|
sw.writeByte(JsonWriter.ARRAY_END);
|
|
}
|
|
}
|
|
|
|
public static float deserializeFloat(final JsonReader reader) throws IOException {
|
|
if (reader.last() == '"') {
|
|
final int position = reader.getCurrentIndex();
|
|
final char[] buf = reader.readSimpleQuote();
|
|
return parseFloatGeneric(buf, reader.getCurrentIndex() - position - 1, reader, true);
|
|
}
|
|
final int start = reader.scanNumber();
|
|
final int end = reader.getCurrentIndex();
|
|
if (end == reader.length()) {
|
|
final NumberInfo tmp = readLongNumber(reader, start);
|
|
return parseFloatGeneric(tmp.buffer, tmp.length, reader, false);
|
|
}
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
if (ch == '-') {
|
|
return -parseFloat(buf, reader, start, end, 1);
|
|
}
|
|
return parseFloat(buf, reader, start, end, 0);
|
|
}
|
|
|
|
private static float parseFloat(byte[] buf, final JsonReader reader, final int start, int end, int offset) throws IOException {
|
|
long value = 0;
|
|
byte ch = ' ';
|
|
int i = start + offset;
|
|
final int digitStart = i;
|
|
final boolean leadingZero = buf[start + offset] == 48;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == '.' || ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + offset + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start + offset && reader.allWhitespace(i, end)) return value;
|
|
numberException(reader, start, end, "Unknown digit", (char)ch);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == digitStart) numberException(reader, start, end, "Digit not found");
|
|
else if (leadingZero && ch != '.' && i > start + offset + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
} else if (i > 18 + digitStart) {
|
|
return parseFloatGeneric(reader.prepareBuffer(start + offset, end - start - offset), end - start - offset, reader, false);
|
|
} else if (i == end) {
|
|
return value;
|
|
} else if (ch == '.') {
|
|
i++;
|
|
if (i == end) numberException(reader, start, end, "Number ends with a dot");
|
|
final int decPos;
|
|
final int maxLen;
|
|
final int pointOffset;
|
|
if (value == 0) {
|
|
pointOffset = 0;
|
|
decPos = i + 1;
|
|
while (i < end && buf[i] == '0') {
|
|
i++;
|
|
}
|
|
maxLen = i + 17;
|
|
} else {
|
|
pointOffset = 1;
|
|
maxLen = digitStart + 17;
|
|
decPos = i;
|
|
}
|
|
final int numLimit = maxLen < end ? maxLen : end;
|
|
boolean foundE = false;
|
|
for (; i < numLimit; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') {
|
|
foundE = true;
|
|
++i;
|
|
break;
|
|
}
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) return (float) (value / POW_10[i - decPos - pointOffset]);
|
|
numberException(reader, start, end, "Unknown digit", (char) ch);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
final int endPos;
|
|
if (i == numLimit && !foundE) {
|
|
endPos = i + 1 - pointOffset;
|
|
while (i < end && ch >= '0' && ch <= '9') {
|
|
ch = buf[i++];
|
|
}
|
|
} else endPos = i - pointOffset;
|
|
while (i == end && reader.length() == end) {
|
|
i = reader.scanNumber();
|
|
end = reader.getCurrentIndex();
|
|
buf = reader.buffer;
|
|
while (i < end && ch >= '0' && ch <= '9') {
|
|
ch = buf[i++];
|
|
}
|
|
}
|
|
if (ch == 'e' || ch == 'E') {
|
|
return floatExponent(reader, value, endPos - decPos, buf, end, i);
|
|
}
|
|
final int expDiff = endPos - decPos;
|
|
if (expDiff > 0) {
|
|
return (float)(value / POW_10[expDiff - 1]);
|
|
} else if (expDiff < 0) {
|
|
return (float)(value * POW_10[-expDiff - 1]);
|
|
} else {
|
|
return value;
|
|
}
|
|
} else if (ch == 'e' || ch == 'E') {
|
|
return floatExponent(reader, value, 0, buf, end, i + 1);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private static float floatExponent(JsonReader reader, final long whole, final int decimals, byte[] buf, int end, int i) throws IOException {
|
|
byte ch;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end) - decimals;
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1) - decimals;
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0) - decimals;
|
|
}
|
|
if (exp == 0 || whole == 0) return whole;
|
|
else if (exp > 0 && exp < POW_10.length) return (float) (whole * POW_10[exp - 1]);
|
|
else if (exp < 0 && -exp < POW_10.length) return (float) (whole / POW_10[-exp - 1]);
|
|
else return exp > 0 ? Float.POSITIVE_INFINITY : 0f;
|
|
}
|
|
|
|
private static float parseFloatGeneric(final char[] buf, final int len, final JsonReader reader, final boolean withQuotes) throws ParsingException {
|
|
int end = len;
|
|
while (end > 0 && Character.isWhitespace(buf[end - 1])) {
|
|
end--;
|
|
}
|
|
if (end > reader.maxNumberDigits) {
|
|
throw reader.newParseErrorWith("Too many digits detected in number", len, "", "Too many digits detected in number", end, "");
|
|
}
|
|
final int offset = buf[0] == '-' ? 1 : 0;
|
|
if (buf[offset] == '0' && end > offset + 1 && buf[offset + 1] >= '0' && buf[offset + 1] <= '9') {
|
|
throw reader.newParseErrorAt("Leading zero is not allowed. Error parsing number", len + (withQuotes ? 2 : 0));
|
|
}
|
|
try {
|
|
return Float.parseFloat(new String(buf, 0, end));
|
|
} catch (NumberFormatException nfe) {
|
|
throw reader.newParseErrorAt("Error parsing number", len + (withQuotes ? 2 : 0), nfe);
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Float> deserializeFloatCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeCollection(FLOAT_READER);
|
|
}
|
|
|
|
public static void deserializeFloatCollection(final JsonReader reader, Collection<Float> res) throws IOException {
|
|
reader.deserializeCollection(FLOAT_READER, res);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Float> deserializeFloatNullableCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeNullableCollection(FLOAT_READER);
|
|
}
|
|
|
|
public static void deserializeFloatNullableCollection(final JsonReader reader, final Collection<Float> res) throws IOException {
|
|
reader.deserializeNullableCollection(FLOAT_READER, res);
|
|
}
|
|
|
|
public static void serializeNullable(@Nullable final Integer value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else {
|
|
serialize(value, sw);
|
|
}
|
|
}
|
|
|
|
private static final byte MINUS = '-';
|
|
private static final byte[] MIN_INT = "-2147483648".getBytes();
|
|
|
|
public static void serialize(final int value, final JsonWriter sw) {
|
|
final byte[] buf = sw.ensureCapacity(11);
|
|
final int position = sw.size();
|
|
int current = serialize(buf, position, value);
|
|
sw.advance(current - position);
|
|
}
|
|
|
|
private static int serialize(final byte[] buf, int pos, final int value) {
|
|
int i;
|
|
if (value < 0) {
|
|
if (value == Integer.MIN_VALUE) {
|
|
for (int x = 0; x < MIN_INT.length; x++) {
|
|
buf[pos + x] = MIN_INT[x];
|
|
}
|
|
return pos + MIN_INT.length;
|
|
}
|
|
i = -value;
|
|
buf[pos++] = MINUS;
|
|
} else {
|
|
i = value;
|
|
}
|
|
final int q1 = i / 1000;
|
|
if (q1 == 0) {
|
|
pos += writeFirstBuf(buf, DIGITS[i], pos);
|
|
return pos;
|
|
}
|
|
final int r1 = i - q1 * 1000;
|
|
final int q2 = q1 / 1000;
|
|
if (q2 == 0) {
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[q1];
|
|
int off = writeFirstBuf(buf, v2, pos);
|
|
writeBuf(buf, v1, pos + off);
|
|
return pos + 3 + off;
|
|
}
|
|
final int r2 = q1 - q2 * 1000;
|
|
final int q3 = q2 / 1000;
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[r2];
|
|
if (q3 == 0) {
|
|
pos += writeFirstBuf(buf, DIGITS[q2], pos);
|
|
} else {
|
|
final int r3 = q2 - q3 * 1000;
|
|
buf[pos++] = (byte) (q3 + '0');
|
|
writeBuf(buf, DIGITS[r3], pos);
|
|
pos += 3;
|
|
}
|
|
writeBuf(buf, v2, pos);
|
|
writeBuf(buf, v1, pos + 3);
|
|
return pos + 6;
|
|
}
|
|
|
|
public static void serialize(@Nullable final int[] values, final JsonWriter sw) {
|
|
if (values == null) {
|
|
sw.writeNull();
|
|
} else if (values.length == 0) {
|
|
sw.writeAscii("[]");
|
|
} else {
|
|
final byte[] buf = sw.ensureCapacity(values.length * 11 + 2);
|
|
int position = sw.size();
|
|
buf[position++] = '[';
|
|
position = serialize(buf, position, values[0]);
|
|
for (int i = 1; i < values.length; i++) {
|
|
buf[position++] = ',';
|
|
position = serialize(buf, position, values[i]);
|
|
}
|
|
buf[position++] = ']';
|
|
sw.advance(position - sw.size());
|
|
}
|
|
}
|
|
|
|
public static void serialize(@Nullable final short[] value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else if (value.length == 0) {
|
|
sw.writeAscii("[]");
|
|
} else {
|
|
sw.writeByte(JsonWriter.ARRAY_START);
|
|
serialize(value[0], sw);
|
|
for (int i = 1; i < value.length; i++) {
|
|
sw.writeByte(JsonWriter.COMMA);
|
|
serialize(value[i], sw);
|
|
}
|
|
sw.writeByte(JsonWriter.ARRAY_END);
|
|
}
|
|
}
|
|
|
|
public static short deserializeShort(final JsonReader reader) throws IOException {
|
|
if (reader.last() == '"') {
|
|
final int position = reader.getCurrentIndex();
|
|
final char[] buf = reader.readSimpleQuote();
|
|
try {
|
|
return parseNumberGeneric(buf, reader.getCurrentIndex() - position - 1, reader, true).shortValueExact();
|
|
} catch (ArithmeticException ignore) {
|
|
throw reader.newParseErrorAt("Short overflow detected", reader.getCurrentIndex() - position);
|
|
}
|
|
}
|
|
final int start = reader.scanNumber();
|
|
final int end = reader.getCurrentIndex();
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
final int value = ch == '-'
|
|
? parseNegativeInt(buf, reader, start, end)
|
|
: parsePositiveInt(buf, reader, start, end, 0);
|
|
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
|
|
throw reader.newParseErrorAt("Short overflow detected", reader.getCurrentIndex());
|
|
}
|
|
return (short)value;
|
|
}
|
|
|
|
public static int deserializeInt(final JsonReader reader) throws IOException {
|
|
if (reader.last() == '"') {
|
|
final int position = reader.getCurrentIndex();
|
|
final char[] buf = reader.readSimpleQuote();
|
|
try {
|
|
return parseNumberGeneric(buf, reader.getCurrentIndex() - position - 1, reader, true).intValueExact();
|
|
} catch (ArithmeticException ignore) {
|
|
throw reader.newParseErrorAt("Integer overflow detected", reader.getCurrentIndex() - position);
|
|
}
|
|
}
|
|
final int start = reader.scanNumber();
|
|
final int end = reader.getCurrentIndex();
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
if (ch == '-') {
|
|
if (end > start + 2 && buf[start + 1] == '0' && buf[start + 2] >= '0' && buf[start + 2] <= '9') {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
return parseNegativeInt(buf, reader, start, end);
|
|
} else {
|
|
if (ch == '0' && end > start + 1 && buf[start + 1] >= '0' && buf[start + 1] <= '9') {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
return parsePositiveInt(buf, reader, start, end, 0);
|
|
}
|
|
}
|
|
|
|
private static int parsePositiveInt(final byte[] buf, final JsonReader reader, final int start, final int end, final int offset) throws IOException {
|
|
int value = 0;
|
|
int i = start + offset;
|
|
if (i == end) numberException(reader, start, end, "Digit not found");
|
|
for (; i < end; i++) {
|
|
final int ind = buf[i] - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (i > start + offset && reader.allWhitespace(i, end)) return value;
|
|
else if (i == end - 1 && buf[i] == '.') numberException(reader, start, end, "Number ends with a dot");
|
|
final BigDecimal v = parseNumberGeneric(reader.prepareBuffer(start, end - start), end - start, reader, false);
|
|
if (v.scale() > 0) numberException(reader, start, end, "Expecting int but found decimal value", v);
|
|
return v.intValue();
|
|
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
if (value < 0) {
|
|
numberException(reader, start, end, "Integer overflow detected");
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private static int parseNegativeInt(final byte[] buf, final JsonReader reader, final int start, final int end) throws IOException {
|
|
int value = 0;
|
|
int i = start + 1;
|
|
if (i == end) numberException(reader, start, end, "Digit not found");
|
|
for (; i < end; i++) {
|
|
final int ind = buf[i] - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (i > start + 1 && reader.allWhitespace(i, end)) return value;
|
|
else if (i == end - 1 && buf[i] == '.') numberException(reader, start, end, "Number ends with a dot");
|
|
final BigDecimal v = parseNumberGeneric(reader.prepareBuffer(start, end - start), end - start, reader, false);
|
|
if (v.scale() > 0) numberException(reader, start, end, "Expecting int but found decimal value", v);
|
|
return v.intValue();
|
|
}
|
|
value = (value << 3) + (value << 1) - ind;
|
|
if (value > 0) {
|
|
numberException(reader, start, end, "Integer overflow detected");
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Integer> deserializeIntCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeCollection(INT_READER);
|
|
}
|
|
|
|
public static int[] deserializeIntArray(final JsonReader reader) throws IOException {
|
|
if (reader.last() == ']') {
|
|
return INT_EMPTY_ARRAY;
|
|
}
|
|
int[] buffer = new int[4];
|
|
buffer[0] = deserializeInt(reader);
|
|
int i = 1;
|
|
while (reader.getNextToken() == ',') {
|
|
reader.getNextToken();
|
|
if (i == buffer.length) {
|
|
buffer = Arrays.copyOf(buffer, buffer.length << 1);
|
|
}
|
|
buffer[i++] = deserializeInt(reader);
|
|
}
|
|
reader.checkArrayEnd();
|
|
return Arrays.copyOf(buffer, i);
|
|
}
|
|
|
|
public static short[] deserializeShortArray(final JsonReader reader) throws IOException {
|
|
if (reader.last() == ']') {
|
|
return SHORT_EMPTY_ARRAY;
|
|
}
|
|
short[] buffer = new short[4];
|
|
buffer[0] = (short)deserializeInt(reader);
|
|
int i = 1;
|
|
while (reader.getNextToken() == ',') {
|
|
reader.getNextToken();
|
|
if (i == buffer.length) {
|
|
buffer = Arrays.copyOf(buffer, buffer.length << 1);
|
|
}
|
|
buffer[i++] = (short)deserializeInt(reader);
|
|
}
|
|
reader.checkArrayEnd();
|
|
return Arrays.copyOf(buffer, i);
|
|
}
|
|
|
|
public static long[] deserializeLongArray(final JsonReader reader) throws IOException {
|
|
if (reader.last() == ']') {
|
|
return LONG_EMPTY_ARRAY;
|
|
}
|
|
long[] buffer = new long[4];
|
|
buffer[0] = deserializeLong(reader);
|
|
int i = 1;
|
|
while (reader.getNextToken() == ',') {
|
|
reader.getNextToken();
|
|
if (i == buffer.length) {
|
|
buffer = Arrays.copyOf(buffer, buffer.length << 1);
|
|
}
|
|
buffer[i++] = deserializeLong(reader);
|
|
}
|
|
reader.checkArrayEnd();
|
|
return Arrays.copyOf(buffer, i);
|
|
}
|
|
|
|
public static float[] deserializeFloatArray(final JsonReader reader) throws IOException {
|
|
if (reader.last() == ']') {
|
|
return FLOAT_EMPTY_ARRAY;
|
|
}
|
|
float[] buffer = new float[4];
|
|
buffer[0] = deserializeFloat(reader);
|
|
int i = 1;
|
|
while (reader.getNextToken() == ',') {
|
|
reader.getNextToken();
|
|
if (i == buffer.length) {
|
|
buffer = Arrays.copyOf(buffer, buffer.length << 1);
|
|
}
|
|
buffer[i++] = deserializeFloat(reader);
|
|
}
|
|
reader.checkArrayEnd();
|
|
return Arrays.copyOf(buffer, i);
|
|
}
|
|
|
|
public static double[] deserializeDoubleArray(final JsonReader reader) throws IOException {
|
|
if (reader.last() == ']') {
|
|
return DOUBLE_EMPTY_ARRAY;
|
|
}
|
|
double[] buffer = new double[4];
|
|
buffer[0] = deserializeDouble(reader);
|
|
int i = 1;
|
|
while (reader.getNextToken() == ',') {
|
|
reader.getNextToken();
|
|
if (i == buffer.length) {
|
|
buffer = Arrays.copyOf(buffer, buffer.length << 1);
|
|
}
|
|
buffer[i++] = deserializeDouble(reader);
|
|
}
|
|
reader.checkArrayEnd();
|
|
return Arrays.copyOf(buffer, i);
|
|
}
|
|
|
|
public static void deserializeShortCollection(final JsonReader reader, final Collection<Short> res) throws IOException {
|
|
reader.deserializeCollection(SHORT_READER, res);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Short> deserializeShortNullableCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeNullableCollection(SHORT_READER);
|
|
}
|
|
|
|
public static void deserializeShortNullableCollection(final JsonReader reader, final Collection<Short> res) throws IOException {
|
|
reader.deserializeNullableCollection(SHORT_READER, res);
|
|
}
|
|
|
|
public static void deserializeIntCollection(final JsonReader reader, final Collection<Integer> res) throws IOException {
|
|
reader.deserializeCollection(INT_READER, res);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Integer> deserializeIntNullableCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeNullableCollection(INT_READER);
|
|
}
|
|
|
|
public static void deserializeIntNullableCollection(final JsonReader reader, final Collection<Integer> res) throws IOException {
|
|
reader.deserializeNullableCollection(INT_READER, res);
|
|
}
|
|
|
|
public static void serializeNullable(@Nullable final Long value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else {
|
|
serialize(value, sw);
|
|
}
|
|
}
|
|
|
|
private static int writeFirstBuf(final byte[] buf, final int v, int pos) {
|
|
final int start = v >> 24;
|
|
if (start == 0) {
|
|
buf[pos++] = (byte) (v >> 16);
|
|
buf[pos++] = (byte) (v >> 8);
|
|
} else if (start == 1) {
|
|
buf[pos++] = (byte) (v >> 8);
|
|
}
|
|
buf[pos] = (byte) v;
|
|
return 3 - start;
|
|
}
|
|
|
|
private static void writeBuf(final byte[] buf, final int v, int pos) {
|
|
buf[pos] = (byte) (v >> 16);
|
|
buf[pos + 1] = (byte) (v >> 8);
|
|
buf[pos + 2] = (byte) v;
|
|
}
|
|
|
|
private static final byte[] MIN_LONG = "-9223372036854775808".getBytes();
|
|
|
|
public static void serialize(final long value, final JsonWriter sw) {
|
|
final byte[] buf = sw.ensureCapacity(21);
|
|
final int position = sw.size();
|
|
int current = serialize(buf, position, value);
|
|
sw.advance(current - position);
|
|
}
|
|
|
|
private static int serialize(final byte[] buf, int pos, final long value) {
|
|
long i;
|
|
if (value < 0) {
|
|
if (value == Long.MIN_VALUE) {
|
|
for (int x = 0; x < MIN_LONG.length; x++) {
|
|
buf[pos + x] = MIN_LONG[x];
|
|
}
|
|
return pos + MIN_LONG.length;
|
|
}
|
|
i = -value;
|
|
buf[pos++] = MINUS;
|
|
} else {
|
|
i = value;
|
|
}
|
|
final long q1 = i / 1000;
|
|
if (q1 == 0) {
|
|
pos += writeFirstBuf(buf, DIGITS[(int) i], pos);
|
|
return pos;
|
|
}
|
|
final int r1 = (int) (i - q1 * 1000);
|
|
final long q2 = q1 / 1000;
|
|
if (q2 == 0) {
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[(int) q1];
|
|
int off = writeFirstBuf(buf, v2, pos);
|
|
writeBuf(buf, v1, pos + off);
|
|
return pos + 3 + off;
|
|
}
|
|
final int r2 = (int) (q1 - q2 * 1000);
|
|
final long q3 = q2 / 1000;
|
|
if (q3 == 0) {
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[r2];
|
|
final int v3 = DIGITS[(int) q2];
|
|
pos += writeFirstBuf(buf, v3, pos);
|
|
writeBuf(buf, v2, pos);
|
|
writeBuf(buf, v1, pos + 3);
|
|
return pos + 6;
|
|
}
|
|
final int r3 = (int) (q2 - q3 * 1000);
|
|
final int q4 = (int) (q3 / 1000);
|
|
if (q4 == 0) {
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[r2];
|
|
final int v3 = DIGITS[r3];
|
|
final int v4 = DIGITS[(int) q3];
|
|
pos += writeFirstBuf(buf, v4, pos);
|
|
writeBuf(buf, v3, pos);
|
|
writeBuf(buf, v2, pos + 3);
|
|
writeBuf(buf, v1, pos + 6);
|
|
return pos + 9;
|
|
}
|
|
final int r4 = (int) (q3 - q4 * 1000);
|
|
final int q5 = q4 / 1000;
|
|
if (q5 == 0) {
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[r2];
|
|
final int v3 = DIGITS[r3];
|
|
final int v4 = DIGITS[r4];
|
|
final int v5 = DIGITS[q4];
|
|
pos += writeFirstBuf(buf, v5, pos);
|
|
writeBuf(buf, v4, pos);
|
|
writeBuf(buf, v3, pos + 3);
|
|
writeBuf(buf, v2, pos + 6);
|
|
writeBuf(buf, v1, pos + 9);
|
|
return pos + 12;
|
|
}
|
|
final int r5 = q4 - q5 * 1000;
|
|
final int q6 = q5 / 1000;
|
|
final int v1 = DIGITS[r1];
|
|
final int v2 = DIGITS[r2];
|
|
final int v3 = DIGITS[r3];
|
|
final int v4 = DIGITS[r4];
|
|
final int v5 = DIGITS[r5];
|
|
if (q6 == 0) {
|
|
pos += writeFirstBuf(buf, DIGITS[q5], pos);
|
|
} else {
|
|
final int r6 = q5 - q6 * 1000;
|
|
buf[pos++] = (byte) (q6 + '0');
|
|
writeBuf(buf, DIGITS[r6], pos);
|
|
pos += 3;
|
|
}
|
|
writeBuf(buf, v5, pos);
|
|
writeBuf(buf, v4, pos + 3);
|
|
writeBuf(buf, v3, pos + 6);
|
|
writeBuf(buf, v2, pos + 9);
|
|
writeBuf(buf, v1, pos + 12);
|
|
return pos + 15;
|
|
}
|
|
|
|
public static void serialize(@Nullable final long[] values, final JsonWriter sw) {
|
|
if (values == null) {
|
|
sw.writeNull();
|
|
} else if (values.length == 0) {
|
|
sw.writeAscii("[]");
|
|
} else {
|
|
final byte[] buf = sw.ensureCapacity(values.length * 21 + 2);
|
|
int position = sw.size();
|
|
buf[position++] = '[';
|
|
position = serialize(buf, position, values[0]);
|
|
for (int i = 1; i < values.length; i++) {
|
|
buf[position++] = ',';
|
|
position = serialize(buf, position, values[i]);
|
|
}
|
|
buf[position++] = ']';
|
|
sw.advance(position - sw.size());
|
|
}
|
|
}
|
|
|
|
public static long deserializeLong(final JsonReader reader) throws IOException {
|
|
if (reader.last() == '"') {
|
|
final int position = reader.getCurrentIndex();
|
|
final char[] buf = reader.readSimpleQuote();
|
|
try {
|
|
return parseNumberGeneric(buf, reader.getCurrentIndex() - position - 1, reader, true).longValueExact();
|
|
} catch (ArithmeticException ignore) {
|
|
throw reader.newParseErrorAt("Long overflow detected", reader.getCurrentIndex() - position);
|
|
}
|
|
}
|
|
final int start = reader.scanNumber();
|
|
final int end = reader.getCurrentIndex();
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
int i = start;
|
|
long value = 0;
|
|
if (ch == '-') {
|
|
i = start + 1;
|
|
if (i == end) numberException(reader, start, end, "Digit not found");
|
|
final boolean leadingZero = buf[i] == 48;
|
|
for (; i < end; i++) {
|
|
final int ind = buf[i] - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + 2) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start + 1 && reader.allWhitespace(i, end)) return value;
|
|
return parseLongGeneric(reader, start, end);
|
|
}
|
|
value = (value << 3) + (value << 1) - ind;
|
|
if (value > 0) {
|
|
numberException(reader, start, end, "Long overflow detected");
|
|
}
|
|
}
|
|
if (leadingZero && i > start + 2) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
return value;
|
|
}
|
|
if (i == end) numberException(reader, start, end, "Digit not found");
|
|
final boolean leadingZero = buf[i] == 48;
|
|
for (; i < end; i++) {
|
|
final int ind = buf[i] - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (ch == '+' && i > start + 1 && reader.allWhitespace(i, end)) return value;
|
|
else if (ch != '+' && i > start && reader.allWhitespace(i, end)) return value;
|
|
return parseLongGeneric(reader, start, end);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
if (value < 0) {
|
|
numberException(reader, start, end, "Long overflow detected");
|
|
}
|
|
}
|
|
if (leadingZero && i > start + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private static long parseLongGeneric(final JsonReader reader, final int start, final int end) throws IOException {
|
|
final int len = end - start;
|
|
final char[] buf = reader.prepareBuffer(start, len);
|
|
if (len > 0 && buf[len - 1] == '.') numberException(reader, start, end, "Number ends with a dot");
|
|
final BigDecimal v = parseNumberGeneric(buf, len, reader, false);
|
|
if (v.scale() > 0) numberException(reader, start, end, "Expecting long, but found decimal value ", v);
|
|
return v.longValue();
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Long> deserializeLongCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeCollection(LONG_READER);
|
|
}
|
|
|
|
public static void deserializeLongCollection(final JsonReader reader, final Collection<Long> res) throws IOException {
|
|
reader.deserializeCollection(LONG_READER, res);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<Long> deserializeLongNullableCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeNullableCollection(LONG_READER);
|
|
}
|
|
|
|
public static void deserializeLongNullableCollection(final JsonReader reader, final Collection<Long> res) throws IOException {
|
|
reader.deserializeNullableCollection(LONG_READER, res);
|
|
}
|
|
|
|
public static void serializeNullable(@Nullable final BigDecimal value, final JsonWriter sw) {
|
|
if (value == null) {
|
|
sw.writeNull();
|
|
} else {
|
|
sw.writeAscii(value.toString());
|
|
}
|
|
}
|
|
|
|
public static void serialize(final BigDecimal value, final JsonWriter sw) {
|
|
sw.writeAscii(value.toString());
|
|
}
|
|
|
|
public static BigDecimal deserializeDecimal(final JsonReader reader) throws IOException {
|
|
if (reader.last() == '"') {
|
|
final int len = reader.parseString();
|
|
return parseNumberGeneric(reader.chars, len, reader, true);
|
|
}
|
|
final int start = reader.scanNumber();
|
|
int end = reader.getCurrentIndex();
|
|
if (end == reader.length()) {
|
|
NumberInfo info = readLongNumber(reader, start);
|
|
return parseNumberGeneric(info.buffer, info.length, reader, false);
|
|
}
|
|
int len = end - start;
|
|
if (len > 18) {
|
|
return parseNumberGeneric(reader.prepareBuffer(start, len), len, reader, false);
|
|
}
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
if (ch == '-') {
|
|
return parseNegativeDecimal(buf, reader, start, end);
|
|
}
|
|
return parsePositiveDecimal(buf, reader, start, end);
|
|
}
|
|
|
|
private static BigDecimal parsePositiveDecimal(final byte[] buf, final JsonReader reader, final int start, final int end) throws IOException {
|
|
long value = 0;
|
|
byte ch = ' ';
|
|
int i = start;
|
|
final boolean leadingZero = buf[start] == 48;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == '.' || ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start && reader.allWhitespace(i, end)) return BigDecimal.valueOf(value);
|
|
numberException(reader, start, end, "Unknown digit", (char)ch);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == start) numberException(reader, start, end, "Digit not found");
|
|
else if (leadingZero && ch != '.' && i > start + 1) numberException(reader, start, end, "Leading zero is not allowed");
|
|
else if (i == end) return BigDecimal.valueOf(value);
|
|
else if (ch == '.') {
|
|
i++;
|
|
if (i == end) numberException(reader, start, end, "Number ends with a dot");
|
|
int dp = i;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) return BigDecimal.valueOf(value, i - dp);
|
|
numberException(reader, start, end, "Unknown digit", (char)ch);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == end) return BigDecimal.valueOf(value, end - dp);
|
|
else if (ch == 'e' || ch == 'E') {
|
|
final int ep = i;
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return BigDecimal.valueOf(value, ep - dp - exp);
|
|
}
|
|
return BigDecimal.valueOf(value, end - dp);
|
|
} else if (ch == 'e' || ch == 'E') {
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return BigDecimal.valueOf(value, -exp);
|
|
}
|
|
return BigDecimal.valueOf(value);
|
|
}
|
|
|
|
private static BigDecimal parseNegativeDecimal(final byte[] buf, final JsonReader reader, final int start, final int end) throws IOException {
|
|
long value = 0;
|
|
byte ch = ' ';
|
|
int i = start + 1;
|
|
final boolean leadingZero = buf[start + 1] == 48;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == '.' || ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + 2) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start + 1 && reader.allWhitespace(i, end)) return BigDecimal.valueOf(value);
|
|
numberException(reader, start, end, "Unknown digit", (char)ch);
|
|
}
|
|
value = (value << 3) + (value << 1) - ind;
|
|
}
|
|
if (i == start + 1) numberException(reader, start, end, "Digit not found");
|
|
else if (leadingZero && ch != '.' && i > start + 2) numberException(reader, start, end, "Leading zero is not allowed");
|
|
else if (i == end) return BigDecimal.valueOf(value);
|
|
else if (ch == '.') {
|
|
i++;
|
|
if (i == end) numberException(reader, start, end, "Number ends with a dot");
|
|
int dp = i;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) return BigDecimal.valueOf(value, i - dp);
|
|
numberException(reader, start, end, "Unknown digit", (char)ch);
|
|
}
|
|
value = (value << 3) + (value << 1) - ind;
|
|
}
|
|
if (i == end) return BigDecimal.valueOf(value, end - dp);
|
|
else if (ch == 'e' || ch == 'E') {
|
|
final int ep = i;
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return BigDecimal.valueOf(value, ep - dp - exp);
|
|
}
|
|
return BigDecimal.valueOf(value, end - dp);
|
|
} else if (ch == 'e' || ch == 'E') {
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return BigDecimal.valueOf(value, -exp);
|
|
}
|
|
return BigDecimal.valueOf(value);
|
|
}
|
|
|
|
private static final BigDecimal BD_MAX_LONG = BigDecimal.valueOf(Long.MAX_VALUE);
|
|
private static final BigDecimal BD_MIN_LONG = BigDecimal.valueOf(Long.MIN_VALUE);
|
|
|
|
private static Number bigDecimalOrDouble(BigDecimal num, JsonReader.UnknownNumberParsing unknownNumbers) {
|
|
return unknownNumbers == JsonReader.UnknownNumberParsing.LONG_AND_BIGDECIMAL
|
|
? num
|
|
: num.doubleValue();
|
|
}
|
|
|
|
private static Number tryLongFromBigDecimal(final char[] buf, final int len, JsonReader reader) throws IOException {
|
|
final BigDecimal num = parseNumberGeneric(buf, len, reader, false);
|
|
if (num.scale() == 0 && num.precision() <= 19) {
|
|
if (num.signum() == 1) {
|
|
if (num.compareTo(BD_MAX_LONG) <= 0) {
|
|
return num.longValue();
|
|
}
|
|
} else if (num.compareTo(BD_MIN_LONG) >= 0) {
|
|
return num.longValue();
|
|
}
|
|
}
|
|
return bigDecimalOrDouble(num, reader.unknownNumbers);
|
|
}
|
|
|
|
public static Number deserializeNumber(final JsonReader reader) throws IOException {
|
|
if (reader.unknownNumbers == JsonReader.UnknownNumberParsing.BIGDECIMAL) return deserializeDecimal(reader);
|
|
else if (reader.unknownNumbers == JsonReader.UnknownNumberParsing.DOUBLE) return deserializeDouble(reader);
|
|
final int start = reader.scanNumber();
|
|
int end = reader.getCurrentIndex();
|
|
if (end == reader.length()) {
|
|
NumberInfo info = readLongNumber(reader, start);
|
|
return tryLongFromBigDecimal(info.buffer, info.length, reader);
|
|
}
|
|
int len = end - start;
|
|
if (len > 18) {
|
|
return tryLongFromBigDecimal(reader.prepareBuffer(start, len), len, reader);
|
|
}
|
|
final byte[] buf = reader.buffer;
|
|
final byte ch = buf[start];
|
|
if (ch == '-') {
|
|
return parseNegativeNumber(buf, reader, start, end);
|
|
}
|
|
return parsePositiveNumber(buf, reader, start, end);
|
|
}
|
|
|
|
private static Number parsePositiveNumber(final byte[] buf, final JsonReader reader, final int start, final int end) throws IOException {
|
|
long value = 0;
|
|
byte ch = ' ';
|
|
int i = start;
|
|
final boolean leadingZero = buf[start] == 48;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == '.' || ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + 1) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start && reader.allWhitespace(i, end)) return value;
|
|
return tryLongFromBigDecimal(reader.prepareBuffer(start, end - start), end - start, reader);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == start) numberException(reader, start, end, "Digit not found");
|
|
else if (leadingZero && ch != '.' && i > start + 1) numberException(reader, start, end, "Leading zero is not allowed");
|
|
else if (i == end) return value;
|
|
else if (ch == '.') {
|
|
i++;
|
|
if (i == end) numberException(reader, start, end, "Number ends with a dot");
|
|
int dp = i;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) return BigDecimal.valueOf(value, i - dp);
|
|
return tryLongFromBigDecimal(reader.prepareBuffer(start, end - start), end - start, reader);
|
|
}
|
|
value = (value << 3) + (value << 1) + ind;
|
|
}
|
|
if (i == end) return bigDecimalOrDouble(BigDecimal.valueOf(value, end - dp), reader.unknownNumbers);
|
|
else if (ch == 'e' || ch == 'E') {
|
|
final int ep = i;
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value, ep - dp - exp), reader.unknownNumbers);
|
|
}
|
|
return BigDecimal.valueOf(value, end - dp);
|
|
} else if (ch == 'e' || ch == 'E') {
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value, -exp), reader.unknownNumbers);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value), reader.unknownNumbers);
|
|
}
|
|
|
|
private static Number parseNegativeNumber(final byte[] buf, final JsonReader reader, final int start, final int end) throws IOException {
|
|
long value = 0;
|
|
byte ch = ' ';
|
|
int i = start + 1;
|
|
final boolean leadingZero = buf[start + 1] == 48;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == '.' || ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (leadingZero && i > start + 2) {
|
|
numberException(reader, start, end, "Leading zero is not allowed");
|
|
}
|
|
if (i > start + 1 && reader.allWhitespace(i, end)) return value;
|
|
return tryLongFromBigDecimal(reader.prepareBuffer(start, end - start), end - start, reader);
|
|
}
|
|
value = (value << 3) + (value << 1) - ind;
|
|
}
|
|
if (i == start + 1) numberException(reader, start, end, "Digit not found");
|
|
else if (leadingZero && ch != '.' && i > start + 2) numberException(reader, start, end, "Leading zero is not allowed");
|
|
else if (i == end) return value;
|
|
else if (ch == '.') {
|
|
i++;
|
|
if (i == end) numberException(reader, start, end, "Number ends with a dot");
|
|
int dp = i;
|
|
for (; i < end; i++) {
|
|
ch = buf[i];
|
|
if (ch == 'e' || ch == 'E') break;
|
|
final int ind = ch - 48;
|
|
if (ind < 0 || ind > 9) {
|
|
if (reader.allWhitespace(i, end)) return BigDecimal.valueOf(value, i - dp);
|
|
return tryLongFromBigDecimal(reader.prepareBuffer(start, end - start), end - start, reader);
|
|
}
|
|
value = (value << 3) + (value << 1) - ind;
|
|
}
|
|
if (i == end) return bigDecimalOrDouble(BigDecimal.valueOf(value, end - dp), reader.unknownNumbers);
|
|
else if (ch == 'e' || ch == 'E') {
|
|
final int ep = i;
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value, ep - dp - exp), reader.unknownNumbers);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value, end - dp), reader.unknownNumbers);
|
|
} else if (ch == 'e' || ch == 'E') {
|
|
i++;
|
|
ch = buf[i];
|
|
final int exp;
|
|
if (ch == '-') {
|
|
exp = parseNegativeInt(buf, reader, i, end);
|
|
} else if (ch == '+') {
|
|
exp = parsePositiveInt(buf, reader, i, end, 1);
|
|
} else {
|
|
exp = parsePositiveInt(buf, reader, i, end, 0);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value, -exp), reader.unknownNumbers);
|
|
}
|
|
return bigDecimalOrDouble(BigDecimal.valueOf(value), reader.unknownNumbers);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<BigDecimal> deserializeDecimalCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeCollection(DecimalReader);
|
|
}
|
|
|
|
public static void deserializeDecimalCollection(final JsonReader reader, final Collection<BigDecimal> res) throws IOException {
|
|
reader.deserializeCollection(DecimalReader, res);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static ArrayList<BigDecimal> deserializeDecimalNullableCollection(final JsonReader reader) throws IOException {
|
|
return reader.deserializeNullableCollection(DecimalReader);
|
|
}
|
|
|
|
public static void deserializeDecimalNullableCollection(final JsonReader reader, final Collection<BigDecimal> res) throws IOException {
|
|
reader.deserializeNullableCollection(DecimalReader, res);
|
|
}
|
|
} |