/*
Исходный код среды исполнения ПВТ-ОО.
Этот исходный код является частью проекта ПВТ-ОО.
Copyright © 2021 Малик Разработчик
Это свободная программа: вы можете перераспространять её и/или
изменять её на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она может быть полезна,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<http://www.gnu.org/licenses/>.
*/
package avt.io.charset.unicode;
import avt.io.*;
import avt.io.charset.*;
import avt.io.charset.rtlang.*;
public final class UTF8(Charset)
{
public (): super("UTF-8", new String[] { "UTF8", "UTF" }) { }
public CharDecoder newDecoder() { return new UTF8Decoder(this); }
public CharEncoder newEncoder() { return new UTF8Encoder(this); }
}
final class UTF8Decoder(CharDecoder)
{
private int fldBytesReaded;
private int fldByte0Value;
private int fldByte1Value;
public (Charset charset): super(charset) { }
protected void decode(ByteReader src, int length, CharWriter dst) throws CharacterDecodingException, IOException {
while(length-- > 0)
{
int b = src.read();
if(b < 0 || b > 0xff) break;
switch(b >> 4)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
writeChar(dst);
dst.write(b);
continue;
case 0x0c:
case 0x0d:
case 0x0e:
writeChar(dst);
fldByte0Value = b;
fldBytesReaded = 1;
continue;
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
switch(fldBytesReaded)
{
case 1:
if((fldByte0Value >> 4) != 0x0e)
{
writeChar(dst, b);
continue;
}
fldByte1Value = b;
fldBytesReaded = 2;
continue;
case 2:
if((fldByte0Value >> 4) == 0x0e)
{
writeChar(dst, b);
continue;
}
}
}
writeChar(dst);
ErrorAction action = errorAction;
if(action == ErrorAction.exception)
{
throw new EightBitCharsetCharacterDecodingException("ошибка декодирования байта") { byteData = b, charset = charset };
}
if(action == ErrorAction.ignore)
{
continue;
}
if(action == ErrorAction.report)
{
report();
break;
}
dst.write(0x003f);
break;
}
}
private void writeChar(CharWriter dst) throws IOException {
int b0 = 0;
int b1 = 0;
switch(fldBytesReaded)
{
case 2:
b1 = fldByte1Value;
/* fall through */
case 1:
b0 = fldByte0Value;
fldBytesReaded = 0;
break;
default:
return;
}
switch(b0 >> 4)
{
case 0x0c:
case 0x0d:
dst.write((b0 & 0x1f) << 6 | (b1 & 0x3f));
break;
case 0x0e:
dst.write((b0 & 0x0f) << 12 | (b1 & 0x3f) << 6);
}
}
private void writeChar(CharWriter dst, int lastByteValue) throws IOException {
int b0 = 0;
int b1 = 0;
int b2 = 0;
switch(fldBytesReaded)
{
case 2:
b0 = fldByte0Value;
b1 = fldByte1Value;
b2 = lastByteValue;
fldBytesReaded = 0;
break;
case 1:
b0 = fldByte0Value;
b1 = lastByteValue;
fldBytesReaded = 0;
break;
default:
return;
}
switch(b0 >> 4)
{
case 0x0c:
case 0x0d:
dst.write((b0 & 0x1f) << 6 | (b1 & 0x3f));
break;
case 0x0e:
dst.write((b0 & 0x0f) << 12 | (b1 & 0x3f) << 6 | (b2 & 0x3f));
}
}
}
final class UTF8Encoder(CharEncoder)
{
public (Charset charset): super(charset) { }
protected void encode(CharReader src, int length, ByteWriter dst) throws IOException {
while(length-- > 0)
{
int c = src.read();
if(c < 0 || c > 0xffff) break;
if(c > 0x0000 && c < 0x0080)
{
dst.write(c);
continue;
}
if(c < 0x0800)
{
dst.write(0xc0 | (c >> 6) & 0x1f);
dst.write(0x80 | c & 0x3f);
continue;
}
dst.write(0xe0 | (c >> 12) & 0x0f);
dst.write(0x80 | (c >> 6) & 0x3f);
dst.write(0x80 | c & 0x3f);
}
}
}