11

我创建了一个可以使用 Goggle Goggles 识别某些图像的测试应用程序。它对我有用,但我收到 binaryt protobuf 响应。我没有原始文件,只有二进制响应。如何从中获取数据?(已经发送了一些带有熊瓶的图片并得到了下一个回复):

A
TuborgLogo9 HoaniText���;�)b���2d8e991bff16229f6"�
+TR=T=AQBd6Cl4Kd8:X=OqSEi:S=_rSozFBgfKt5d9b0
+TR=T=6rLQxKE2xdA:X=OqSEi:S=gd6Aqb28X0ltBU9V
+TR=T=uGPf9zJDWe0:X=OqSEi:S=32zTfdIOdI6kuUTa
+TR=T=RLkVoGVd92I:X=OqSEi:S=P7yOhvSAOQW6SRHN
+TR=T=J1FMvNmcyMk:X=OqSEi:S=5Z631_rd2ijo_iuf�

需要得到字符串“Tuborg”,如果可能的话输入 - “Logo”

4

3 回答 3

19

您可以使用以下代码进行解码protoc

protoc --decode_raw < msg.bin
于 2015-03-03T08:07:01.097 回答
7
UnknownFieldSet.parseFrom(msg).toString()

这将向您显示顶级字段。不幸的是,它无法知道字段类型的确切细节。long/int/bool/enum 等都被编码为 Varint 并且看起来都一样。字符串、字节数组和子消息是有长度分隔的,也无法区分。

这里有一些有用的细节:https ://github.com/dcodeIO/protobuf.js/wiki/How-to-reverse-engineer-a-buffer-by-hand

如果您遵循 UnknownFieldSet.mergeFrom() 中的代码,您将看到如何尝试解码子消息并在失败时回退到字符串 - 但它不会非常可靠。

协议中的线型有 2 个备用值 - 如果 google 使用其中一个来表示子消息,那将非常有帮助。(另一个可能是空值。)

这是一些非常粗糙的匆忙代码,它试图产生对诊断有用的东西。它猜测数据类型,在字符串和子消息的情况下,它会在某些情况下打印两种选择。请不要相信它打印的任何值:

public static String decodeProto(byte[] data, boolean singleLine) throws IOException {
    return decodeProto(ByteString.copyFrom(data), 0, singleLine);
}

public static String decodeProto(ByteString data, int depth, boolean singleLine) throws IOException {
    final CodedInputStream input = CodedInputStream.newInstance(data.asReadOnlyByteBuffer());
    return decodeProtoInput(input, depth, singleLine);
}

private static String decodeProtoInput(CodedInputStream input, int depth, boolean singleLine) throws IOException {
    StringBuilder s = new StringBuilder("{ ");
    boolean foundFields = false;
    while (true) {
        final int tag = input.readTag();
        int type = WireFormat.getTagWireType(tag);
        if (tag == 0 || type == WireFormat.WIRETYPE_END_GROUP) {
            break;
        }
        foundFields = true;
        protoNewline(depth, s, singleLine);

        final int number = WireFormat.getTagFieldNumber(tag);
        s.append(number).append(": ");

        switch (type) {
            case WireFormat.WIRETYPE_VARINT:
                s.append(input.readInt64());
                break;
            case WireFormat.WIRETYPE_FIXED64:
                s.append(Double.longBitsToDouble(input.readFixed64()));
                break;
            case WireFormat.WIRETYPE_LENGTH_DELIMITED:
                ByteString data = input.readBytes();
                try {
                    String submessage = decodeProto(data, depth + 1, singleLine);
                    if (data.size() < 30) {
                        boolean probablyString = true;
                        String str = new String(data.toByteArray(), Charsets.UTF_8);
                        for (char c : str.toCharArray()) {
                            if (c < '\n') {
                                probablyString = false;
                                break;
                            }
                        }
                        if (probablyString) {
                            s.append("\"").append(str).append("\" ");
                        }
                    }
                    s.append(submessage);
                } catch (IOException e) {
                    s.append('"').append(new String(data.toByteArray())).append('"');
                }
            break;
            case WireFormat.WIRETYPE_START_GROUP:
                s.append(decodeProtoInput(input, depth + 1, singleLine));
                break;
            case WireFormat.WIRETYPE_FIXED32:
                s.append(Float.intBitsToFloat(input.readFixed32()));
                break;
            default:
                throw new InvalidProtocolBufferException("Invalid wire type");
        }

    }
    if (foundFields) {
        protoNewline(depth - 1, s, singleLine);
    }
    return s.append('}').toString();
}

private static void protoNewline(int depth, StringBuilder s, boolean noNewline) {
    if (noNewline) {
        s.append(" ");
        return;
    }
    s.append('\n');
    for (int i = 0; i <= depth; i++) {
        s.append(INDENT);
    }
}
于 2018-02-19T14:25:51.577 回答
4

我将假设真正的问题是如何解码 protobuf,而不是如何使用 Java 从网络中读取二进制文件。

您的问题的答案可以在这里找到

简而言之,在网络上,protobuf 被编码为 的 3 元组<key,type,value>,其中:

  • 键是分配给.proto架构中字段的字段编号
  • 类型是 之一<Varint, int32, length-delimited, start-group, end-group,int64。它包含足够的信息来解码 3 元组的值,即它告诉您该值有多长。
于 2012-04-20T21:03:34.407 回答