package com.alibaba.fastjson.serializer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import com.alibaba.fastjson.JSONException; import com.alibaba.fastjson.util.ThreadLocalCache; public class SerialWriterStringEncoder { private final CharsetEncoder encoder; public SerialWriterStringEncoder(Charset cs) { this(cs.newEncoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE)); } public SerialWriterStringEncoder(CharsetEncoder encoder) { this.encoder = encoder; } public byte[] encode(char[] chars, int off, int len) { if (len == 0) { return new byte[0]; } encoder.reset(); int bytesLength = scale(len, encoder.maxBytesPerChar()); byte[] bytes = ThreadLocalCache.getBytes(bytesLength); return encode(chars, off, len, bytes); } public CharsetEncoder getEncoder() { return encoder; } public byte[] encode(char[] chars, int off, int len, byte[] bytes) { ByteBuffer byteBuf = ByteBuffer.wrap(bytes); CharBuffer charBuf = CharBuffer.wrap(chars, off, len); try { CoderResult cr = encoder.encode(charBuf, byteBuf, true); if (!cr.isUnderflow()) { cr.throwException(); } cr = encoder.flush(byteBuf); if (!cr.isUnderflow()) { cr.throwException(); } } catch (CharacterCodingException x) { // Substitution is always enabled, // so this shouldn't happen throw new JSONException(x.getMessage(), x); } int bytesLength = byteBuf.position(); byte[] copy = new byte[bytesLength]; System.arraycopy(bytes, 0, copy, 0, bytesLength); return copy; } private static int scale(int len, float expansionFactor) { // We need to perform double, not float, arithmetic; otherwise // we lose low order bits when len is larger than 2**24. return (int) (len * (double) expansionFactor); } }