如何将int32数据附加到protobuf JS bytebuffer消息

时间:2015-07-28 12:20:32

标签: javascript angularjs protocol-buffers arraybuffer

Hello javascript master,

我尝试使用javascript生成基于protobuf的文件,该文件具有以下结构:

messageSize | probuff字节| messageSize | protobuff bytes .. etc

我的想法是,我只在一个文件中附加多个protobuf消息,稍后通过读取消息大小(4个字节整数)来处理它,然后通过读取相应的后续字节来重建pb消息,稍后用protobuf解码每条消息。

我已经在Objective-C中进行了编码/解码,但是我很难用javascript做同样的事情。由于代码不言自明,所以在每次迭代中,它是如何使用Objc(使用pod' ProtocolBuffers','〜> 1.9.8')完成的:

//configure protobuff, then build.
DataOperationPB * dataOp = [dataOperationBuilder build];
//get its NSData representation
NSData * varBlob = [dataOp data]; //byte string

unsigned int size = (unsigned int)[dataOp serializedSize];
[variablesBlobContainer appendData:[NSMutableData dataWithBytes:&size length:sizeof(size)]];
[variablesBlobContainer appendData:varBlob];

//then we can easily write this to a file with: 
[variablesBlobContainer writeToFile:fileNameWithPath atomically:YES]

这么容易;如果我打开生成的文件,并说出第一个protobuffer消息'大小为250,正确显示文件中的初始数据:

在HEX中查看文件的前4个字节(偏移0):

  

FA 00 00 00

和INT(LITTLE ENDIAN):

  

250

按预期工作。如果你对这种语言感觉更舒服(为简洁起见删除了断言),我也可以使用python进行解码:

 file = open(currentPbdFile, 'r')
                    msgSize = file.read(4)
                    msg_len = struct.unpack('<L',msgSize)[0]
                    while msg_len > 0:
                            bufferVar = file.read(msg_len)
                            dataOpList.append(DataOperation(bufferVar))
                            msgSize = file.read(4)

                            if(msgSize == ''):
                                    break
                            msg_len = struct.unpack('<L', msgSize)[0]

现在,当我尝试使用javascript时,我正在努力解决这个问题。我的一次尝试是(使用protobuf.js对消息进行编码):

var ProtoBuf = dcodeIO.ProtoBuf;
var builder = ProtoBuf.loadProtoFile("DataOperationPB.proto");

var ByteBuffer = dcodeIO.ByteBuffer;
var byteBuffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
var data = new DataOperationPB({
                //(omitted code for setting pb message values)
            });

然后在循环中构建消息并附加数据:

byteBuffer.append(new ByteBuffer().writeInt32(data.calculate()));
byteBuffer.append(data.encode()); //the protobuff data itself

稍后我将数据作为网址下载按钮提供:

var data = new Blob([new DataView(byteBuffer.toArrayBuffer())], {type: 'application/octet-stream'});

来自角度:

this.url = ($window.URL || $window.webkitURL).createObjectURL(data);

当我打开下载文件以获取29长度的protobuff消息时,前四个字节如下所示:

  

28 01 38 04

哪个是完全错误的。

进一步挖掘我注意到protobuf.js使用他们自己的ArrayBuffers实现(称为ByteBuffer.js),而后者在浏览器中运行Javascript时会使用正常的ArrayBuffers。我不是JS的高级人员,任何人都可以指出完成上述工作的方向吗?提前感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

回答我自己的问题..图书馆的开发人员让我弄清楚了。

我感觉到的陷阱并没有注意到.toArrayBuffer()方法有效地需要执行读取,并且当从/向切换/读取操作切换时,需要flip(),这里:

//the important, forgotten flip() - 'implicit' read operation:
new Blob([new DataView(byteBuffer.flip().toArrayBuffer())]

此外,直接使用.writeInt32()时,不需要翻转,而附加新创建的byteBuffer需要:

for(...){
    byteBuffer.writeInt32(data.calculate());
    // -- or --
    byteBuffer.append(new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN).writeInt32(data.calculate()).flip());
}

Here是关于它的更多文档。希望这有助于某人。

祝你好运!

相关问题