org.asynchttpclient.netty.util.Utf8Reader.java Source code

Java tutorial

Introduction

Here is the source code for org.asynchttpclient.netty.util.Utf8Reader.java

Source

/*
 * Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
 *
 * This program is licensed to you under the Apache License Version 2.0,
 * and you may not use this file except in compliance with the Apache License Version 2.0.
 * You may obtain a copy of the Apache License Version 2.0 at
 *     http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the Apache License Version 2.0 is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
 */
package org.asynchttpclient.netty.util;

import io.netty.buffer.AbstractByteBuf;
import io.netty.buffer.ByteBuf;
import io.netty.util.concurrent.FastThreadLocal;

import java.io.UTFDataFormatException;

public class Utf8Reader {

    private static int SMALL_BUFFER_SIZE = 4096;
    private static final IndexOutOfBoundsException STRING_DECODER_INDEX_OUT_OF_BOUNDS_EXCEPTION = new IndexOutOfBoundsException(
            "String decoder index out of bounds");

    private static final FastThreadLocal<char[]> CACHED_CHAR_BUFFERS = new FastThreadLocal<char[]>() {
        @Override
        protected char[] initialValue() throws Exception {
            return new char[SMALL_BUFFER_SIZE];
        }
    };

    public static String readUtf8(ByteBuf buf, int utflen)
            throws UTFDataFormatException, IndexOutOfBoundsException {

        boolean small = utflen <= SMALL_BUFFER_SIZE;
        char[] chararr = small ? CACHED_CHAR_BUFFERS.get() : new char[utflen];

        int char1, char2, char3;
        int count = 0, chararr_count = 0;

        if (buf.readableBytes() > utflen) {
            throw STRING_DECODER_INDEX_OUT_OF_BOUNDS_EXCEPTION;
        }

        if (buf instanceof AbstractByteBuf) {
            AbstractByteBuf b = (AbstractByteBuf) buf;
            int readerIndex = buf.readerIndex();

            // fast-path
            while (count < utflen) {
                char1 = b.getByte(readerIndex + count) & 0xff;
                if (char1 > 127)
                    break;
                count++;
                chararr[chararr_count++] = (char) char1;
            }

            while (count < utflen) {
                char1 = b.getByte(readerIndex + count) & 0xff;
                switch (char1 >> 4) {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                    /* 0xxxxxxx */
                    count++;
                    chararr[chararr_count++] = (char) char1;
                    break;
                case 12:
                case 13:
                    /* 110x xxxx 10xx xxxx */
                    count += 2;
                    if (count > utflen)
                        throw new UTFDataFormatException("malformed input: partial character at end");
                    char2 = b.getByte(readerIndex + count - 1);
                    if ((char2 & 0xC0) != 0x80)
                        throw new UTFDataFormatException("malformed input around byte " + count);
                    chararr[chararr_count++] = (char) (((char1 & 0x1F) << 6) | (char2 & 0x3F));
                    break;
                case 14:
                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
                    count += 3;
                    if (count > utflen)
                        throw new UTFDataFormatException("malformed input: partial character at end");
                    char2 = b.getByte(readerIndex + count - 2);
                    char3 = b.getByte(readerIndex + count - 1);
                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                        throw new UTFDataFormatException("malformed input around byte " + (count - 1));
                    chararr[chararr_count++] = (char) (((char1 & 0x0F) << 12) | ((char2 & 0x3F) << 6)
                            | ((char3 & 0x3F) << 0));
                    break;
                default:
                    /* 10xx xxxx, 1111 xxxx */
                    throw new UTFDataFormatException("malformed input around byte " + count);
                }
            }

            buf.readerIndex(buf.readerIndex() + count);

            // The number of chars produced may be less than utflen
            return new String(chararr, 0, chararr_count);

        } else {
            byte[] b = new byte[utflen];
            buf.readBytes(b);

            return new String(b);
        }
    }
}