// 
// Decompiled by Procyon v0.6.0
// 

package ch.randelshofer.fastdoubleparser;

final class Utf8Decoder
{
    private Utf8Decoder() {
    }
    
    static Result decode(final byte[] bytes, final int offset, final int length) {
        final char[] chars = new char[length];
        boolean invalid = false;
        int charIndex = 0;
        final int limit = offset + length;
        int i = offset;
        while (i < limit) {
            final byte b = bytes[i];
            final int opcode = Integer.numberOfLeadingZeros(~b << 24);
            if (i + opcode > limit) {
                throw new NumberFormatException("UTF-8 code point is incomplete");
            }
            switch (opcode) {
                case 0: {
                    chars[charIndex++] = (char)b;
                    ++i;
                    continue;
                }
                case 1: {
                    invalid = true;
                    i = limit;
                    continue;
                }
                case 2: {
                    final int c1 = bytes[i + 1];
                    final int value = (b & 0x1F) << 6 | (c1 & 0x3F);
                    invalid |= (value < 128 | (c1 & 0xC0) != 0x80);
                    chars[charIndex++] = (char)value;
                    i += 2;
                    continue;
                }
                case 3: {
                    final int c1 = bytes[i + 1];
                    final int c2 = bytes[i + 2];
                    final int value = (b & 0xF) << 12 | (c1 & 0x3F) << 6 | (c2 & 0x3F);
                    invalid |= (value < 2048 | (c1 & c2 & 0xC0) != 0x80);
                    chars[charIndex++] = (char)value;
                    i += 3;
                    continue;
                }
                case 4: {
                    final int c1 = bytes[i + 1];
                    final int c2 = bytes[i + 2];
                    final int c3 = bytes[i + 2];
                    final int value = (b & 0x7) << 18 | (c1 & 0x3F) << 12 | (c2 & 0x3F) << 6 | (c3 & 0x3F);
                    chars[charIndex++] = (char)(0xD800 | (value - 65536 >>> 10 & 0x3FF));
                    chars[charIndex++] = (char)(0xDC00 | (value - 65536 & 0x3FF));
                    invalid |= (value < 65536 | (c1 & c2 & c3 & 0xC0) != 0x80);
                    i += 4;
                    continue;
                }
                default: {
                    invalid = true;
                    i = limit;
                    continue;
                }
            }
        }
        if (invalid) {
            throw new NumberFormatException("invalid UTF-8 encoding");
        }
        return new Result(chars, charIndex);
    }
    
    static final class Result
    {
        private final char[] chars;
        private final int length;
        
        Result(final char[] chars, final int length) {
            this.chars = chars;
            this.length = length;
        }
        
        public char[] chars() {
            return this.chars;
        }
        
        public int length() {
            return this.length;
        }
    }
}
