/**********************************************************\
| |
| hprose |
| |
| Official WebSite: http://www.hprose.com/ |
| http://www.hprose.org/ |
| |
\**********************************************************/
/**********************************************************\
* *
* ValueWriter.java *
* *
* value writer class for Java. *
* *
* LastModified: Aug 16, 2016 *
* Author: Ma Bingyao <andot@hprose.com> *
* *
\**********************************************************/
package net.hasor.libs.com.hprose.io.serialize;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Calendar;
import static net.hasor.libs.com.hprose.io.HproseTags.*;
public final class ValueWriter {
private final static byte[] digits = {//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'//
};
private final static byte[] DigitTens = {//
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',//
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',//
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',//
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',//
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',//
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',//
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',//
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',//
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',//
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9'//
};
private final static byte[] DigitOnes = {//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'//
};
private final static byte[] minIntBuf = new byte[] {//
'-', '2', '1', '4', '7', '4', '8', '3', '6', '4', '8'//
};
private final static byte[] minLongBuf = new byte[] {//
'-', '9', '2', '2', '3', '3', '7', '2', '0', '3',//
'6', '8', '5', '4', '7', '7', '5', '8', '0', '8'//
};
private final static ThreadLocal<byte[]> buffer = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[20];
}
};
public final static void writeInt(OutputStream stream, int i) throws IOException {
if ((i >= 0) && (i <= 9)) {
stream.write((byte) ('0' + i));
} else if (i == Integer.MIN_VALUE) {
stream.write(minIntBuf);
} else {
byte[] buf = buffer.get();
int off = 20;
int q, r;
byte sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
while (i >= 65536) {
q = i / 100;
r = i - (q * 100);
i = q;
buf[--off] = DigitOnes[r];
buf[--off] = DigitTens[r];
}
for (; ; ) {
q = (i * 52429) >>> (16 + 3);
r = i - (q * 10);
buf[--off] = digits[r];
i = q;
if (i == 0)
break;
}
if (sign != 0) {
buf[--off] = sign;
}
stream.write(buf, off, 20 - off);
}
}
public final static void writeInt(OutputStream stream, long i) throws IOException {
if ((i >= 0) && (i <= 9)) {
stream.write((byte) ('0' + i));
} else if (i == Long.MIN_VALUE) {
stream.write(minLongBuf);
} else {
byte[] buf = buffer.get();
long q;
int off = 20;
int q2, r;
byte sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
while (i > Integer.MAX_VALUE) {
q = i / 100;
r = (int) (i - (q * 100));
i = q;
buf[--off] = DigitOnes[r];
buf[--off] = DigitTens[r];
}
int i2 = (int) i;
while (i2 >= 65536) {
q2 = i2 / 100;
r = i2 - (q2 * 100);
i2 = q2;
buf[--off] = DigitOnes[r];
buf[--off] = DigitTens[r];
}
for (; ; ) {
q2 = (i2 * 52429) >>> (16 + 3);
r = i2 - (q2 * 10);
buf[--off] = digits[r];
i2 = q2;
if (i2 == 0)
break;
}
if (sign != 0) {
buf[--off] = sign;
}
stream.write(buf, off, 20 - off);
}
}
public final static void write(OutputStream stream, int i) throws IOException {
if (i >= 0 && i <= 9) {
stream.write(i + '0');
} else {
stream.write(TagInteger);
writeInt(stream, i);
stream.write(TagSemicolon);
}
}
public final static void write(OutputStream stream, long l) throws IOException {
if (l >= 0 && l <= 9) {
stream.write((int) l + '0');
} else {
stream.write(TagLong);
writeInt(stream, l);
stream.write(TagSemicolon);
}
}
public final static void write(OutputStream stream, boolean b) throws IOException {
stream.write(b ? TagTrue : TagFalse);
}
public final static void write(OutputStream stream, float f) throws IOException {
if (Float.isNaN(f)) {
stream.write(TagNaN);
} else if (Float.isInfinite(f)) {
stream.write(TagInfinity);
stream.write(f > 0 ? TagPos : TagNeg);
} else {
stream.write(TagDouble);
stream.write(getAscii(Float.toString(f)));
stream.write(TagSemicolon);
}
}
public final static void write(OutputStream stream, double d) throws IOException {
if (Double.isNaN(d)) {
stream.write(TagNaN);
} else if (Double.isInfinite(d)) {
stream.write(TagInfinity);
stream.write(d > 0 ? TagPos : TagNeg);
} else {
stream.write(TagDouble);
stream.write(getAscii(Double.toString(d)));
stream.write(TagSemicolon);
}
}
public final static void write(OutputStream stream, BigInteger bi) throws IOException {
stream.write(TagLong);
stream.write(getAscii(bi.toString()));
stream.write(TagSemicolon);
}
public final static void write(OutputStream stream, BigDecimal bd) throws IOException {
stream.write(TagDouble);
stream.write(getAscii(bd.toString()));
stream.write(TagSemicolon);
}
public final static void write(OutputStream stream, char c) throws IOException {
stream.write(TagUTF8Char);
if (c < 0x80) {
stream.write(c);
} else if (c < 0x800) {
stream.write(0xc0 | (c >>> 6));
stream.write(0x80 | (c & 0x3f));
} else {
stream.write(0xe0 | (c >>> 12));
stream.write(0x80 | ((c >>> 6) & 0x3f));
stream.write(0x80 | (c & 0x3f));
}
}
public final static void write(OutputStream stream, char[] s) throws IOException {
int length = s.length;
if (length > 0) {
writeInt(stream, length);
}
stream.write(TagQuote);
stream.write(new String(s).getBytes("UTF-8"));
/*
byte[] b = new byte[length * 3];
int n = 0;
for (int i = 0; i < length; ++i) {
int c = 0xffff & s[i];
if (c < 0x80) {
b[n++] = (byte)c;
}
else if (c < 0x800) {
b[n++] = (byte)(0xc0 | (c >>> 6));
b[n++] = (byte)(0x80 | (c & 0x3f));
}
else if (c < 0xd800 || c > 0xdfff) {
b[n++] = (byte)(0xe0 | (c >>> 12));
b[n++] = (byte)(0x80 | ((c >>> 6) & 0x3f));
b[n++] = (byte)(0x80 | (c & 0x3f));
}
else {
if (++i < length) {
int c2 = 0xffff & s[i];
if (c < 0xdc00 && 0xdc00 <= c2 && c2 <= 0xdfff) {
c = ((c & 0x03ff) << 10 | (c2 & 0x03ff)) + 0x010000;
b[n++] = (byte)(0xf0 | (c >>> 18));
b[n++] = (byte)(0x80 | ((c >>> 12) & 0x3f));
b[n++] = (byte)(0x80 | ((c >>> 6) & 0x3f));
b[n++] = (byte)(0x80 | (c & 0x3f));
}
else {
throw new HproseException("wrong unicode string");
}
}
else {
throw new HproseException("wrong unicode string");
}
}
}
stream.write(b, 0, n);
*/
stream.write(TagQuote);
}
public final static void write(OutputStream stream, String s) throws IOException {
int length = s.length();
if (length > 0) {
writeInt(stream, length);
}
stream.write(TagQuote);
stream.write(s.getBytes("UTF-8"));
/*
byte[] b = new byte[length * 3];
int n = 0;
for (int i = 0; i < length; ++i) {
int c = 0xffff & s.charAt(i);
if (c < 0x80) {
b[n++] = (byte)c;
}
else if (c < 0x800) {
b[n++] = (byte)(0xc0 | (c >>> 6));
b[n++] = (byte)(0x80 | (c & 0x3f));
}
else if (c < 0xd800 || c > 0xdfff) {
b[n++] = (byte)(0xe0 | (c >>> 12));
b[n++] = (byte)(0x80 | ((c >>> 6) & 0x3f));
b[n++] = (byte)(0x80 | (c & 0x3f));
}
else {
if (++i < length) {
int c2 = 0xffff & s.charAt(i);
if (c < 0xdc00 && 0xdc00 <= c2 && c2 <= 0xdfff) {
c = ((c & 0x03ff) << 10 | (c2 & 0x03ff)) + 0x010000;
b[n++] = (byte)(0xf0 | (c >>> 18));
b[n++] = (byte)(0x80 | ((c >>> 12) & 0x3f));
b[n++] = (byte)(0x80 | ((c >>> 6) & 0x3f));
b[n++] = (byte)(0x80 | (c & 0x3f));
}
else {
throw new HproseException("wrong unicode string");
}
}
else {
throw new HproseException("wrong unicode string");
}
}
}
stream.write(b, 0, n);
*/
stream.write(TagQuote);
}
public final static void writeDate(OutputStream stream, int year, int month, int day) throws IOException {
stream.write(TagDate);
stream.write((byte) ('0' + (year / 1000 % 10)));
stream.write((byte) ('0' + (year / 100 % 10)));
stream.write((byte) ('0' + (year / 10 % 10)));
stream.write((byte) ('0' + (year % 10)));
stream.write((byte) ('0' + (month / 10 % 10)));
stream.write((byte) ('0' + (month % 10)));
stream.write((byte) ('0' + (day / 10 % 10)));
stream.write((byte) ('0' + (day % 10)));
}
public final static void writeDateOfCalendar(OutputStream stream, Calendar calendar) throws IOException {
writeDate(stream, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH));
}
public final static void writeTime(OutputStream stream, int hour, int minute, int second, int millisecond, boolean ignoreZero, boolean ignoreMillisecond) throws IOException {
if (ignoreZero && hour == 0 && minute == 0 && second == 0 && millisecond == 0) {
return;
}
stream.write(TagTime);
stream.write((byte) ('0' + (hour / 10 % 10)));
stream.write((byte) ('0' + (hour % 10)));
stream.write((byte) ('0' + (minute / 10 % 10)));
stream.write((byte) ('0' + (minute % 10)));
stream.write((byte) ('0' + (second / 10 % 10)));
stream.write((byte) ('0' + (second % 10)));
if (!ignoreMillisecond && millisecond > 0) {
stream.write(TagPoint);
stream.write((byte) ('0' + (millisecond / 100 % 10)));
stream.write((byte) ('0' + (millisecond / 10 % 10)));
stream.write((byte) ('0' + (millisecond % 10)));
}
}
public final static void writeTimeOfCalendar(OutputStream stream, Calendar calendar, boolean ignoreZero, boolean ignoreMillisecond) throws IOException {
writeTime(stream, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), calendar.get(Calendar.SECOND), calendar.get(Calendar.MILLISECOND), ignoreZero, ignoreMillisecond);
}
public final static void writeNano(OutputStream stream, int nanosecond) throws IOException {
if (nanosecond > 0) {
stream.write(TagPoint);
stream.write((byte) ('0' + (nanosecond / 100000000 % 10)));
stream.write((byte) ('0' + (nanosecond / 10000000 % 10)));
stream.write((byte) ('0' + (nanosecond / 1000000 % 10)));
if (nanosecond % 1000000 > 0) {
stream.write((byte) ('0' + (nanosecond / 100000 % 10)));
stream.write((byte) ('0' + (nanosecond / 10000 % 10)));
stream.write((byte) ('0' + (nanosecond / 1000 % 10)));
if (nanosecond % 1000 > 0) {
stream.write((byte) ('0' + (nanosecond / 100 % 10)));
stream.write((byte) ('0' + (nanosecond / 10 % 10)));
stream.write((byte) ('0' + (nanosecond % 10)));
}
}
}
}
public final static byte[] getAscii(String s) {
int size = s.length();
byte[] b = new byte[size--];
for (; size >= 0; --size) {
b[size] = (byte) s.charAt(size);
}
return b;
}
}