379 lines
13 KiB
Java
379 lines
13 KiB
Java
/*
|
|
* To change this license header, choose License Headers in Project Properties.
|
|
* To change this template file, choose Tools | Templates
|
|
* and open the template in the editor.
|
|
*/
|
|
package org.redkale.convert.json;
|
|
|
|
import java.nio.*;
|
|
import java.nio.charset.*;
|
|
import org.redkale.convert.*;
|
|
import static org.redkale.convert.Reader.*;
|
|
|
|
/**
|
|
* 以ByteBuffer为数据载体的JsonReader <br>
|
|
*
|
|
* 只支持UTF-8格式
|
|
*
|
|
* 详情见: https://redkale.org
|
|
*
|
|
* @author zhangjx
|
|
*/
|
|
public class JsonByteBufferReader extends JsonReader {
|
|
|
|
private char currentChar;
|
|
|
|
private ByteBuffer[] buffers;
|
|
|
|
private int currentIndex = 0;
|
|
|
|
private ByteBuffer currentBuffer;
|
|
|
|
protected ConvertMask mask;
|
|
|
|
protected JsonByteBufferReader(ConvertMask mask, ByteBuffer... buffers) {
|
|
this.mask = mask;
|
|
this.buffers = buffers;
|
|
if (buffers != null && buffers.length > 0) this.currentBuffer = buffers[currentIndex];
|
|
}
|
|
|
|
@Override
|
|
protected boolean recycle() {
|
|
super.recycle(); // this.position 初始化值为-1
|
|
this.currentIndex = 0;
|
|
this.currentChar = 0;
|
|
this.currentBuffer = null;
|
|
this.buffers = null;
|
|
this.mask = null;
|
|
return false;
|
|
}
|
|
|
|
protected byte nextByte() {
|
|
if (this.currentBuffer.hasRemaining()) {
|
|
this.position++;
|
|
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
|
|
}
|
|
for (;;) {
|
|
this.currentBuffer = this.buffers[++this.currentIndex];
|
|
if (this.currentBuffer.hasRemaining()) {
|
|
this.position++;
|
|
return mask == null ? this.currentBuffer.get() : mask.unmask(this.currentBuffer.get());
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 读取下一个字符, 不跳过空白字符
|
|
*
|
|
* @return 有效字符或空白字符
|
|
*/
|
|
@Override
|
|
protected final char nextChar() {
|
|
if (currentChar != 0) {
|
|
char ch = currentChar;
|
|
this.currentChar = 0;
|
|
return ch;
|
|
}
|
|
if (this.currentBuffer != null) {
|
|
int remain = this.currentBuffer.remaining();
|
|
if (remain == 0 && this.currentIndex + 1 >= this.buffers.length) return 0;
|
|
}
|
|
byte b1 = nextByte();
|
|
if (b1 >= 0) {// 1 byte, 7 bits: 0xxxxxxx
|
|
return (char) b1;
|
|
} else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx
|
|
return (char) (((b1 << 6) ^ nextByte()) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80)));
|
|
} else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
|
|
return (char) ((b1 << 12) ^ (nextByte() << 6) ^ (nextByte() ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80))));
|
|
} else { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
|
throw new RuntimeException(new UnmappableCharacterException(4));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 读取下一个有效字符
|
|
*
|
|
* @return 有效字符
|
|
*/
|
|
@Override
|
|
protected final char nextGoodChar() {
|
|
char c = nextChar();
|
|
if (c > ' ' || c == 0) return c; // 0 表示buffer结尾了
|
|
for (;;) {
|
|
c = nextChar();
|
|
if (c > ' ' || c == 0) return c;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 回退最后读取的字符
|
|
*
|
|
* @param ch 回退的字符
|
|
*/
|
|
@Override
|
|
protected final void backChar(char ch) {
|
|
this.currentChar = ch;
|
|
}
|
|
|
|
/**
|
|
* 判断下一个非空白字符是否为{
|
|
*
|
|
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
|
*/
|
|
@Override
|
|
public final String readObjectB(final Class clazz) {
|
|
char ch = nextGoodChar();
|
|
if (ch == '{') return "";
|
|
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return null;
|
|
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return null;
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(ch);
|
|
char one;
|
|
try {
|
|
while ((one = nextChar()) != 0) sb.append(one);
|
|
} catch (Exception e) {
|
|
}
|
|
throw new ConvertException("a json object text must begin with '{' (position = " + position + ") but '" + ch + "' in (" + sb + ")");
|
|
}
|
|
|
|
/**
|
|
* 判断下一个非空白字符是否为[
|
|
*
|
|
* @param member DeMember
|
|
* @param decoder Decodeable
|
|
*
|
|
* @return SIGN_NOLENGTH 或 SIGN_NULL
|
|
*/
|
|
@Override
|
|
public final int readArrayB(DeMember member, Decodeable decoder) {
|
|
char ch = nextGoodChar();
|
|
if (ch == '[' || ch == '{') return SIGN_NOLENGTH;
|
|
if (ch == 'n' && nextChar() == 'u' && nextChar() == 'l' && nextChar() == 'l') return SIGN_NULL;
|
|
if (ch == 'N' && nextChar() == 'U' && nextChar() == 'L' && nextChar() == 'L') return SIGN_NULL;
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(ch);
|
|
char one;
|
|
try {
|
|
while ((one = nextChar()) != 0) sb.append(one);
|
|
} catch (Exception e) {
|
|
}
|
|
throw new ConvertException("a json array text must begin with '[' (position = " + position + ") but '" + ch + "' in (" + sb + ")");
|
|
}
|
|
|
|
/**
|
|
* 判断下一个非空白字符是否:
|
|
*/
|
|
@Override
|
|
public final void readBlank() {
|
|
char ch = nextGoodChar();
|
|
if (ch == ':') return;
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append(ch);
|
|
char one;
|
|
try {
|
|
while ((one = nextChar()) != 0) sb.append(one);
|
|
} catch (Exception e) {
|
|
}
|
|
throw new ConvertException("expected a ':' but '" + ch + "'(position = " + position + ") in (" + sb + ")");
|
|
}
|
|
|
|
/**
|
|
* 判断对象是否存在下一个属性或者数组是否存在下一个元素
|
|
*
|
|
* @param startPosition 起始位置
|
|
* @param contentLength 内容大小, 不确定的传-1
|
|
*
|
|
* @return 是否存在
|
|
*/
|
|
@Override
|
|
public boolean hasNext(int startPosition, int contentLength) {
|
|
char ch = nextGoodChar();
|
|
if (ch == ',') return true;
|
|
if (ch == '}' || ch == ']' || ch == 0) return false;
|
|
backChar(ch); // { [ 交由 readObjectB 或 readMapB 或 readArrayB 读取
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 读取小字符串
|
|
*
|
|
* @return String值
|
|
*/
|
|
@Override
|
|
public final String readSmallString() {
|
|
char ch = nextGoodChar();
|
|
if (ch == 0) return null;
|
|
final StringBuilder sb = new StringBuilder();
|
|
if (ch == '"' || ch == '\'') {
|
|
final char quote = ch;
|
|
for (;;) {
|
|
ch = nextChar();
|
|
if (ch == '\\') {
|
|
char c = nextChar();
|
|
switch (c) {
|
|
case '"':
|
|
case '\'':
|
|
case '\\':
|
|
case '/':
|
|
sb.append(c);
|
|
break;
|
|
case 'n':
|
|
sb.append('\n');
|
|
break;
|
|
case 'r':
|
|
sb.append('\r');
|
|
break;
|
|
case 'u':
|
|
sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16));
|
|
break;
|
|
case 't':
|
|
sb.append('\t');
|
|
break;
|
|
case 'b':
|
|
sb.append('\b');
|
|
break;
|
|
case 'f':
|
|
sb.append('\f');
|
|
break;
|
|
default:
|
|
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
|
|
}
|
|
} else if (ch == quote || ch == 0) {
|
|
break;
|
|
} else {
|
|
sb.append(ch);
|
|
}
|
|
}
|
|
return sb.toString();
|
|
} else {
|
|
sb.append(ch);
|
|
for (;;) {
|
|
ch = nextChar();
|
|
if (ch == '\\') {
|
|
char c = nextChar();
|
|
switch (c) {
|
|
case '"':
|
|
case '\'':
|
|
case '\\':
|
|
case '/':
|
|
sb.append(c);
|
|
break;
|
|
case 'n':
|
|
sb.append('\n');
|
|
break;
|
|
case 'r':
|
|
sb.append('\r');
|
|
break;
|
|
case 'u':
|
|
sb.append((char) Integer.parseInt(new String(new char[]{nextChar(), nextChar(), nextChar(), nextChar()}), 16));
|
|
break;
|
|
case 't':
|
|
sb.append('\t');
|
|
break;
|
|
case 'b':
|
|
sb.append('\b');
|
|
break;
|
|
case 'f':
|
|
sb.append('\f');
|
|
break;
|
|
default:
|
|
throw new ConvertException("illegal escape(" + c + ") (position = " + this.position + ")");
|
|
}
|
|
} else if (ch == ',' || ch == ']' || ch == '}' || ch <= ' ' || ch == ':') { // ch <= ' ' 包含 0
|
|
backChar(ch);
|
|
break;
|
|
} else {
|
|
sb.append(ch);
|
|
}
|
|
}
|
|
String rs = sb.toString();
|
|
return "null".equalsIgnoreCase(rs) ? null : rs;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 读取一个int值
|
|
*
|
|
* @return int值
|
|
*/
|
|
@Override
|
|
public final int readInt() {
|
|
char firstchar = nextGoodChar();
|
|
boolean quote = false;
|
|
if (firstchar == '"' || firstchar == '\'') {
|
|
quote = true;
|
|
firstchar = nextGoodChar();
|
|
if (firstchar == '"' || firstchar == '\'') return 0;
|
|
}
|
|
int value = 0;
|
|
final boolean negative = firstchar == '-';
|
|
if (!negative) {
|
|
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
|
|
value = firstchar - '0';
|
|
}
|
|
for (;;) {
|
|
char ch = nextChar();
|
|
if (ch == 0) break;
|
|
if (ch >= '0' && ch <= '9') {
|
|
value = (value << 3) + (value << 1) + (ch - '0');
|
|
} else if (ch == '"' || ch == '\'') {
|
|
} else if (quote && ch <= ' ') {
|
|
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
|
|
backChar(ch);
|
|
break;
|
|
} else {
|
|
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
|
|
}
|
|
}
|
|
return negative ? -value : value;
|
|
}
|
|
|
|
/**
|
|
* 读取一个long值
|
|
*
|
|
* @return long值
|
|
*/
|
|
@Override
|
|
public final long readLong() {
|
|
char firstchar = nextGoodChar();
|
|
boolean quote = false;
|
|
if (firstchar == '"' || firstchar == '\'') {
|
|
quote = true;
|
|
firstchar = nextGoodChar();
|
|
if (firstchar == '"' || firstchar == '\'') return 0L;
|
|
}
|
|
long value = 0;
|
|
final boolean negative = firstchar == '-';
|
|
if (!negative) {
|
|
if (firstchar < '0' || firstchar > '9') throw new ConvertException("illegal escape(" + firstchar + ") (position = " + position + ")");
|
|
value = firstchar - '0';
|
|
}
|
|
for (;;) {
|
|
char ch = nextChar();
|
|
if (ch == 0) break;
|
|
if (ch >= '0' && ch <= '9') {
|
|
value = (value << 3) + (value << 1) + (ch - '0');
|
|
} else if (ch == '"' || ch == '\'') {
|
|
} else if (quote && ch <= ' ') {
|
|
} else if (ch == ',' || ch == '}' || ch == ']' || ch <= ' ' || ch == ':') {
|
|
backChar(ch);
|
|
break;
|
|
} else {
|
|
throw new ConvertException("illegal escape(" + ch + ") (position = " + position + ")");
|
|
}
|
|
}
|
|
return negative ? -value : value;
|
|
}
|
|
|
|
/**
|
|
* 读取字符串, 必须是"或者'包围的字符串值
|
|
*
|
|
* @return String值
|
|
*/
|
|
@Override
|
|
public final String readString() {
|
|
return readSmallString();
|
|
}
|
|
|
|
}
|