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