CharsetUTF16.java 9.91 KB
/*
 * Decompiled with CFR 0_118.
 */
package com.adobe.agl.charset;

import com.adobe.agl.charset.*;
import com.adobe.agl.text.UTF16;
import com.adobe.agl.text.UnicodeSet;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;

class CharsetUTF16
extends CharsetICU {
    private static final int SIGNATURE_LENGTH = 2;
    private static final byte[] fromUSubstitution_BE = new byte[]{-1, -3};
    private static final byte[] fromUSubstitution_LE = new byte[]{-3, -1};
    private static final byte[] BOM_BE = new byte[]{-2, -1};
    private static final byte[] BOM_LE = new byte[]{-1, -2};
    private static final int ENDIAN_XOR_BE = 0;
    private static final int ENDIAN_XOR_LE = 1;
    private static final int NEED_TO_WRITE_BOM = 1;
    private boolean isEndianSpecified;
    private boolean isBigEndian;
    private int endianXOR;
    private byte[] bom;
    private byte[] fromUSubstitution;

    public CharsetUTF16(String icuCanonicalName, String javaCanonicalName, String[] aliases) {
        super(icuCanonicalName, javaCanonicalName, aliases);
        this.isEndianSpecified = this instanceof CharsetUTF16BE || this instanceof CharsetUTF16LE;
        boolean bl = this.isBigEndian = !(this instanceof CharsetUTF16LE);
        if (this.isBigEndian) {
            this.bom = BOM_BE;
            this.fromUSubstitution = fromUSubstitution_BE;
            this.endianXOR = 0;
        } else {
            this.bom = BOM_LE;
            this.fromUSubstitution = fromUSubstitution_LE;
            this.endianXOR = 1;
        }
        this.maxBytesPerChar = 4;
        this.minBytesPerChar = 2;
        this.maxCharsPerByte = 1.0f;
    }

    public CharsetDecoder newDecoder() {
        return new CharsetDecoderUTF16(this);
    }

    public CharsetEncoder newEncoder() {
        return new CharsetEncoderUTF16(this);
    }

    void getUnicodeSetImpl(UnicodeSet setFillIn, int which) {
        CharsetUTF16.getNonSurrogateUnicodeSet(setFillIn);
    }

    class CharsetEncoderUTF16
    extends CharsetEncoderICU {
        private final byte[] temp;

        public CharsetEncoderUTF16(CharsetICU cs) {
            super(cs, CharsetUTF16.this.fromUSubstitution);
            this.temp = new byte[4];
            this.fromUnicodeStatus = CharsetUTF16.this.isEndianSpecified ? 0 : 1;
        }

        protected void implReset() {
            super.implReset();
            this.fromUnicodeStatus = CharsetUTF16.this.isEndianSpecified ? 0 : 1;
        }

        protected CoderResult encodeLoop(CharBuffer source, ByteBuffer target, IntBuffer offsets, boolean flush) {
            CoderResult cr;
            if (this.fromUnicodeStatus == 1) {
                if (!target.hasRemaining()) {
                    return CoderResult.OVERFLOW;
                }
                this.fromUnicodeStatus = 0;
                cr = CharsetEncoderUTF16.fromUWriteBytes(this, CharsetUTF16.this.bom, 0, CharsetUTF16.this.bom.length, target, offsets, -1);
                if (cr.isOverflow()) {
                    return cr;
                }
            }
            if (this.fromUChar32 != 0) {
                if (!target.hasRemaining()) {
                    return CoderResult.OVERFLOW;
                }
                cr = this.encodeChar(source, target, offsets, (char)this.fromUChar32);
                if (cr != null) {
                    return cr;
                }
            }
            do {
                if (!source.hasRemaining()) {
                    return CoderResult.UNDERFLOW;
                }
                if (target.hasRemaining()) continue;
                return CoderResult.OVERFLOW;
            } while ((cr = this.encodeChar(source, target, offsets, source.get())) == null);
            return cr;
        }

        private final CoderResult encodeChar(CharBuffer source, ByteBuffer target, IntBuffer offsets, char ch) {
            CoderResult cr;
            int sourceIndex = source.position() - 1;
            if (UTF16.isSurrogate(ch)) {
                cr = this.handleSurrogates(source, ch);
                if (cr != null) {
                    return cr;
                }
                char trail = UTF16.getTrailSurrogate(this.fromUChar32);
                this.fromUChar32 = 0;
                this.temp[0 ^ CharsetUTF16.access$400((CharsetUTF16)CharsetUTF16.this)] = (byte)(ch >>> 8);
                this.temp[1 ^ CharsetUTF16.access$400((CharsetUTF16)CharsetUTF16.this)] = (byte)ch;
                this.temp[2 ^ CharsetUTF16.access$400((CharsetUTF16)CharsetUTF16.this)] = (byte)(trail >>> 8);
                this.temp[3 ^ CharsetUTF16.access$400((CharsetUTF16)CharsetUTF16.this)] = (byte)trail;
                cr = CharsetEncoderUTF16.fromUWriteBytes(this, this.temp, 0, 4, target, offsets, sourceIndex);
            } else {
                this.temp[0 ^ CharsetUTF16.access$400((CharsetUTF16)CharsetUTF16.this)] = (byte)(ch >>> 8);
                this.temp[1 ^ CharsetUTF16.access$400((CharsetUTF16)CharsetUTF16.this)] = (byte)ch;
                cr = CharsetEncoderUTF16.fromUWriteBytes(this, this.temp, 0, 2, target, offsets, sourceIndex);
            }
            return cr.isUnderflow() ? null : cr;
        }
    }

    class CharsetDecoderUTF16
    extends CharsetDecoderICU {
        private boolean isBOMReadYet;
        private int actualEndianXOR;
        private byte[] actualBOM;

        public CharsetDecoderUTF16(CharsetICU cs) {
            super(cs);
        }

        protected void implReset() {
            super.implReset();
            this.isBOMReadYet = false;
            this.actualBOM = null;
        }

        protected CoderResult decodeLoop(ByteBuffer source, CharBuffer target, IntBuffer offsets, boolean flush) {
            CoderResult cr;
            CoderResult cr2;
            if (!this.isBOMReadYet) {
                block13 : {
                    do {
                        if (!source.hasRemaining()) {
                            return CoderResult.UNDERFLOW;
                        }
                        this.toUBytesArray[this.toULength++] = source.get();
                        if (this.toULength == 1) {
                            if ((!CharsetUTF16.this.isEndianSpecified || CharsetUTF16.this.isBigEndian) && this.toUBytesArray[this.toULength - 1] == BOM_BE[this.toULength - 1]) {
                                this.actualBOM = BOM_BE;
                                this.actualEndianXOR = 0;
                                continue;
                            }
                            if (!(CharsetUTF16.this.isEndianSpecified && CharsetUTF16.this.isBigEndian || this.toUBytesArray[this.toULength - 1] != BOM_LE[this.toULength - 1])) {
                                this.actualBOM = BOM_LE;
                                this.actualEndianXOR = 1;
                                continue;
                            }
                            this.actualBOM = null;
                            this.actualEndianXOR = CharsetUTF16.this.endianXOR;
                            break block13;
                        }
                        if (this.toUBytesArray[this.toULength - 1] != this.actualBOM[this.toULength - 1]) {
                            this.actualBOM = null;
                            this.actualEndianXOR = CharsetUTF16.this.endianXOR;
                            break block13;
                        }
                        if (this.toULength == 2) break;
                    } while (true);
                    this.toULength = 0;
                }
                this.isBOMReadYet = true;
            }
            if (this.toUnicodeStatus != 0 && (cr2 = this.decodeTrail(source, target, offsets, (char)this.toUnicodeStatus)) != null) {
                return cr2;
            }
            do {
                if (this.toULength < 2) {
                    if (!source.hasRemaining()) {
                        return CoderResult.UNDERFLOW;
                    }
                    this.toUBytesArray[this.toULength++] = source.get();
                    continue;
                }
                if (!target.hasRemaining()) {
                    return CoderResult.OVERFLOW;
                }
                char char16 = (char)((this.toUBytesArray[0 ^ this.actualEndianXOR] & 255) << 8 | this.toUBytesArray[1 ^ this.actualEndianXOR] & 255);
                if (!UTF16.isSurrogate(char16)) {
                    this.toULength = 0;
                    target.put(char16);
                    continue;
                }
                cr = this.decodeTrail(source, target, offsets, char16);
                if (cr != null) break;
            } while (true);
            return cr;
        }

        private final CoderResult decodeTrail(ByteBuffer source, CharBuffer target, IntBuffer offsets, char lead) {
            if (!UTF16.isLeadSurrogate(lead)) {
                this.toUnicodeStatus = 0;
                return CoderResult.malformedForLength(2);
            }
            while (this.toULength < 4) {
                if (!source.hasRemaining()) {
                    this.toUnicodeStatus = lead;
                    return CoderResult.UNDERFLOW;
                }
                this.toUBytesArray[this.toULength++] = source.get();
            }
            char trail = (char)((this.toUBytesArray[2 ^ this.actualEndianXOR] & 255) << 8 | this.toUBytesArray[3 ^ this.actualEndianXOR] & 255);
            if (!UTF16.isTrailSurrogate(trail)) {
                this.toULength = 2;
                source.position(source.position() - 2);
                this.toUnicodeStatus = 0;
                return CoderResult.malformedForLength(2);
            }
            this.toUnicodeStatus = 0;
            this.toULength = 0;
            target.put(lead);
            if (target.hasRemaining()) {
                target.put(trail);
                return null;
            }
            this.charErrorBufferArray[0] = trail;
            this.charErrorBufferLength = 1;
            return CoderResult.OVERFLOW;
        }
    }

}