我创建了一个可以使用Goggle Goggles识别某些图像的测试应用。它适用于我,但我收到二进制protobuf响应。我没有原型文件,只是二进制响应。我怎样才能从中获取数据? (已经发送了一些熊的图像并得到了nex响应):
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”
答案 0 :(得分:10)
您可以使用protoc
解码:
protoc --decode_raw < msg.bin
答案 1 :(得分:3)
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个备用值 - 如果谷歌使用其中一个来表示子消息,那将非常有用。 (或者另一个可能是null值。)
这里有一些非常粗糙的代码,试图产生一些对诊断有用的东西。它猜测数据类型,在字符串和子消息的情况下,它会在某些情况下打印两种替代方案。请不要相信它打印的任何值:
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);
}
}
答案 2 :(得分:2)
我将假设真正的问题是如何解码protobufs而不是如何使用Java从线路读取二进制文件。
您可以找到问题的答案here
简而言之,在线上,protobufs被编码为&lt; key,type,value&gt;的3元组,其中键是分配给.proto模式中的字段的字段编号。该类型是&lt; Varint,int32,length-delimited,start-group,end-group,int64&gt;之一。它包含足够的信息来解码3元组的值,即它告诉你这个值有多长。