package com.jsoniter;
import com.jsoniter.any.Any;
import java.io.IOException;
class IterImplForStreaming {
public static final int readObjectFieldAsHash(JsonIterator iter) throws IOException {
if (nextToken(iter) != '"') {
throw iter.reportError("readObjectFieldAsHash", "expect \"");
}
long hash = 0x811c9dc5;
for (; ; ) {
byte c = 0;
int i = iter.head;
for (; i < iter.tail; i++) {
c = iter.buf[i];
if (c == '"') {
break;
}
hash ^= c;
hash *= 0x1000193;
}
if (c == '"') {
iter.head = i + 1;
if (nextToken(iter) != ':') {
throw iter.reportError("readObjectFieldAsHash", "expect :");
}
return (int) hash;
}
if (!loadMore(iter)) {
throw iter.reportError("readObjectFieldAsHash", "unmatched quote");
}
}
}
public static final Slice readObjectFieldAsSlice(JsonIterator iter) throws IOException {
Slice field = readSlice(iter);
boolean notCopied = field != null;
if (CodegenAccess.skipWhitespacesWithoutLoadMore(iter)) {
if (notCopied) {
int len = field.tail() - field.head();
byte[] newBuf = new byte[len];
System.arraycopy(field.data(), field.head(), newBuf, 0, len);
field.reset(newBuf, 0, newBuf.length);
}
if (!loadMore(iter)) {
throw iter.reportError("readObjectFieldAsSlice", "expect : after object field");
}
}
if (iter.buf[iter.head] != ':') {
throw iter.reportError("readObjectFieldAsSlice", "expect : after object field");
}
iter.head++;
return field;
}
final static void skipArray(JsonIterator iter) throws IOException {
int level = 1;
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
switch (iter.buf[i]) {
case '"': // If inside string, skip it
iter.head = i + 1;
skipString(iter);
i = iter.head - 1; // it will be i++ soon
break;
case '[': // If open symbol, increase level
level++;
break;
case ']': // If close symbol, increase level
level--;
// If we have returned to the original level, we're done
if (level == 0) {
iter.head = i + 1;
return;
}
break;
}
}
if (!loadMore(iter)) {
return;
}
}
}
final static void skipObject(JsonIterator iter) throws IOException {
int level = 1;
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
switch (iter.buf[i]) {
case '"': // If inside string, skip it
iter.head = i + 1;
skipString(iter);
i = iter.head - 1; // it will be i++ soon
break;
case '{': // If open symbol, increase level
level++;
break;
case '}': // If close symbol, increase level
level--;
// If we have returned to the original level, we're done
if (level == 0) {
iter.head = i + 1;
return;
}
break;
}
}
if (!loadMore(iter)) {
return;
}
}
}
final static void skipString(JsonIterator iter) throws IOException {
for (; ; ) {
int end = IterImplSkip.findStringEnd(iter);
if (end == -1) {
int j = iter.tail - 1;
boolean escaped = true;
// can not just look the last byte is \
// because it could be \\ or \\\
for (; ; ) {
// walk backward until head
if (j < iter.head || iter.buf[j] != '\\') {
// even number of backslashes
// either end of buffer, or " found
escaped = false;
break;
}
j--;
if (j < iter.head || iter.buf[j] != '\\') {
// odd number of backslashes
// it is \" or \\\"
break;
}
j--;
}
if (!loadMore(iter)) {
throw iter.reportError("skipString", "incomplete string");
}
if (escaped) {
iter.head = 1; // skip the first char as last char is \
}
} else {
iter.head = end;
return;
}
}
}
final static void skipUntilBreak(JsonIterator iter) throws IOException {
// true, false, null, number
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
byte c = iter.buf[i];
if (IterImplSkip.breaks[c]) {
iter.head = i;
return;
}
}
if (!loadMore(iter)) {
iter.head = iter.tail;
return;
}
}
}
final static boolean skipNumber(JsonIterator iter) throws IOException {
// true, false, null, number
boolean dotFound = false;
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
byte c = iter.buf[i];
if (c == '.') {
dotFound = true;
continue;
}
if (IterImplSkip.breaks[c]) {
iter.head = i;
return dotFound;
}
}
if (!loadMore(iter)) {
iter.head = iter.tail;
return dotFound;
}
}
}
// read the bytes between " "
final static Slice readSlice(JsonIterator iter) throws IOException {
if (IterImpl.nextToken(iter) != '"') {
throw iter.reportError("readSlice", "expect \" for string");
}
int end = IterImplString.findSliceEnd(iter);
if (end != -1) {
// reuse current buffer
iter.reusableSlice.reset(iter.buf, iter.head, end - 1);
iter.head = end;
return iter.reusableSlice;
}
// TODO: avoid small memory allocation
byte[] part1 = new byte[iter.tail - iter.head];
System.arraycopy(iter.buf, iter.head, part1, 0, part1.length);
for (; ; ) {
if (!loadMore(iter)) {
throw iter.reportError("readSlice", "unmatched quote");
}
end = IterImplString.findSliceEnd(iter);
if (end == -1) {
byte[] part2 = new byte[part1.length + iter.buf.length];
System.arraycopy(part1, 0, part2, 0, part1.length);
System.arraycopy(iter.buf, 0, part2, part1.length, iter.buf.length);
part1 = part2;
} else {
byte[] part2 = new byte[part1.length + end - 1];
System.arraycopy(part1, 0, part2, 0, part1.length);
System.arraycopy(iter.buf, 0, part2, part1.length, end - 1);
iter.head = end;
iter.reusableSlice.reset(part2, 0, part2.length);
return iter.reusableSlice;
}
}
}
final static byte nextToken(JsonIterator iter) throws IOException {
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
byte c = iter.buf[i];
switch (c) {
case ' ':
case '\n':
case '\t':
case '\r':
continue;
default:
iter.head = i + 1;
return c;
}
}
if (!loadMore(iter)) {
return 0;
}
}
}
public final static boolean loadMore(JsonIterator iter) throws IOException {
if (iter.in == null) {
return false;
}
if (iter.skipStartedAt != -1) {
return keepSkippedBytesThenRead(iter);
}
int n = iter.in.read(iter.buf);
if (n < 1) {
if (n == -1) {
return false;
} else {
throw iter.reportError("loadMore", "read from input stream returned " + n);
}
} else {
iter.head = 0;
iter.tail = n;
}
return true;
}
private static boolean keepSkippedBytesThenRead(JsonIterator iter) throws IOException {
int n;
int offset;
if (iter.skipStartedAt == 0 || iter.skipStartedAt < iter.tail / 2) {
byte[] newBuf = new byte[iter.buf.length * 2];
offset = iter.tail - iter.skipStartedAt;
System.arraycopy(iter.buf, iter.skipStartedAt, newBuf, 0, offset);
iter.buf = newBuf;
n = iter.in.read(iter.buf, offset, iter.buf.length - offset);
} else {
offset = iter.tail - iter.skipStartedAt;
System.arraycopy(iter.buf, iter.skipStartedAt, iter.buf, 0, offset);
n = iter.in.read(iter.buf, offset, iter.buf.length - offset);
}
iter.skipStartedAt = 0;
if (n < 1) {
if (n == -1) {
return false;
} else {
throw iter.reportError("loadMore", "read from input stream returned " + n);
}
} else {
iter.head = offset;
iter.tail = offset + n;
}
return true;
}
final static byte readByte(JsonIterator iter) throws IOException {
if (iter.head == iter.tail) {
if (!loadMore(iter)) {
throw iter.reportError("readByte", "no more to read");
}
}
return iter.buf[iter.head++];
}
public static Any readAny(JsonIterator iter) throws IOException {
// TODO: avoid small memory allocation
iter.skipStartedAt = iter.head;
byte c = nextToken(iter);
switch (c) {
case '"':
skipString(iter);
byte[] copied = copySkippedBytes(iter);
return Any.lazyString(copied, 0, copied.length);
case 't':
skipFixedBytes(iter, 3);
iter.skipStartedAt = -1;
return Any.wrap(true);
case 'f':
skipFixedBytes(iter, 4);
iter.skipStartedAt = -1;
return Any.wrap(false);
case 'n':
skipFixedBytes(iter, 3);
iter.skipStartedAt = -1;
return Any.wrap((Object) null);
case '[':
skipArray(iter);
copied = copySkippedBytes(iter);
return Any.lazyArray(copied, 0, copied.length);
case '{':
skipObject(iter);
copied = copySkippedBytes(iter);
return Any.lazyObject(copied, 0, copied.length);
default:
if (skipNumber(iter)) {
copied = copySkippedBytes(iter);
return Any.lazyDouble(copied, 0, copied.length);
} else {
copied = copySkippedBytes(iter);
return Any.lazyLong(copied, 0, copied.length);
}
}
}
private static byte[] copySkippedBytes(JsonIterator iter) {
int start = iter.skipStartedAt;
iter.skipStartedAt = -1;
int end = iter.head;
byte[] bytes = new byte[end - start];
System.arraycopy(iter.buf, start, bytes, 0, bytes.length);
return bytes;
}
public static void skipFixedBytes(JsonIterator iter, int n) throws IOException {
iter.head += n;
if (iter.head >= iter.tail) {
int more = iter.head - iter.tail;
if (!loadMore(iter)) {
if (more == 0) {
iter.head = iter.tail;
return;
}
throw iter.reportError("skipFixedBytes", "unexpected end");
}
iter.head += more;
}
}
public static int updateStringCopyBound(final JsonIterator iter, final int bound) {
if (bound > iter.tail - iter.head) {
return iter.tail - iter.head;
} else {
return bound;
}
}
public final static int readStringSlowPath(JsonIterator iter, int j) throws IOException {
for (;;) {
int bc = readByte(iter);
if (bc == '"') {
return j;
}
if (bc == '\\') {
bc = readByte(iter);
switch (bc) {
case 'b':
bc = '\b';
break;
case 't':
bc = '\t';
break;
case 'n':
bc = '\n';
break;
case 'f':
bc = '\f';
break;
case 'r':
bc = '\r';
break;
case '"':
case '/':
case '\\':
break;
case 'u':
bc = (IterImplString.translateHex(readByte(iter)) << 12) +
(IterImplString.translateHex(readByte(iter)) << 8) +
(IterImplString.translateHex(readByte(iter)) << 4) +
IterImplString.translateHex(readByte(iter));
break;
default:
throw iter.reportError("readStringSlowPath", "invalid escape character: " + bc);
}
} else if ((bc & 0x80) != 0) {
final int u2 = readByte(iter);
if ((bc & 0xE0) == 0xC0) {
bc = ((bc & 0x1F) << 6) + (u2 & 0x3F);
} else {
final int u3 = readByte(iter);
if ((bc & 0xF0) == 0xE0) {
bc = ((bc & 0x0F) << 12) + ((u2 & 0x3F) << 6) + (u3 & 0x3F);
} else {
final int u4 = readByte(iter);
if ((bc & 0xF8) == 0xF0) {
bc = ((bc & 0x07) << 18) + ((u2 & 0x3F) << 12) + ((u3 & 0x3F) << 6) + (u4 & 0x3F);
} else {
throw iter.reportError("readStringSlowPath", "invalid unicode character");
}
if (bc >= 0x10000) {
// check if valid unicode
if (bc >= 0x110000)
throw iter.reportError("readStringSlowPath", "invalid unicode character");
// split surrogates
final int sup = bc - 0x10000;
if (iter.reusableChars.length == j) {
char[] newBuf = new char[iter.reusableChars.length * 2];
System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length);
iter.reusableChars = newBuf;
}
iter.reusableChars[j++] = (char) ((sup >>> 10) + 0xd800);
if (iter.reusableChars.length == j) {
char[] newBuf = new char[iter.reusableChars.length * 2];
System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length);
iter.reusableChars = newBuf;
}
iter.reusableChars[j++] = (char) ((sup & 0x3ff) + 0xdc00);
continue;
}
}
}
}
if (iter.reusableChars.length == j) {
char[] newBuf = new char[iter.reusableChars.length * 2];
System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length);
iter.reusableChars = newBuf;
}
iter.reusableChars[j++] = (char) bc;
}
}
static long readLongSlowPath(JsonIterator iter, long value) throws IOException {
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
int ind = IterImplNumber.intDigits[iter.buf[i]];
if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) {
iter.head = i;
return value;
}
value = (value << 3) + (value << 1) + ind;
if (value < 0) {
// overflow
if (value == Long.MIN_VALUE) {
// if there is more number following, subsequent read will fail anyway
iter.head = i;
return value;
} else {
throw iter.reportError("readPositiveLong", "value is too large for long");
}
}
}
if (!IterImpl.loadMore(iter)) {
iter.head = iter.tail;
return value;
}
}
}
static int readIntSlowPath(JsonIterator iter, int value) throws IOException {
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
int ind = IterImplNumber.intDigits[iter.buf[i]];
if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) {
iter.head = i;
return value;
}
value = (value << 3) + (value << 1) + ind;
if (value < 0) {
// overflow
if (value == Integer.MIN_VALUE) {
// if there is more number following, subsequent read will fail anyway
iter.head = i;
return value;
} else {
throw iter.reportError("readPositiveInt", "value is too large for int");
}
}
}
if (!IterImpl.loadMore(iter)) {
iter.head = iter.tail;
return value;
}
}
}
public static final double readDoubleSlowPath(final JsonIterator iter) throws IOException {
try {
return Double.valueOf(readNumber(iter));
} catch (NumberFormatException e) {
throw iter.reportError("readDoubleSlowPath", e.toString());
}
}
public static final String readNumber(final JsonIterator iter) throws IOException {
int j = 0;
for (; ; ) {
for (int i = iter.head; i < iter.tail; i++) {
if (j == iter.reusableChars.length) {
char[] newBuf = new char[iter.reusableChars.length * 2];
System.arraycopy(iter.reusableChars, 0, newBuf, 0, iter.reusableChars.length);
iter.reusableChars = newBuf;
}
byte c = iter.buf[i];
switch (c) {
case '-':
case '.':
case 'e':
case 'E':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
iter.reusableChars[j++] = (char) c;
break;
default:
iter.head = i;
return new String(iter.reusableChars, 0, j);
}
}
if (!IterImpl.loadMore(iter)) {
iter.head = iter.tail;
return new String(iter.reusableChars, 0, j);
}
}
}
static final double readPositiveDouble(final JsonIterator iter) throws IOException {
return readDoubleSlowPath(iter);
}
static final long readPositiveLong(final JsonIterator iter, byte c) throws IOException {
long ind = IterImplNumber.intDigits[c];
if (ind == 0) {
return 0;
}
if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) {
throw iter.reportError("readPositiveLong", "expect 0~9");
}
return IterImplForStreaming.readLongSlowPath(iter, ind);
}
static final int readPositiveInt(final JsonIterator iter, byte c) throws IOException {
int ind = IterImplNumber.intDigits[c];
if (ind == 0) {
return 0;
}
if (ind == IterImplNumber.INVALID_CHAR_FOR_NUMBER) {
throw iter.reportError("readPositiveInt", "expect 0~9");
}
return IterImplForStreaming.readIntSlowPath(iter, ind);
}
}