All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dongliu.prettypb.runtime.code.ProtoBufReader Maven / Gradle / Ivy

There is a newer version: 0.3.5
Show newest version
package net.dongliu.prettypb.runtime.code;

import net.dongliu.prettypb.runtime.exception.ProtoDeSerializeException;
import net.dongliu.prettypb.runtime.exception.UnExpectedEOFException;
import net.dongliu.prettypb.runtime.utils.Constant;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;

/**
 * @author Dong Liu
 */
public class ProtoBufReader implements Closeable {
    private final InputStream in;

    public ProtoBufReader(InputStream in) {
        this.in = in;
    }

    private byte readByte() throws IOException {
        int i = in.read();
        if (i == -1) {
            throw new UnExpectedEOFException();
        }
        return (byte) i;
    }


    private void read(byte[] bytes) throws IOException {
        readBytes(bytes, 0, bytes.length);
    }

    private void read(byte[] bytes, int len) throws IOException {
        readBytes(bytes, 0, len);
    }

    private void readBytes(byte[] bytes, int offset, int len) throws IOException {
        int readed = 0;
        while (readed < len) {
            int count = in.read(bytes, offset, len);
            if (count < 0) {
                throw new UnExpectedEOFException();
            }
            len -= count;
            if (len <= 0) {
                return;
            }
            offset += count;
        }
    }


    /**
     * read little endian base128 var int, max 32 bit
     *
     * @return
     */
    public int readVarInt() throws IOException {
        int num = 0;
        for (int i = 0; i < 5; i++) {
            byte b = readByte();
            if ((b & 0x80) == 0) {
                num = num | (b << (i * 7));
                break;
            } else {
                num = num | ((b & 0x7f) << (i * 7));
            }
        }
        return num;
    }

    /**
     * read little endian base128 var int, max 64 bit
     *
     * @return
     */
    public long readVarLong() throws IOException {
        long num = 0;
        for (int i = 0; i < 10; i++) {
            byte b = readByte();
            if ((b & 0x80) == 0) {
                num = num | ((long) b << (i * 7));
                break;
            } else {
                num = num | ((long) (b & 0x7f) << (i * 7));
            }
        }
        return num;
    }

    /**
     * for protobuf sint32 type decode
     *
     * @return
     */
    public int readVarSInt() throws IOException {
        return deZigzag(readVarInt());
    }

    /**
     * for protobuf sint64 type decode
     *
     * @return
     */
    public long readVarSLong() throws IOException {
        return deZigzag(readVarLong());
    }

    protected static int deZigzag(int num) {
        return (num >> 1) ^ (-(num & 1));
    }

    protected static long deZigzag(long num) {
        return (num >> 1) ^ (-(num & 1));
    }

    public int readFixedInt() throws IOException {
        int i = 0;
        i |= readByte() & 0xff;
        i |= (readByte() & 0xff) << 8;
        i |= (readByte() & 0xff) << 16;
        i |= (readByte() & 0xff) << 24;
        return i;
    }

    /**
     * read float.
     *
     * @return
     * @throws IOException
     */
    public float readFloat() throws IOException {
        int i = readFixedInt();
        return Float.intBitsToFloat(i);
    }

    /**
     * read fixed len 64-bit number
     *
     * @return
     * @throws IOException
     */
    public long readFixedLong() throws IOException {
        long l = 0;
        l |= ((long) (readByte() & 0xff));
        l |= ((long) (readByte() & 0xff)) << 8;
        l |= ((long) (readByte() & 0xff)) << 16;
        l |= ((long) (readByte() & 0xff)) << 24;
        l |= ((long) (readByte() & 0xff)) << 32;
        l |= ((long) (readByte() & 0xff)) << 40;
        l |= ((long) (readByte() & 0xff)) << 48;
        l |= ((long) (readByte() & 0xff)) << 56;
        return l;
    }


    /**
     * read double field
     *
     * @return
     * @throws IOException
     */
    public double readDouble() throws IOException {
        long l = readFixedLong();
        return Double.longBitsToDouble(l);
    }

    /**
     * read string field. string is encode as UTF-8 bytes
     *
     * @return
     * @throws IOException
     */
    public String readString() throws IOException {
        int len = readVarInt();
        byte[] bytes = new byte[len];
        read(bytes);
        return new String(bytes, Constant.charset);
    }

    /**
     * read bytes field. the bytes' len is stored in var int
     *
     * @return
     * @throws IOException
     */
    public byte[] readBytes() throws IOException {
        int len = readVarInt();
        byte[] bytes = new byte[len];
        read(bytes);
        return bytes;
    }

    /**
     * decode field tag. field tag is var int composed by wireType and field number
     *
     * @return
     * @throws IOException
     */
    public int[] decodeTag() throws IOException {
        int i;
        try {
            i = readVarInt();
        } catch (UnExpectedEOFException e) {
            return null;
        }
        int wireType = i & 0x7;
        int idx = i >>> 3;
        return new int[]{wireType, idx};
    }

    /**
     * skip one filed. how many bytes skipped is determined by wireType
     *
     * @param wireType
     * @throws IOException
     */
    public void skip(int wireType) throws IOException {
        switch (wireType) {
            case 0:
                // var int. readVarLong can read 32-bit var int or 64-bit var int
                readVarLong();
                break;
            case 1:
                readFixedLong();
                break;
            case 2:
                readBytes();
                break;
            case 3:
            case 4:
                // group
                throw new ProtoDeSerializeException("Group not supported");
            case 5:
                readFixedInt();
                break;
            default:
                throw new ProtoDeSerializeException("unknown wiretype:" + wireType);
        }
    }

    @Override
    public void close() throws IOException {
        this.in.close();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy