package gnu.java.nio.charset;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
/**
* Encoder for UTF-16, UTF-15LE, and UTF-16BE.
*
* @author Jesse Rosenstock
*/
final class UTF_16Encoder extends CharsetEncoder
{
// byte orders
static final int BIG_ENDIAN = 0;
static final int LITTLE_ENDIAN = 1;
private static final char BYTE_ORDER_MARK = '\uFEFF';
private final int byteOrder;
private final boolean useByteOrderMark;
private boolean needsByteOrderMark;
UTF_16Encoder (Charset cs, int byteOrder, boolean useByteOrderMark)
{
super (cs, 2.0f,
useByteOrderMark ? 4.0f : 2.0f,
byteOrder == BIG_ENDIAN
? new byte[] { (byte) 0xFF, (byte) 0xFD }
: new byte[] { (byte) 0xFD, (byte) 0xFF });
this.byteOrder = byteOrder;
this.useByteOrderMark = useByteOrderMark;
this.needsByteOrderMark = useByteOrderMark;
}
protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out)
{
// TODO: Optimize this in the case in.hasArray() / out.hasArray()
if (needsByteOrderMark)
{
if (out.remaining () < 2)
return CoderResult.OVERFLOW;
put (out, BYTE_ORDER_MARK);
needsByteOrderMark = false;
}
int inPos = in.position ();
try
{
while (in.hasRemaining ())
{
char c = in.get ();
if (0xD800 <= c && c <= 0xDFFF)
{
// c is a surrogate
// make sure c is a high surrogate
if (c > 0xDBFF)
return CoderResult.malformedForLength (1);
if (in.remaining () < 1)
return CoderResult.UNDERFLOW;
char d = in.get ();
// make sure d is a low surrogate
if (d < 0xDC00 || d > 0xDFFF)
return CoderResult.malformedForLength (1);
put (out, c);
put (out, d);
inPos += 2;
}
else
{
if (out.remaining () < 2)
return CoderResult.OVERFLOW;
put (out, c);
inPos++;
}
}
return CoderResult.UNDERFLOW;
}
finally
{
in.position (inPos);
}
}
/**
* Writes c
to out
in the byte order
* specified by byteOrder
.
**/
private void put (ByteBuffer out, char c)
{
if (byteOrder == BIG_ENDIAN)
{
out.put ((byte) (c >> 8));
out.put ((byte) (c & 0xFF));
}
else
{
out.put ((byte) (c & 0xFF));
out.put ((byte) (c >> 8));
}
}
protected void implReset ()
{
needsByteOrderMark = useByteOrderMark;
}
// TODO: override canEncode(char) and canEncode(CharSequence)
// for performance
}