UTF8.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Реализация среды исполнения языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    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);
        }
    }
}