All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dslplatform.json.BigIntegerConverter Maven / Gradle / Ivy

There is a newer version: 1.10.0
Show newest version
package com.dslplatform.json;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;

public abstract class BigIntegerConverter {

	static final JsonReader.ReadObject Reader = reader -> reader.wasNull() ? null : deserialize(reader);
	static final JsonWriter.WriteObject Writer = (writer, value) -> serialize(value, writer);

	private static void numberException(final JsonReader reader, final int start, final int end, String message) throws IOException {
		final int len = end - start;
		final char[] buf = reader.prepareBuffer(reader.getCurrentIndex() - len, len);
		if (len < reader.maxNumberDigits) {
			final NumberFormatException error = new NumberFormatException(new String(buf, 0, len));
			throw new IOException("Error parsing number at position: " + reader.positionInStream(len) + ". " + message, error);
		}
		throw new IOException("Error parsing number at position: " + reader.positionInStream(len) + ". " + message);
	}

	private static BigInteger parseNumberGeneric(final char[] buf, final int len, final JsonReader reader) throws IOException {
		int end = len;
		while (end > 0 && Character.isWhitespace(buf[end - 1])) {
			end--;
		}
		try {
			return new BigInteger(new String(buf, 0, end));
		} catch (NumberFormatException nfe) {
			throw new IOException("Error parsing number at position: " + reader.positionInStream(len), nfe);
		}
	}

	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 i = reader.length() - start;
		char[] tmp = reader.prepareBuffer(start, i);
		final long position = reader.positionInStream();
		while (!reader.isEndOfStream()) {
			while (i < tmp.length) {
				final char ch = (char) reader.read();
				tmp[i++] = ch;
				if (reader.isEndOfStream() || !(ch >= '0' && ch <= '9' || ch == '-' || ch == '+' || ch == '.' || ch == 'e' || ch == 'E')) {
					return new NumberInfo(tmp, i);
				}
			}
			final int newSize = tmp.length * 2;
			if (newSize > reader.maxNumberDigits) throw new IOException("Unable to read number at: " + position + ". Number of digits larger than " + reader.maxNumberDigits);
			tmp = Arrays.copyOf(tmp, newSize);
		}
		return new NumberInfo(tmp, i);
	}

	public static void serialize(final BigInteger value, final JsonWriter sw) {
		if (value == null) {
			sw.writeNull();
		} else {
			sw.writeAscii(value.toString());
		}
	}

	public static BigInteger deserialize(final JsonReader reader) throws IOException {
		if (reader.last() == '"') {
			final int len = reader.parseString();
			return parseNumberGeneric(reader.chars, len, reader);
		}
		final int start = reader.scanNumber();
		int end = reader.getCurrentIndex();
		int len = end - start;
		if (len > 18) {
			end = reader.findNonWhitespace(end);
			len = end - start;
			if (end == reader.length()) {
				final NumberInfo info = readLongNumber(reader, start);
				return parseNumberGeneric(info.buffer, info.length, reader);
			} else if (len > 18) {
				return parseNumberGeneric(reader.prepareBuffer(start, len), len, reader);
			}
		}
		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");
			for (; i < end; i++) {
				final int ind = buf[i] - 48;
				if (ind < 0 || ind > 9) {
					if (i > start + 1 && reader.allWhitespace(i, end)) return BigInteger.valueOf(value);
					numberException(reader, start, end, "Unknown digit: " + (char)ch);
				}
				value = (value << 3) + (value << 1) - ind;
			}
			return BigInteger.valueOf(value);
		}
		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 (ch == '+' && i > start + 1 && reader.allWhitespace(i, end)) return BigInteger.valueOf(value);
				else if (ch != '+' && i > start && reader.allWhitespace(i, end)) return BigInteger.valueOf(value);
				numberException(reader, start, end, "Unknown digit: " + (char)ch);
			}
			value = (value << 3) + (value << 1) + ind;
		}
		return BigInteger.valueOf(value);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy