Как добавить данные int32 в протокол protobuf JS bytebuffer
Здравствуйте, мастера JavaScript,
Я пытаюсь сгенерировать файл на основе protobuf, используя javascript, который имеет следующую структуру:
messageSize | байты пробаффа | messageSize | байты протобаффа и т. д.
Идея состоит в том, что я добавляю несколько сообщений protobuf в один файл, чтобы потом обработать его, считав размер сообщения (4 байта целое), а затем перестроить сообщение pb, прочитав соответствующие следующие байты, а затем расшифровать каждое сообщение с помощью protobuf.,
У меня уже есть кодирование / декодирование, работающее в Objective-C, но я изо всех сил пытаюсь сделать то же самое с javascript. Поскольку код говорит сам за себя, вот как это делается с Objc (используя модуль '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]
Так просто; Если я открою сгенерированный файл и скажу, что размер первого сообщения протобуфера равен 250, начальные данные в файле будут правильно видны:
Просмотр первых 4 байтов файла (смещение 0) в HEX:
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
Позже я предоставлю данные в виде кнопки загрузки URL:
var data = new Blob([new DataView(byteBuffer.toArrayBuffer())], {type: 'application/octet-stream'});
Из углового:
this.url = ($window.URL || $window.webkitURL).createObjectURL(data);
Когда я открываю загруженный файл для сообщения protobuff длиной 29, первые четыре байта выглядят так:
28 01 38 04
Что совершенно неправильно.
Пройдя немного дальше, я заметил, что protobuf.js использует собственную реализацию ArrayBuffers (называемую ByteBuffer.js), которая, в свою очередь, использует обычные ArrayBuffers при запуске Javascript в браузере. Я, не будучи старшим в JS, может кто-нибудь указать направление для достижения вышеупомянутого? Заранее благодарю за любую помощь.
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());
}
Вот больше документации об этом. Надеюсь, это кому-нибудь поможет.
С наилучшими пожеланиями!