6dd1b06886
* gnu/gcj/convert/Input_UTF8.java (read): Fixed handling of surrogate characters. * gnu/gcj/convert/Output_UTF8.java (standardUTF8): Default to true. (write): Correct handling of surrogate characters. From-SVN: r35569
115 lines
3.2 KiB
Java
115 lines
3.2 KiB
Java
/* Copyright (C) 1999, 2000 Free Software Foundation
|
|
|
|
This file is part of libgcj.
|
|
|
|
This software is copyrighted work licensed under the terms of the
|
|
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|
details. */
|
|
|
|
package gnu.gcj.convert;
|
|
|
|
/**
|
|
* Convert UTF8 to Unicode.
|
|
* @author Per Bothner <bothner@cygnus.com>
|
|
* @date March 1999.
|
|
*/
|
|
|
|
public class Input_UTF8 extends BytesToUnicode
|
|
{
|
|
public String getName() { return "UTF8"; }
|
|
|
|
int partial = 0;
|
|
int partial_bytes_expected = 0;
|
|
//int suggogate_second = -1;
|
|
|
|
public int read (char[] outbuffer, int outpos, int count)
|
|
{
|
|
int origpos = outpos;
|
|
for (;;)
|
|
{
|
|
if (outpos - origpos >= count)
|
|
break;
|
|
if (inpos >= inlength)
|
|
break;
|
|
int b = inbuffer[inpos++];
|
|
if (b >= 0)
|
|
outbuffer[outpos++] = (char) b;
|
|
else
|
|
{
|
|
if ((b & 0xC0) == 0x80) // Continuation byte
|
|
{
|
|
partial = (partial << 6) | (b & 0x3F);
|
|
--partial_bytes_expected;
|
|
if (partial_bytes_expected == 1)
|
|
{
|
|
if (partial > (0xFFFF>>6))
|
|
{
|
|
// The next continuation byte will cause the result
|
|
// to exceed 0xFFFF, so we must use a surrogate pair.
|
|
// The "Unicode scalar value" (see D28 in section 3.7
|
|
// of the Unicode Standard 2.0) is defined as:
|
|
// value == (hi-0xD800)*0x400+(lo-0xDC00)+0x10000,
|
|
// where (hi, lo) is the Unicode surrogate pair.
|
|
// After reading the first three bytes, we have:
|
|
// partial == (value >> 6).
|
|
// Substituting and simplifying, we get:
|
|
// partial == (hi-0xD800)*0x10+((lo-0xDC00)>>6)+0x400.
|
|
// The definition lo>=0xDC00 && lo<=0xDFFF implies
|
|
// that (lo-0xDC00)>>6 is in the range 0..15.
|
|
// Hence we can solve for `hi' and we can emit
|
|
// the high-surrogate without waiting for the
|
|
// final byte:
|
|
outbuffer[outpos++]
|
|
= (char) (0xD800 + ((partial - 0x400) >> 4));
|
|
|
|
// Now we want to set it up so that when we read
|
|
// the final byte on the next iteration, we will
|
|
// get the low-surrogate without special handling.
|
|
// I.e. we want:
|
|
// lo == (next_partial << 6) | (next & 0x3F)
|
|
// where next is the next input byte and next_partial
|
|
// is the value of partial at the end of this
|
|
// iteration. This implies: next_partial == lo >> 6.
|
|
// We can simplify the previous:
|
|
// partial == (hi-0xD800)*0x10+((lo-0xDC00)>>6)+0x400,
|
|
// to: partial == (hi-0xD800)*0x10+(lo>>6)+0x90.
|
|
// Inserting the values of hi and next_partial,
|
|
// and simplifying, we get: partial ==
|
|
// ( (partial-0x400)&~0xF) + next_partial + 0x90.
|
|
// Solving for next_partial, we get:
|
|
// next_partial = partial+0x400-0x90-(partial&~0xF):
|
|
// or: next_partial = (partial&0xF) + 0x370. Hence:
|
|
partial = (partial & 0xF) + 0x370;
|
|
}
|
|
}
|
|
else if (partial_bytes_expected == 0)
|
|
{
|
|
outbuffer[outpos++] = (char) partial;
|
|
partial = 0;
|
|
partial_bytes_expected = 0;
|
|
}
|
|
}
|
|
else // prefix byte
|
|
{
|
|
if ((b & 0xE0) == 0xC0)
|
|
{
|
|
partial = b & 0x1F;
|
|
partial_bytes_expected = 1;
|
|
}
|
|
else if ((b & 0xF0) == 0xE0)
|
|
{
|
|
partial = b & 0xF;
|
|
partial_bytes_expected = 2;
|
|
}
|
|
else
|
|
{
|
|
partial = b & 7;
|
|
partial_bytes_expected = 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return outpos - origpos;
|
|
}
|
|
}
|