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

import com.adobe.agl.charset.CharsetCallback;
import com.adobe.agl.charset.CharsetICU;
import com.adobe.agl.impl.Assert;

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

public abstract class CharsetDecoderICU
extends CharsetDecoder {
    int toUnicodeStatus;
    byte[] toUBytesArray = new byte[128];
    int toUBytesBegin = 0;
    int toULength;
    char[] charErrorBufferArray = new char[128];
    int charErrorBufferLength;
    int charErrorBufferBegin;
    char[] invalidCharBuffer = new char[128];
    int invalidCharLength;
    private static final int EXT_MAX_BYTES = 31;
    byte[] preToUArray = new byte[31];
    int preToUBegin;
    int preToULength;
    int preToUFirstLength;
    int mode;
    Object toUContext = null;
    private CharsetCallback.Decoder onUnmappableCharacter = CharsetCallback.TO_U_CALLBACK_STOP;
    private CharsetCallback.Decoder onMalformedInput = CharsetCallback.TO_U_CALLBACK_STOP;
    CharsetCallback.Decoder toCharErrorBehaviour;
    private boolean malformedInputCalled;
    private boolean unmappableCharacterCalled;
    private final ByteBuffer EMPTY;

    CharsetDecoderICU(CharsetICU cs) {
        super(cs, 1.0f / cs.maxCharsPerByte, cs.maxCharsPerByte);
        this.toCharErrorBehaviour = new CharsetCallback.Decoder(){

            public CoderResult call(CharsetDecoderICU decoder, Object context, ByteBuffer source, CharBuffer target, IntBuffer offsets, char[] buffer, int length, CoderResult cr) {
                if (cr.isUnmappable()) {
                    return CharsetDecoderICU.this.onUnmappableCharacter.call(decoder, context, source, target, offsets, buffer, length, cr);
                }
                return CharsetDecoderICU.this.onMalformedInput.call(decoder, context, source, target, offsets, buffer, length, cr);
            }
        };
        this.malformedInputCalled = false;
        this.unmappableCharacterCalled = false;
        this.EMPTY = ByteBuffer.allocate(0);
    }

    final boolean isFallbackUsed() {
        return true;
    }

    static final boolean isToUUseFallback() {
        return CharsetDecoderICU.isToUUseFallback(true);
    }

    static final boolean isToUUseFallback(boolean iUseFallback) {
        return true;
    }

    protected final void implOnMalformedInput(CodingErrorAction newAction) {
        if (this.malformedInputCalled) {
            return;
        }
        if (newAction == CodingErrorAction.REPLACE) {
            this.malformedInputCalled = true;
            super.onMalformedInput(CodingErrorAction.IGNORE);
            this.malformedInputCalled = false;
        }
        this.onMalformedInput = CharsetDecoderICU.getCallback(newAction);
    }

    protected final void implOnUnmappableCharacter(CodingErrorAction newAction) {
        if (this.unmappableCharacterCalled) {
            return;
        }
        if (newAction == CodingErrorAction.REPLACE) {
            this.unmappableCharacterCalled = true;
            super.onUnmappableCharacter(CodingErrorAction.IGNORE);
            this.unmappableCharacterCalled = false;
        }
        this.onUnmappableCharacter = CharsetDecoderICU.getCallback(newAction);
    }

    public final void setToUCallback(CoderResult err, CharsetCallback.Decoder newCallback, Object newContext) {
        if (err.isMalformed()) {
            this.onMalformedInput = newCallback;
        } else if (err.isUnmappable()) {
            this.onUnmappableCharacter = newCallback;
        }
        if (this.toUContext == null || !this.toUContext.equals(newContext)) {
            this.toUContext = newContext;
        }
    }

    private static CharsetCallback.Decoder getCallback(CodingErrorAction action) {
        if (action == CodingErrorAction.REPLACE) {
            return CharsetCallback.TO_U_CALLBACK_SUBSTITUTE;
        }
        if (action == CodingErrorAction.IGNORE) {
            return CharsetCallback.TO_U_CALLBACK_SKIP;
        }
        return CharsetCallback.TO_U_CALLBACK_STOP;
    }

    protected final CoderResult implFlush(CharBuffer out) {
        return this.decode(this.EMPTY, out, null, true);
    }

    protected void implReset() {
        this.toUnicodeStatus = 0;
        this.toULength = 0;
        this.charErrorBufferLength = 0;
        this.charErrorBufferBegin = 0;
        this.preToUBegin = 0;
        this.preToULength = 0;
        this.preToUFirstLength = 0;
        this.mode = 0;
    }

    protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
        if (in.remaining() < this.toUCountPending()) {
            return CoderResult.UNDERFLOW;
        }
        in.position(in.position() + this.toUCountPending());
        CoderResult ret = this.decode(in, out, null, false);
        in.position(in.position() - this.toUCountPending());
        return ret;
    }

    abstract CoderResult decodeLoop(ByteBuffer var1, CharBuffer var2, IntBuffer var3, boolean var4);

    final CoderResult decode(ByteBuffer source, CharBuffer target, IntBuffer offsets, boolean flush) {
        if (target == null || source == null) {
            throw new IllegalArgumentException();
        }
        if (this.charErrorBufferLength > 0) {
            int i = 0;
            do {
                if (!target.hasRemaining()) {
                    int j = 0;
                    do {
                        this.charErrorBufferArray[j++] = this.charErrorBufferArray[i++];
                    } while (i < this.charErrorBufferLength);
                    this.charErrorBufferLength = (byte)j;
                    return CoderResult.OVERFLOW;
                }
                target.put(this.charErrorBufferArray[i++]);
                if (offsets == null) continue;
                offsets.put(-1);
            } while (i < this.charErrorBufferLength);
            this.charErrorBufferLength = 0;
        }
        if (!flush && !source.hasRemaining() && this.preToULength >= 0) {
            return CoderResult.UNDERFLOW;
        }
        return this.toUnicodeWithCallback(source, target, offsets, flush);
    }

    /*
     * Unable to fully structure code
     * Enabled aggressive block sorting
     * Lifted jumps to return sites
     */
    final CoderResult toUnicodeWithCallback(ByteBuffer source, CharBuffer target, IntBuffer offsets, boolean flush) {
        s = source.position();
        replayArray = ByteBuffer.allocate(31);
        replayArrayIndex = 0;
        realSource = null;
        realFlush = false;
        realSourceIndex = 0;
        cr = CoderResult.UNDERFLOW;
        sourceIndex = 0;
        if (this.preToULength < 0) {
            realSource = source;
            realFlush = flush;
            realSourceIndex = sourceIndex;
            replayArray.put(this.preToUArray, 0, - this.preToULength);
            source = replayArray;
            source.position(0);
            source.limit(replayArrayIndex - this.preToULength);
            flush = false;
            sourceIndex = -1;
            this.preToULength = 0;
        }
        block0 : do {
            converterSawEndOfInput = (cr = this.decodeLoop(source, target, offsets, flush)).isUnderflow() != false && flush != false && source.remaining() == 0 && this.toULength == 0;
            calledCallback = false;
            errorInputLength = 0;
            do {
                if (this.preToULength < 0) {
                    if (realSource == null) {
                        realSource = source;
                        realFlush = flush;
                        realSourceIndex = sourceIndex;
                        replayArray.put(this.preToUArray, 0, - this.preToULength);
                        source = replayArray;
                        source.limit(replayArrayIndex - this.preToULength);
                        flush = false;
                        if ((sourceIndex += this.preToULength) < 0) {
                            sourceIndex = -1;
                        }
                        this.preToULength = 0;
                    } else {
                        Assert.assrt(realSource == null);
                    }
                }
                s = source.position();
                if (cr.isUnderflow()) {
                    if (s < source.limit()) continue block0;
                    if (realSource != null) {
                        source = realSource;
                        flush = realFlush;
                        sourceIndex = realSourceIndex;
                        realSource = null;
                        continue block0;
                    }
                    if (flush && this.toULength > 0) {
                        cr = CoderResult.malformedForLength(this.toULength);
                        calledCallback = false;
                    } else {
                        if (flush == false) return cr;
                        if (converterSawEndOfInput) ** break;
                        continue block0;
                        this.implReset();
                        return cr;
                    }
                }
                if (calledCallback || cr.isOverflow() || cr.isMalformed() && cr.isUnmappable()) {
                    if (realSource == null) return cr;
                    Assert.assrt(this.preToULength == 0);
                    length = source.limit() - source.position();
                    if (length > 0) {
                        source.get(this.preToUArray, this.preToUBegin, length);
                        this.preToULength = (byte)(- length);
                    }
                    source = realSource;
                    flush = realFlush;
                    return cr;
                }
                this.invalidCharLength = this.toULength;
                errorInputLength = this.invalidCharLength;
                if (errorInputLength > 0) {
                    this.copy(this.toUBytesArray, 0, this.invalidCharBuffer, 0, errorInputLength);
                }
                this.toULength = 0;
                cr = this.toCharErrorBehaviour.call(this, this.toUContext, source, target, offsets, this.invalidCharBuffer, errorInputLength, cr);
                calledCallback = true;
            } while (true);
            break;
        } while (true);
    }

    int toUCountPending() {
        if (this.preToULength > 0) {
            return this.preToULength;
        }
        if (this.preToULength < 0) {
            return - this.preToULength;
        }
        if (this.toULength > 0) {
            return this.toULength;
        }
        return 0;
    }

    private void copy(byte[] src, int srcOffset, char[] dst, int dstOffset, int length) {
        for (int i = srcOffset; i < length; ++i) {
            dst[dstOffset++] = src[srcOffset++];
        }
    }

    static final CoderResult toUWriteUChars(CharsetDecoderICU cnv, char[] ucharsArray, int ucharsBegin, int length, CharBuffer target, IntBuffer offsets, int sourceIndex) {
        CoderResult cr = CoderResult.UNDERFLOW;
        if (offsets == null) {
            while (length > 0 && target.hasRemaining()) {
                target.put(ucharsArray[ucharsBegin++]);
                --length;
            }
        } else {
            while (length > 0 && target.hasRemaining()) {
                target.put(ucharsArray[ucharsBegin++]);
                offsets.put(sourceIndex);
                --length;
            }
        }
        if (length > 0) {
            cnv.charErrorBufferLength = 0;
            cr = CoderResult.OVERFLOW;
            do {
                cnv.charErrorBufferArray[cnv.charErrorBufferLength++] = ucharsArray[ucharsBegin++];
            } while (--length > 0);
        }
        return cr;
    }

}