protobuf解析

package protobuf;

import com.google.protobuf.ByteString;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.WireFormat;

import javax.xml.bind.DatatypeConverter;
import java.io.IOException;

public class Test {
    public static void main(String[] args) throws IOException {
        String str1 = "0A094A7842726F777365721206372E31322E321A480A4631424E444846534331465A5A3139574C494A573734514D394F4552445631435A324235344E4C514430534D4A56544C46554650354A37385644354750574F454435343836314A2281016A6176612E6C616E672E5468726561640D0A636F6D2E7465616D6465762E6A7862726F777365722E656E67696E652E696E7465726E616C2E456E67696E65496D706C0D0A636F6D2E7465616D6465762E6A7862726F777365722E656E67696E652E456E67696E650D0A636F6D2E6A782E746573742E48656C6C6F576F726C640D0A";
        byte[] bb = DatatypeConverter.parseHexBinary(str1);
        read(bb, null);
    }

    public static boolean read(byte[] data, String pre) throws IOException {
        if (pre == null) {
            System.out.println("[");
            pre = "\t";
        } else {
            pre = pre + "\t";
        }
        CodedInputStream cism = CodedInputStream.newInstance(data);
        while (!cism.isAtEnd()) {
            int tag = cism.readTag();
            int type = WireFormat.getTagWireType(tag);
            int number = WireFormat.getTagFieldNumber(tag);
            switch (type) {
                //int32, int64, uint32, uint64, sint32, sint64, bool, enum
                //對應java(boolean int long enum)
                case WireFormat.WIRETYPE_VARINT:
                    //按最大精確度讀取無符號數值
                    System.out.print(pre + number + ":");
                    System.out.println(cism.readUInt64());
                    break;
                //fixed64, sfixed64, double
                //對應java(long double)
                case WireFormat.WIRETYPE_FIXED64:
                    //按最大精確度讀取無符號數值,默認不按double讀取,fixed64和sfixed64爲8位,double爲不定長
                    long fixed = cism.readFixed64();
                    if (cism.getTotalBytesRead() > 8) {
                        return false;
                    }
                    System.out.print(pre + number + ":");
                    System.out.println(fixed);
                    break;
                //string, bytes, embedded messages, packed repeated
                //對應java(string message bytestring)
                case WireFormat.WIRETYPE_LENGTH_DELIMITED://會有個別字符串解析爲protobuf
                    ByteString bs = cism.readBytes();
                    if (isProtobuf(bs.toByteArray())) {//是protobuf協議繼續解析
                        System.out.print(pre + number + "{" + "\n");
                        if (!read(bs.toByteArray(), pre)) {//遞歸解析失敗時按字符串處理
                            System.out.println(pre + bs.toStringUtf8());
                        }
                        System.out.println(pre + "}");
                    } else {//不是protobuf協議則打印輸出
                        if (bs.isValidUtf8()) {//如果爲utf8編碼,按字符串輸出
                            System.out.println(pre + number + ":" + bs.toStringUtf8().replaceAll(new String("\r\n"), "\r\n" + pre));//有換行的時候對齊一下
                        } else {//不是輸出16進制字符串
                            System.out.println(pre + number + ":" + util.buf_to_string(bs.toByteArray()));
                        }
                    }
                    break;
                //groups (deprecated)
                //對應java(message),類型已經過時,出現有問題
                case WireFormat.WIRETYPE_START_GROUP:
                    return false;
                //groups (deprecated)
                //對應java(message),類型已經過時,出現有問題
                case WireFormat.WIRETYPE_END_GROUP:
                    return false;
                //fixed32, sfixed32, float
                //對應java(int float)
                case WireFormat.WIRETYPE_FIXED32:
                    System.out.print(pre + number + ":");
                    System.out.println(cism.readFixed32());
                    break;
                default:
                    System.out.println("------" + type + "------");
                    cism.skipField(tag);
                    break;
            }
        }

        if (pre.equals("\t")) {
            System.out.println("]");
        }
        return true;
    }

    /**
     * 是否爲protobuf數據
     *
     * @param data
     * @return
     */
    public static boolean isProtobuf(byte[] data) {
        CodedInputStream cism = CodedInputStream.newInstance(data);
        try {
            while (!cism.isAtEnd()) {
                int tag = cism.readTag();
                int type = WireFormat.getTagWireType(tag);
                if (tag < 0 || type < 0 || type > 5) {
                    return false;
                }
                cism.skipField(tag);
            }
        } catch (IOException e) {
            return false;
        }
        return true;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章