UTF8.avt

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

/*
    Исходный код среды исполнения ПВТ-ОО.

    Этот исходный код является частью проекта ПВТ-ОО.

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