/*
* Copyright 1999-2017 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.fastjson.serializer;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.util.IOUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.List;
import static com.alibaba.fastjson.util.IOUtils.replaceChars;
/**
* @author wenshao[szujobs@hotmail.com]
*/
public final class SerializeWriter extends Writer {
private final static Charset UTF8 = Charset.forName("UTF-8");
private final static ThreadLocal<char[]> bufLocal = new ThreadLocal<char[]>();
private final static ThreadLocal<byte[]> bytesBufLocal = new ThreadLocal<byte[]>();
protected char buf[];
/**
* The number of chars in the buffer.
*/
protected int count;
protected int features;
private final Writer writer;
protected boolean useSingleQuotes;
protected boolean quoteFieldNames;
protected boolean sortField;
protected boolean disableCircularReferenceDetect;
protected boolean beanToArray;
protected boolean writeNonStringValueAsString;
protected boolean notWriteDefaultValue;
protected boolean writeEnumUsingName;
protected boolean writeEnumUsingToString;
protected boolean writeDirect;
protected char keySeperator;
protected int maxBufSize = -1;
public SerializeWriter(){
this((Writer) null);
}
public SerializeWriter(Writer writer){
this(writer, JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.EMPTY);
}
public SerializeWriter(SerializerFeature... features){
this(null, features);
}
public SerializeWriter(Writer writer, SerializerFeature... features){
this(writer, 0, features);
}
/**
* @since 1.2.9
* @param writer
* @param defaultFeatures
* @param features
*/
public SerializeWriter(Writer writer, int defaultFeatures, SerializerFeature... features){
this.writer = writer;
buf = bufLocal.get();
if (buf != null) {
bufLocal.set(null);
} else {
buf = new char[2048];
}
int featuresValue = defaultFeatures;
for (SerializerFeature feature : features) {
featuresValue |= feature.getMask();
}
this.features = featuresValue;
computeFeatures();
}
public int getMaxBufSize() {
return maxBufSize;
}
public void setMaxBufSize(int maxBufSize) {
if (maxBufSize < this.buf.length) {
throw new JSONException("must > " + buf.length);
}
this.maxBufSize = maxBufSize;
}
public int getBufferLength() {
return this.buf.length;
}
public SerializeWriter(int initialSize){
this(null, initialSize);
}
public SerializeWriter(Writer writer, int initialSize){
this.writer = writer;
if (initialSize <= 0) {
throw new IllegalArgumentException("Negative initial size: " + initialSize);
}
buf = new char[initialSize];
// computeFeatures();
}
public void config(SerializerFeature feature, boolean state) {
if (state) {
features |= feature.getMask();
// 由于枚举序列化特性WriteEnumUsingToString和WriteEnumUsingName不能共存,需要检查
if (feature == SerializerFeature.WriteEnumUsingToString) {
features &= ~SerializerFeature.WriteEnumUsingName.getMask();
} else if (feature == SerializerFeature.WriteEnumUsingName) {
features &= ~SerializerFeature.WriteEnumUsingToString.getMask();
}
} else {
features &= ~feature.getMask();
}
computeFeatures();
}
final static int nonDirectFeautres = 0 //
| SerializerFeature.UseSingleQuotes.mask //
| SerializerFeature.BrowserSecure.mask //
| SerializerFeature.BrowserCompatible.mask //
| SerializerFeature.PrettyFormat.mask //
| SerializerFeature.WriteEnumUsingToString.mask
| SerializerFeature.WriteNonStringValueAsString.mask
| SerializerFeature.WriteSlashAsSpecial.mask
| SerializerFeature.IgnoreErrorGetter.mask
| SerializerFeature.WriteClassName.mask
| SerializerFeature.NotWriteDefaultValue.mask
;
protected void computeFeatures() {
quoteFieldNames = (this.features & SerializerFeature.QuoteFieldNames.mask) != 0;
useSingleQuotes = (this.features & SerializerFeature.UseSingleQuotes.mask) != 0;
sortField = (this.features & SerializerFeature.SortField.mask) != 0;
disableCircularReferenceDetect = (this.features & SerializerFeature.DisableCircularReferenceDetect.mask) != 0;
beanToArray = (this.features & SerializerFeature.BeanToArray.mask) != 0;
writeNonStringValueAsString = (this.features & SerializerFeature.WriteNonStringValueAsString.mask) != 0;
notWriteDefaultValue = (this.features & SerializerFeature.NotWriteDefaultValue.mask) != 0;
writeEnumUsingName = (this.features & SerializerFeature.WriteEnumUsingName.mask) != 0;
writeEnumUsingToString = (this.features & SerializerFeature.WriteEnumUsingToString.mask) != 0;
writeDirect = quoteFieldNames //
&& (this.features & nonDirectFeautres) == 0 //
&& (beanToArray || writeEnumUsingName)
;
keySeperator = useSingleQuotes ? '\'' : '"';
}
public boolean isSortField() {
return sortField;
}
public boolean isNotWriteDefaultValue() {
return notWriteDefaultValue;
}
public boolean isEnabled(SerializerFeature feature) {
return (this.features & feature.mask) != 0;
}
public boolean isEnabled(int feature) {
return (this.features & feature) != 0;
}
/**
* Writes a character to the buffer.
*/
public void write(int c) {
int newcount = count + 1;
if (newcount > buf.length) {
if (writer == null) {
expandCapacity(newcount);
} else {
flush();
newcount = 1;
}
}
buf[count] = (char) c;
count = newcount;
}
/**
* Writes characters to the buffer.
*
* @param c the data to be written
* @param off the start offset in the data
* @param len the number of chars that are written
*/
public void write(char c[], int off, int len) {
if (off < 0 //
|| off > c.length //
|| len < 0 //
|| off + len > c.length //
|| off + len < 0) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
int newcount = count + len;
if (newcount > buf.length) {
if (writer == null) {
expandCapacity(newcount);
} else {
do {
int rest = buf.length - count;
System.arraycopy(c, off, buf, count, rest);
count = buf.length;
flush();
len -= rest;
off += rest;
} while (len > buf.length);
newcount = len;
}
}
System.arraycopy(c, off, buf, count, len);
count = newcount;
}
public void expandCapacity(int minimumCapacity) {
if (maxBufSize != -1 && minimumCapacity >= maxBufSize) {
throw new JSONException("serialize exceeded MAX_OUTPUT_LENGTH=" + maxBufSize + ", minimumCapacity=" + minimumCapacity);
}
int newCapacity = (buf.length * 3) / 2 + 1;
if (newCapacity < minimumCapacity) {
newCapacity = minimumCapacity;
}
char newValue[] = new char[newCapacity];
System.arraycopy(buf, 0, newValue, 0, count);
buf = newValue;
}
public SerializeWriter append(CharSequence csq) {
String s = (csq == null ? "null" : csq.toString());
write(s, 0, s.length());
return this;
}
public SerializeWriter append(CharSequence csq, int start, int end) {
String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
write(s, 0, s.length());
return this;
}
public SerializeWriter append(char c) {
write(c);
return this;
}
/**
* Write a portion of a string to the buffer.
*
* @param str String to be written from
* @param off Offset from which to start reading characters
* @param len Number of characters to be written
*/
public void write(String str, int off, int len) {
int newcount = count + len;
if (newcount > buf.length) {
if (writer == null) {
expandCapacity(newcount);
} else {
do {
int rest = buf.length - count;
str.getChars(off, off + rest, buf, count);
count = buf.length;
flush();
len -= rest;
off += rest;
} while (len > buf.length);
newcount = len;
}
}
str.getChars(off, off + len, buf, count);
count = newcount;
}
/**
* Writes the contents of the buffer to another character stream.
*
* @param out the output stream to write to
* @throws IOException If an I/O error occurs.
*/
public void writeTo(Writer out) throws IOException {
if (this.writer != null) {
throw new UnsupportedOperationException("writer not null");
}
out.write(buf, 0, count);
}
public void writeTo(OutputStream out, String charsetName) throws IOException {
writeTo(out, Charset.forName(charsetName));
}
public void writeTo(OutputStream out, Charset charset) throws IOException {
writeToEx(out, charset);
}
public int writeToEx(OutputStream out, Charset charset) throws IOException {
if (this.writer != null) {
throw new UnsupportedOperationException("writer not null");
}
if (charset == UTF8) {
return encodeToUTF8(out);
} else {
byte[] bytes = new String(buf, 0, count).getBytes(charset);
out.write(bytes);
return bytes.length;
}
}
/**
* Returns a copy of the input data.
*
* @return an array of chars copied from the input data.
*/
public char[] toCharArray() {
if (this.writer != null) {
throw new UnsupportedOperationException("writer not null");
}
char[] newValue = new char[count];
System.arraycopy(buf, 0, newValue, 0, count);
return newValue;
}
/**
* only for springwebsocket
* @return
*/
public char[] toCharArrayForSpringWebSocket() {
if (this.writer != null) {
throw new UnsupportedOperationException("writer not null");
}
char[] newValue = new char[count - 2];
System.arraycopy(buf, 1, newValue, 0, count - 2);
return newValue;
}
public byte[] toBytes(String charsetName) {
return toBytes(charsetName == null || "UTF-8".equals(charsetName) //
? UTF8 //
: Charset.forName(charsetName));
}
public byte[] toBytes(Charset charset) {
if (this.writer != null) {
throw new UnsupportedOperationException("writer not null");
}
if (charset == UTF8) {
return encodeToUTF8Bytes();
} else {
return new String(buf, 0, count).getBytes(charset);
}
}
private int encodeToUTF8(OutputStream out) throws IOException {
int bytesLength = (int) (count * (double) 3);
byte[] bytes = bytesBufLocal.get();
if (bytes == null) {
bytes = new byte[1024 * 8];
bytesBufLocal.set(bytes);
}
if (bytes.length < bytesLength) {
bytes = new byte[bytesLength];
}
int position = IOUtils.encodeUTF8(buf, 0, count, bytes);
out.write(bytes, 0, position);
return position;
}
private byte[] encodeToUTF8Bytes() {
int bytesLength = (int) (count * (double) 3);
byte[] bytes = bytesBufLocal.get();
if (bytes == null) {
bytes = new byte[1024 * 8];
bytesBufLocal.set(bytes);
}
if (bytes.length < bytesLength) {
bytes = new byte[bytesLength];
}
int position = IOUtils.encodeUTF8(buf, 0, count, bytes);
byte[] copy = new byte[position];
System.arraycopy(bytes, 0, copy, 0, position);
return copy;
}
public int size() {
return count;
}
public String toString() {
return new String(buf, 0, count);
}
/**
* Close the stream. This method does not release the buffer, since its contents might still be required. Note:
* Invoking this method in this class will have no effect.
*/
public void close() {
if (writer != null && count > 0) {
flush();
}
if (buf.length <= 1024 * 64) {
bufLocal.set(buf);
}
this.buf = null;
}
public void write(String text) {
if (text == null) {
writeNull();
return;
}
write(text, 0, text.length());
}
public void writeInt(int i) {
if (i == Integer.MIN_VALUE) {
write("-2147483648");
return;
}
int size = (i < 0) ? IOUtils.stringSize(-i) + 1 : IOUtils.stringSize(i);
int newcount = count + size;
if (newcount > buf.length) {
if (writer == null) {
expandCapacity(newcount);
} else {
char[] chars = new char[size];
IOUtils.getChars(i, size, chars);
write(chars, 0, chars.length);
return;
}
}
IOUtils.getChars(i, newcount, buf);
count = newcount;
}
public void writeByteArray(byte[] bytes) {
int bytesLen = bytes.length;
final char quote = useSingleQuotes ? '\'' : '"';
if (bytesLen == 0) {
String emptyString = useSingleQuotes ? "''" : "\"\"";
write(emptyString);
return;
}
final char[] CA = IOUtils.CA;
int eLen = (bytesLen / 3) * 3; // Length of even 24-bits.
int charsLen = ((bytesLen - 1) / 3 + 1) << 2; // base64 character count
// char[] chars = new char[charsLen];
int offset = count;
int newcount = count + charsLen + 2;
if (newcount > buf.length) {
if (writer != null) {
write(quote);
for (int s = 0; s < eLen;) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);
// Encode the int into four chars
write(CA[(i >>> 18) & 0x3f]);
write(CA[(i >>> 12) & 0x3f]);
write(CA[(i >>> 6) & 0x3f]);
write(CA[i & 0x3f]);
}
// Pad and encode last bits if source isn't even 24 bits.
int left = bytesLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = ((bytes[eLen] & 0xff) << 10) | (left == 2 ? ((bytes[bytesLen - 1] & 0xff) << 2) : 0);
// Set last four chars
write(CA[i >> 12]);
write(CA[(i >>> 6) & 0x3f]);
write(left == 2 ? CA[i & 0x3f] : '=');
write('=');
}
write(quote);
return;
}
expandCapacity(newcount);
}
count = newcount;
buf[offset++] = quote;
// Encode even 24-bits
for (int s = 0, d = offset; s < eLen;) {
// Copy next three bytes into lower 24 bits of int, paying attension to sign.
int i = (bytes[s++] & 0xff) << 16 | (bytes[s++] & 0xff) << 8 | (bytes[s++] & 0xff);
// Encode the int into four chars
buf[d++] = CA[(i >>> 18) & 0x3f];
buf[d++] = CA[(i >>> 12) & 0x3f];
buf[d++] = CA[(i >>> 6) & 0x3f];
buf[d++] = CA[i & 0x3f];
}
// Pad and encode last bits if source isn't even 24 bits.
int left = bytesLen - eLen; // 0 - 2.
if (left > 0) {
// Prepare the int
int i = ((bytes[eLen] & 0xff) << 10) | (left == 2 ? ((bytes[bytesLen - 1] & 0xff) << 2) : 0);
// Set last four chars
buf[newcount - 5] = CA[i >> 12];
buf[newcount - 4] = CA[(i >>> 6) & 0x3f];
buf[newcount - 3] = left == 2 ? CA[i & 0x3f] : '=';
buf[newcount - 2] = '=';
}
buf[newcount - 1] = quote;
}
public void writeFloat(float value, boolean checkWriteClassName) {
if (Float.isNaN(value) //
|| Float.isInfinite(value)) {
writeNull();
} else {
String floatText= Float.toString(value);
if (isEnabled(SerializerFeature.WriteNullNumberAsZero) && floatText.endsWith(".0")) {
floatText = floatText.substring(0, floatText.length() - 2);
}
write(floatText);
if (checkWriteClassName && isEnabled(SerializerFeature.WriteClassName)) {
write('F');
}
}
}
public void writeDouble(double doubleValue, boolean checkWriteClassName) {
if (Double.isNaN(doubleValue) //
|| Double.isInfinite(doubleValue)) {
writeNull();
} else {
String doubleText = Double.toString(doubleValue);
if (isEnabled(SerializerFeature.WriteNullNumberAsZero) && doubleText.endsWith(".0")) {
doubleText = doubleText.substring(0, doubleText.length() - 2);
}
write(doubleText);
if (checkWriteClassName && isEnabled(SerializerFeature.WriteClassName)) {
write('D');
}
}
}
public void writeEnum(Enum<?> value) {
if (value == null) {
writeNull();
return;
}
String strVal = null;
if (writeEnumUsingName && !writeEnumUsingToString) {
strVal = value.name();
} else if (writeEnumUsingToString) {
strVal = value.toString();;
}
if (strVal != null) {
char quote = isEnabled(SerializerFeature.UseSingleQuotes) ? '\'' : '"';
write(quote);
write(strVal);
write(quote);
} else {
writeInt(value.ordinal());
}
}
public void writeLong(long i) {
boolean needQuotationMark = isEnabled(SerializerFeature.BrowserCompatible) //
&& (!isEnabled(SerializerFeature.WriteClassName)) //
&& (i > 9007199254740991L || i < -9007199254740991L);
if (i == Long.MIN_VALUE) {
if (needQuotationMark) write("\"-9223372036854775808\"");
else write("-9223372036854775808");
return;
}
int size = (i < 0) ? IOUtils.stringSize(-i) + 1 : IOUtils.stringSize(i);
int newcount = count + size;
if (needQuotationMark) newcount += 2;
if (newcount > buf.length) {
if (writer == null) {
expandCapacity(newcount);
} else {
char[] chars = new char[size];
IOUtils.getChars(i, size, chars);
if (needQuotationMark) {
write('"');
write(chars, 0, chars.length);
write('"');
} else {
write(chars, 0, chars.length);
}
return;
}
}
if (needQuotationMark) {
buf[count] = '"';
IOUtils.getChars(i, newcount - 1, buf);
buf[newcount - 1] = '"';
} else {
IOUtils.getChars(i, newcount, buf);
}
count = newcount;
}
public void writeNull() {
write("null");
}
public void writeNull(SerializerFeature feature) {
writeNull(0, feature.mask);
}
public void writeNull(int beanFeatures , int feature) {
if ((beanFeatures & feature) == 0 //
&& (this.features & feature) == 0) {
writeNull();
return;
}
if (feature == SerializerFeature.WriteNullListAsEmpty.mask) {
write("[]");
} else if (feature == SerializerFeature.WriteNullStringAsEmpty.mask) {
writeString("");
} else if (feature == SerializerFeature.WriteNullBooleanAsFalse.mask) {
write("false");
} else if (feature == SerializerFeature.WriteNullNumberAsZero.mask) {
write('0');
} else {
writeNull();
}
}
public void writeStringWithDoubleQuote(String text, final char seperator) {
if (text == null) {
writeNull();
if (seperator != 0) {
write(seperator);
}
return;
}
int len = text.length();
int newcount = count + len + 2;
if (seperator != 0) {
newcount++;
}
if (newcount > buf.length) {
if (writer != null) {
write('"');
for (int i = 0; i < text.length(); ++i) {
char ch = text.charAt(i);
if (isEnabled(SerializerFeature.BrowserSecure)) {
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z')
&& !(ch == ',') && !(ch == '.') && !(ch == '_')) {
write('\\');
write('u');
write(IOUtils.DIGITS[(ch >>> 12) & 15]);
write(IOUtils.DIGITS[(ch >>> 8) & 15]);
write(IOUtils.DIGITS[(ch >>> 4) & 15]);
write(IOUtils.DIGITS[ch & 15]);
continue;
}
} else if (isEnabled(SerializerFeature.BrowserCompatible)) {
if (ch == '\b' //
|| ch == '\f' //
|| ch == '\n' //
|| ch == '\r' //
|| ch == '\t' //
|| ch == '"' //
|| ch == '/' //
|| ch == '\\') {
write('\\');
write(replaceChars[(int) ch]);
continue;
}
if (ch < 32) {
write('\\');
write('u');
write('0');
write('0');
write(IOUtils.ASCII_CHARS[ch * 2]);
write(IOUtils.ASCII_CHARS[ch * 2 + 1]);
continue;
}
if (ch >= 127) {
write('\\');
write('u');
write(IOUtils.DIGITS[(ch >>> 12) & 15]);
write(IOUtils.DIGITS[(ch >>> 8) & 15]);
write(IOUtils.DIGITS[(ch >>> 4) & 15]);
write(IOUtils.DIGITS[ch & 15]);
continue;
}
} else {
if (ch < IOUtils.specicalFlags_doubleQuotes.length
&& IOUtils.specicalFlags_doubleQuotes[ch] != 0 //
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
write('\\');
if (IOUtils.specicalFlags_doubleQuotes[ch] == 4) {
write('u');
write(IOUtils.DIGITS[ch >>> 12 & 15]);
write(IOUtils.DIGITS[ch >>> 8 & 15]);
write(IOUtils.DIGITS[ch >>> 4 & 15]);
write(IOUtils.DIGITS[ch & 15]);
} else {
write(IOUtils.replaceChars[ch]);
}
continue;
}
}
write(ch);
}
write('"');
if (seperator != 0) {
write(seperator);
}
return;
}
expandCapacity(newcount);
}
int start = count + 1;
int end = start + len;
buf[count] = '\"';
text.getChars(0, len, buf, start);
count = newcount;
if (isEnabled(SerializerFeature.BrowserSecure)) {
int lastSpecialIndex = -1;
for (int i = start; i < end; ++i) {
char ch = buf[i];
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch == ',')
&& !(ch == '.') && !(ch == '_')) {
lastSpecialIndex = i;
newcount += 5;
continue;
}
}
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
for (int i = lastSpecialIndex; i >= start; --i) {
char ch = buf[i];
if (!(ch >= '0' && ch <= '9') && !(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch == ',')
&& !(ch == '.') && !(ch == '_')) {
System.arraycopy(buf, i + 1, buf, i + 6, end - i - 1);
buf[i] = '\\';
buf[i + 1] = 'u';
buf[i + 2] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[i + 3] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[i + 4] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[i + 5] = IOUtils.DIGITS[ch & 15];
end += 5;
}
}
if (seperator != 0) {
buf[count - 2] = '\"';
buf[count - 1] = seperator;
} else {
buf[count - 1] = '\"';
}
return;
}
if (isEnabled(SerializerFeature.BrowserCompatible)) {
int lastSpecialIndex = -1;
for (int i = start; i < end; ++i) {
char ch = buf[i];
if (ch == '"' //
|| ch == '/' //
|| ch == '\\') {
lastSpecialIndex = i;
newcount += 1;
continue;
}
if (ch == '\b' //
|| ch == '\f' //
|| ch == '\n' //
|| ch == '\r' //
|| ch == '\t') {
lastSpecialIndex = i;
newcount += 1;
continue;
}
if (ch < 32) {
lastSpecialIndex = i;
newcount += 5;
continue;
}
if (ch >= 127) {
lastSpecialIndex = i;
newcount += 5;
continue;
}
}
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
for (int i = lastSpecialIndex; i >= start; --i) {
char ch = buf[i];
if (ch == '\b' //
|| ch == '\f'//
|| ch == '\n' //
|| ch == '\r' //
|| ch == '\t') {
System.arraycopy(buf, i + 1, buf, i + 2, end - i - 1);
buf[i] = '\\';
buf[i + 1] = replaceChars[(int) ch];
end += 1;
continue;
}
if (ch == '"' //
|| ch == '/' //
|| ch == '\\') {
System.arraycopy(buf, i + 1, buf, i + 2, end - i - 1);
buf[i] = '\\';
buf[i + 1] = ch;
end += 1;
continue;
}
if (ch < 32) {
System.arraycopy(buf, i + 1, buf, i + 6, end - i - 1);
buf[i] = '\\';
buf[i + 1] = 'u';
buf[i + 2] = '0';
buf[i + 3] = '0';
buf[i + 4] = IOUtils.ASCII_CHARS[ch * 2];
buf[i + 5] = IOUtils.ASCII_CHARS[ch * 2 + 1];
end += 5;
continue;
}
if (ch >= 127) {
System.arraycopy(buf, i + 1, buf, i + 6, end - i - 1);
buf[i] = '\\';
buf[i + 1] = 'u';
buf[i + 2] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[i + 3] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[i + 4] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[i + 5] = IOUtils.DIGITS[ch & 15];
end += 5;
}
}
if (seperator != 0) {
buf[count - 2] = '\"';
buf[count - 1] = seperator;
} else {
buf[count - 1] = '\"';
}
return;
}
int specialCount = 0;
int lastSpecialIndex = -1;
int firstSpecialIndex = -1;
char lastSpecial = '\0';
for (int i = start; i < end; ++i) {
char ch = buf[i];
if (ch == '\u2028' || ch == '\u2029') {
specialCount++;
lastSpecialIndex = i;
lastSpecial = ch;
newcount += 4;
if (firstSpecialIndex == -1) {
firstSpecialIndex = i;
}
continue;
}
if (ch >= ']') {
if (ch >= 0x7F && ch < 0xA0) {
if (firstSpecialIndex == -1) {
firstSpecialIndex = i;
}
specialCount++;
lastSpecialIndex = i;
lastSpecial = ch;
newcount += 4;
}
continue;
}
if (isSpecial(ch, this.features)) {
specialCount++;
lastSpecialIndex = i;
lastSpecial = ch;
if (ch < IOUtils.specicalFlags_doubleQuotes.length //
&& IOUtils.specicalFlags_doubleQuotes[ch] == 4 //
) {
newcount += 4;
}
if (firstSpecialIndex == -1) {
firstSpecialIndex = i;
}
}
}
if (specialCount > 0) {
newcount += specialCount;
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
if (specialCount == 1) {
if (lastSpecial == '\u2028') {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 6;
int LengthOfCopy = end - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = 'u';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '0';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '8';
} else if (lastSpecial == '\u2029') {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 6;
int LengthOfCopy = end - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = 'u';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '0';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '9';
} else {
final char ch = lastSpecial;
if (ch < IOUtils.specicalFlags_doubleQuotes.length //
&& IOUtils.specicalFlags_doubleQuotes[ch] == 4) {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 6;
int LengthOfCopy = end - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
int bufIndex = lastSpecialIndex;
buf[bufIndex++] = '\\';
buf[bufIndex++] = 'u';
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[bufIndex++] = IOUtils.DIGITS[ch & 15];
} else {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 2;
int LengthOfCopy = end - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = replaceChars[(int) ch];
}
}
} else if (specialCount > 1) {
int textIndex = firstSpecialIndex - start;
int bufIndex = firstSpecialIndex;
for (int i = textIndex; i < text.length(); ++i) {
char ch = text.charAt(i);
if (ch < IOUtils.specicalFlags_doubleQuotes.length //
&& IOUtils.specicalFlags_doubleQuotes[ch] != 0 //
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
buf[bufIndex++] = '\\';
if (IOUtils.specicalFlags_doubleQuotes[ch] == 4) {
buf[bufIndex++] = 'u';
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[bufIndex++] = IOUtils.DIGITS[ch & 15];
end += 5;
} else {
buf[bufIndex++] = replaceChars[(int) ch];
end++;
}
} else {
if (ch == '\u2028' || ch == '\u2029') {
buf[bufIndex++] = '\\';
buf[bufIndex++] = 'u';
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[bufIndex++] = IOUtils.DIGITS[ch & 15];
end += 5;
} else {
buf[bufIndex++] = ch;
}
}
}
}
}
if (seperator != 0) {
buf[count - 2] = '\"';
buf[count - 1] = seperator;
} else {
buf[count - 1] = '\"';
}
}
public void writeFieldNameDirect(String text) {
int len = text.length();
int newcount = count + len + 3;
if (newcount > buf.length) {
expandCapacity(newcount);
}
int start = count + 1;
buf[count] = '\"';
text.getChars(0, len, buf, start);
count = newcount;
buf[count - 2] = '\"';
buf[count - 1] = ':';
}
public void write(List<String> list) {
if (list.isEmpty()) {
write("[]");
return;
}
int offset = count;
final int initOffset = offset;
for (int i = 0, list_size = list.size(); i < list_size; ++i) {
String text = list.get(i);
boolean hasSpecial = false;
if (text == null) {
hasSpecial = true;
} else {
for (int j = 0, len = text.length(); j < len; ++j) {
char ch = text.charAt(j);
if (hasSpecial = (ch < ' ' //
|| ch > '~' //
|| ch == '"' //
|| ch == '\\')) {
break;
}
}
}
if (hasSpecial) {
count = initOffset;
write('[');
for (int j = 0; j < list.size(); ++j) {
text = list.get(j);
if (j != 0) {
write(',');
}
if (text == null) {
write("null");
} else {
writeStringWithDoubleQuote(text, (char) 0);
}
}
write(']');
return;
}
int newcount = offset + text.length() + 3;
if (i == list.size() - 1) {
newcount++;
}
if (newcount > buf.length) {
count = offset;
expandCapacity(newcount);
}
if (i == 0) {
buf[offset++] = '[';
} else {
buf[offset++] = ',';
}
buf[offset++] = '"';
text.getChars(0, text.length(), buf, offset);
offset += text.length();
buf[offset++] = '"';
}
buf[offset++] = ']';
count = offset;
}
public void writeFieldValue(char seperator, String name, char value) {
write(seperator);
writeFieldName(name);
if (value == 0) {
writeString("\u0000");
} else {
writeString(Character.toString(value));
}
}
public void writeFieldValue(char seperator, String name, boolean value) {
if (!quoteFieldNames) {
write(seperator);
writeFieldName(name);
write(value);
return;
}
int intSize = value ? 4 : 5;
int nameLen = name.length();
int newcount = count + nameLen + 4 + intSize;
if (newcount > buf.length) {
if (writer != null) {
write(seperator);
writeString(name);
write(':');
write(value);
return;
}
expandCapacity(newcount);
}
int start = count;
count = newcount;
buf[start] = seperator;
int nameEnd = start + nameLen + 1;
buf[start + 1] = keySeperator;
name.getChars(0, nameLen, buf, start + 2);
buf[nameEnd + 1] = keySeperator;
if (value) {
System.arraycopy(":true".toCharArray(), 0, buf, nameEnd + 2, 5);
} else {
System.arraycopy(":false".toCharArray(), 0, buf, nameEnd + 2, 6);
}
}
public void write(boolean value) {
if (value) {
write("true");
} else {
write("false");
}
}
public void writeFieldValue(char seperator, String name, int value) {
if (value == Integer.MIN_VALUE || !quoteFieldNames) {
write(seperator);
writeFieldName(name);
writeInt(value);
return;
}
int intSize = (value < 0) ? IOUtils.stringSize(-value) + 1 : IOUtils.stringSize(value);
int nameLen = name.length();
int newcount = count + nameLen + 4 + intSize;
if (newcount > buf.length) {
if (writer != null) {
write(seperator);
writeFieldName(name);
writeInt(value);
return;
}
expandCapacity(newcount);
}
int start = count;
count = newcount;
buf[start] = seperator;
int nameEnd = start + nameLen + 1;
buf[start + 1] = keySeperator;
name.getChars(0, nameLen, buf, start + 2);
buf[nameEnd + 1] = keySeperator;
buf[nameEnd + 2] = ':';
IOUtils.getChars(value, count, buf);
}
public void writeFieldValue(char seperator, String name, long value) {
if (value == Long.MIN_VALUE || !quoteFieldNames) {
write(seperator);
writeFieldName(name);
writeLong(value);
return;
}
int intSize = (value < 0) ? IOUtils.stringSize(-value) + 1 : IOUtils.stringSize(value);
int nameLen = name.length();
int newcount = count + nameLen + 4 + intSize;
if (newcount > buf.length) {
if (writer != null) {
write(seperator);
writeFieldName(name);
writeLong(value);
return;
}
expandCapacity(newcount);
}
int start = count;
count = newcount;
buf[start] = seperator;
int nameEnd = start + nameLen + 1;
buf[start + 1] = keySeperator;
name.getChars(0, nameLen, buf, start + 2);
buf[nameEnd + 1] = keySeperator;
buf[nameEnd + 2] = ':';
IOUtils.getChars(value, count, buf);
}
public void writeFieldValue(char seperator, String name, float value) {
write(seperator);
writeFieldName(name);
writeFloat(value, false);
}
public void writeFieldValue(char seperator, String name, double value) {
write(seperator);
writeFieldName(name);
writeDouble(value, false);
}
public void writeFieldValue(char seperator, String name, String value) {
if (quoteFieldNames) {
if (useSingleQuotes) {
write(seperator);
writeFieldName(name);
if (value == null) {
writeNull();
} else {
writeString(value);
}
} else {
if (isEnabled(SerializerFeature.BrowserSecure)) {
write(seperator);
writeStringWithDoubleQuote(name, ':');
writeStringWithDoubleQuote(value, (char) 0);
} else if (isEnabled(SerializerFeature.BrowserCompatible)) {
write(seperator);
writeStringWithDoubleQuote(name, ':');
writeStringWithDoubleQuote(value, (char) 0);
} else {
writeFieldValueStringWithDoubleQuoteCheck(seperator, name, value);
}
}
} else {
write(seperator);
writeFieldName(name);
if (value == null) {
writeNull();
} else {
writeString(value);
}
}
}
public void writeFieldValueStringWithDoubleQuoteCheck(char seperator, String name, String value) {
int nameLen = name.length();
int valueLen;
int newcount = count;
if (value == null) {
valueLen = 4;
newcount += nameLen + 8;
} else {
valueLen = value.length();
newcount += nameLen + valueLen + 6;
}
if (newcount > buf.length) {
if (writer != null) {
write(seperator);
writeStringWithDoubleQuote(name, ':');
writeStringWithDoubleQuote(value, (char) 0);
return;
}
expandCapacity(newcount);
}
buf[count] = seperator;
int nameStart = count + 2;
int nameEnd = nameStart + nameLen;
buf[count + 1] = '\"';
name.getChars(0, nameLen, buf, nameStart);
count = newcount;
buf[nameEnd] = '\"';
int index = nameEnd + 1;
buf[index++] = ':';
if (value == null) {
buf[index++] = 'n';
buf[index++] = 'u';
buf[index++] = 'l';
buf[index++] = 'l';
return;
}
buf[index++] = '"';
int valueStart = index;
int valueEnd = valueStart + valueLen;
value.getChars(0, valueLen, buf, valueStart);
int specialCount = 0;
int lastSpecialIndex = -1;
int firstSpecialIndex = -1;
char lastSpecial = '\0';
for (int i = valueStart; i < valueEnd; ++i) {
char ch = buf[i];
if (ch >= ']') {
if (ch >= 0x7F //
&& (ch == '\u2028' //
|| ch == '\u2029' //
|| ch < 0xA0)) {
if (firstSpecialIndex == -1) {
firstSpecialIndex = i;
}
specialCount++;
lastSpecialIndex = i;
lastSpecial = ch;
newcount += 4;
}
continue;
}
if (isSpecial(ch, this.features)) {
specialCount++;
lastSpecialIndex = i;
lastSpecial = ch;
if (ch < IOUtils.specicalFlags_doubleQuotes.length //
&& IOUtils.specicalFlags_doubleQuotes[ch] == 4 //
) {
newcount += 4;
}
if (firstSpecialIndex == -1) {
firstSpecialIndex = i;
}
}
}
if (specialCount > 0) {
newcount += specialCount;
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
if (specialCount == 1) {
if (lastSpecial == '\u2028') {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 6;
int LengthOfCopy = valueEnd - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = 'u';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '0';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '8';
} else if (lastSpecial == '\u2029') {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 6;
int LengthOfCopy = valueEnd - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = 'u';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '0';
buf[++lastSpecialIndex] = '2';
buf[++lastSpecialIndex] = '9';
} else {
final char ch = lastSpecial;
if (ch < IOUtils.specicalFlags_doubleQuotes.length //
&& IOUtils.specicalFlags_doubleQuotes[ch] == 4) {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 6;
int LengthOfCopy = valueEnd - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
int bufIndex = lastSpecialIndex;
buf[bufIndex++] = '\\';
buf[bufIndex++] = 'u';
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[bufIndex++] = IOUtils.DIGITS[ch & 15];
} else {
int srcPos = lastSpecialIndex + 1;
int destPos = lastSpecialIndex + 2;
int LengthOfCopy = valueEnd - lastSpecialIndex - 1;
System.arraycopy(buf, srcPos, buf, destPos, LengthOfCopy);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = replaceChars[(int) ch];
}
}
} else if (specialCount > 1) {
int textIndex = firstSpecialIndex - valueStart;
int bufIndex = firstSpecialIndex;
for (int i = textIndex; i < value.length(); ++i) {
char ch = value.charAt(i);
if (ch < IOUtils.specicalFlags_doubleQuotes.length //
&& IOUtils.specicalFlags_doubleQuotes[ch] != 0 //
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
buf[bufIndex++] = '\\';
if (IOUtils.specicalFlags_doubleQuotes[ch] == 4) {
buf[bufIndex++] = 'u';
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[bufIndex++] = IOUtils.DIGITS[ch & 15];
valueEnd += 5;
} else {
buf[bufIndex++] = replaceChars[(int) ch];
valueEnd++;
}
} else {
if (ch == '\u2028' || ch == '\u2029') {
buf[bufIndex++] = '\\';
buf[bufIndex++] = 'u';
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 12) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 8) & 15];
buf[bufIndex++] = IOUtils.DIGITS[(ch >>> 4) & 15];
buf[bufIndex++] = IOUtils.DIGITS[ch & 15];
valueEnd += 5;
} else {
buf[bufIndex++] = ch;
}
}
}
}
}
buf[count - 1] = '\"';
}
public void writeFieldValueStringWithDoubleQuote(char seperator, String name, String value) {
int nameLen = name.length();
int valueLen;
int newcount = count;
valueLen = value.length();
newcount += nameLen + valueLen + 6;
if (newcount > buf.length) {
if (writer != null) {
write(seperator);
writeStringWithDoubleQuote(name, ':');
writeStringWithDoubleQuote(value, (char) 0);
return;
}
expandCapacity(newcount);
}
buf[count] = seperator;
int nameStart = count + 2;
int nameEnd = nameStart + nameLen;
buf[count + 1] = '\"';
name.getChars(0, nameLen, buf, nameStart);
count = newcount;
buf[nameEnd] = '\"';
int index = nameEnd + 1;
buf[index++] = ':';
buf[index++] = '"';
int valueStart = index;
value.getChars(0, valueLen, buf, valueStart);
buf[count - 1] = '\"';
}
static boolean isSpecial(char ch, int features) {
// if (ch > ']') {
// return false;
// }
if (ch == ' ') { // 32
return false;
}
if (ch == '/') { // 47
return (features & SerializerFeature.WriteSlashAsSpecial.mask) != 0;
}
if (ch > '#' // 35
&& ch != '\\' // 92
) {
return false;
}
if (ch <= 0x1F // 31
|| ch == '\\' // 92
|| ch == '"' // 34
) {
return true;
}
return false;
}
// writeStringWithSingleQuote
public void writeFieldValue(char seperator, String name, Enum<?> value) {
if (value == null) {
write(seperator);
writeFieldName(name);
writeNull();
return;
}
if (writeEnumUsingName && !writeEnumUsingToString) {
writeEnumFieldValue(seperator, name, value.name());
} else if (writeEnumUsingToString) {
writeEnumFieldValue(seperator, name, value.toString());
} else {
writeFieldValue(seperator, name, value.ordinal());
}
}
private void writeEnumFieldValue(char seperator, String name, String value) {
if (useSingleQuotes) {
writeFieldValue(seperator, name, value);
} else {
writeFieldValueStringWithDoubleQuote(seperator, name, value);
}
}
public void writeFieldValue(char seperator, String name, BigDecimal value) {
write(seperator);
writeFieldName(name);
if (value == null) {
writeNull();
} else {
write(value.toString());
}
}
public void writeString(String text, char seperator) {
if (useSingleQuotes) {
writeStringWithSingleQuote(text);
write(seperator);
} else {
writeStringWithDoubleQuote(text, seperator);
}
}
public void writeString(String text) {
if (useSingleQuotes) {
writeStringWithSingleQuote(text);
} else {
writeStringWithDoubleQuote(text, (char) 0);
}
}
protected void writeStringWithSingleQuote(String text) {
if (text == null) {
int newcount = count + 4;
if (newcount > buf.length) {
expandCapacity(newcount);
}
"null".getChars(0, 4, buf, count);
count = newcount;
return;
}
int len = text.length();
int newcount = count + len + 2;
if (newcount > buf.length) {
if (writer != null) {
write('\'');
for (int i = 0; i < text.length(); ++i) {
char ch = text.charAt(i);
if (ch <= 13 || ch == '\\' || ch == '\'' //
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
write('\\');
write(replaceChars[(int) ch]);
} else {
write(ch);
}
}
write('\'');
return;
}
expandCapacity(newcount);
}
int start = count + 1;
int end = start + len;
buf[count] = '\'';
text.getChars(0, len, buf, start);
count = newcount;
int specialCount = 0;
int lastSpecialIndex = -1;
char lastSpecial = '\0';
for (int i = start; i < end; ++i) {
char ch = buf[i];
if (ch <= 13 || ch == '\\' || ch == '\'' //
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
specialCount++;
lastSpecialIndex = i;
lastSpecial = ch;
}
}
newcount += specialCount;
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
if (specialCount == 1) {
System.arraycopy(buf, lastSpecialIndex + 1, buf, lastSpecialIndex + 2, end - lastSpecialIndex - 1);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = replaceChars[(int) lastSpecial];
} else if (specialCount > 1) {
System.arraycopy(buf, lastSpecialIndex + 1, buf, lastSpecialIndex + 2, end - lastSpecialIndex - 1);
buf[lastSpecialIndex] = '\\';
buf[++lastSpecialIndex] = replaceChars[(int) lastSpecial];
end++;
for (int i = lastSpecialIndex - 2; i >= start; --i) {
char ch = buf[i];
if (ch <= 13 || ch == '\\' || ch == '\'' //
|| (ch == '/' && isEnabled(SerializerFeature.WriteSlashAsSpecial))) {
System.arraycopy(buf, i + 1, buf, i + 2, end - i - 1);
buf[i] = '\\';
buf[i + 1] = replaceChars[(int) ch];
end++;
}
}
}
buf[count - 1] = '\'';
}
public void writeFieldName(String key) {
writeFieldName(key, false);
}
public void writeFieldName(String key, boolean checkSpecial) {
if (key == null) {
write("null:");
return;
}
if (useSingleQuotes) {
if (quoteFieldNames) {
writeStringWithSingleQuote(key);
write(':');
} else {
writeKeyWithSingleQuoteIfHasSpecial(key);
}
} else {
if (quoteFieldNames) {
writeStringWithDoubleQuote(key, ':');
} else {
boolean hashSpecial = key.length() == 0;
for (int i = 0; i < key.length(); ++i) {
char ch = key.charAt(i);
if (SerializeWriter.isSpecial(ch, 0)) {
hashSpecial = true;
break;
}
}
if (hashSpecial) {
writeStringWithDoubleQuote(key, ':');
} else {
write(key);
write(':');
}
}
}
}
private void writeKeyWithSingleQuoteIfHasSpecial(String text) {
final byte[] specicalFlags_singleQuotes = IOUtils.specicalFlags_singleQuotes;
int len = text.length();
int newcount = count + len + 1;
if (newcount > buf.length) {
if (writer != null) {
if (len == 0) {
write('\'');
write('\'');
write(':');
return;
}
boolean hasSpecial = false;
for (int i = 0; i < len; ++i) {
char ch = text.charAt(i);
if (ch < specicalFlags_singleQuotes.length && specicalFlags_singleQuotes[ch] != 0) {
hasSpecial = true;
break;
}
}
if (hasSpecial) {
write('\'');
}
for (int i = 0; i < len; ++i) {
char ch = text.charAt(i);
if (ch < specicalFlags_singleQuotes.length && specicalFlags_singleQuotes[ch] != 0) {
write('\\');
write(replaceChars[(int) ch]);
} else {
write(ch);
}
}
if (hasSpecial) {
write('\'');
}
write(':');
return;
}
expandCapacity(newcount);
}
if (len == 0) {
int newCount = count + 3;
if (newCount > buf.length) {
expandCapacity(count + 3);
}
buf[count++] = '\'';
buf[count++] = '\'';
buf[count++] = ':';
return;
}
int start = count;
int end = start + len;
text.getChars(0, len, buf, start);
count = newcount;
boolean hasSpecial = false;
for (int i = start; i < end; ++i) {
char ch = buf[i];
if (ch < specicalFlags_singleQuotes.length && specicalFlags_singleQuotes[ch] != 0) {
if (!hasSpecial) {
newcount += 3;
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
System.arraycopy(buf, i + 1, buf, i + 3, end - i - 1);
System.arraycopy(buf, 0, buf, 1, i);
buf[start] = '\'';
buf[++i] = '\\';
buf[++i] = replaceChars[(int) ch];
end += 2;
buf[count - 2] = '\'';
hasSpecial = true;
} else {
newcount++;
if (newcount > buf.length) {
expandCapacity(newcount);
}
count = newcount;
System.arraycopy(buf, i + 1, buf, i + 2, end - i);
buf[i] = '\\';
buf[++i] = replaceChars[(int) ch];
end++;
}
}
}
buf[newcount - 1] = ':';
}
public void flush() {
if (writer == null) {
return;
}
try {
writer.write(buf, 0, count);
writer.flush();
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
count = 0;
}
}