Си-подобные структуры. Парсинг пакета, массива байт
Дан дамп некоторого количества пакетов, определённых Си-структурой (порядок байт LE):
typedef struct udpPackage_t { char protocolID[4]; // Всегда одинаковое значение uint32_t uid; int64_t timestamp; float data32[ DATA32_ARRAY_SIZE ]; } udpPackage_t; Задача: распарсить дамп со raw-data на пакеты на JS. Решение на Си простО до безобразия: udpPackage_t *p; p = [адрес начального байта пакета]; p->[имя поля]; // получаем значение пакета.Тут может возникнуть проблема с порядком байт, если этот код будет компилироваться под BE, но это поравлятся одним макросом. В javascript объект fields = { protocolID : '', uid : null, timestamp : null, data32 : new Array(DATA_ARRAY_SIZE) };сам по себе не упакуется. Каждому из полей нужно добавить(привязать) констанстанту LENGTH и OFFSET. Вот что у меня получилось: /** class Packet constructor */ function Packet(data) { /** Parsed fields */ this.fields = { protocolID : '', uid : null, timestamp : null, data32 : new Array(Packet.DATA_ARRAY_SIZE) }; this.parseAllFields(data); } /** Packet fields constants */ Packet.PROTOCOL_ID_OFFSET = 0; Packet.PROTOCOL_ID_LEN = 4; Packet.UID_OFFSET = Packet.PROTOCOL_ID_OFFSET + Packet.PROTOCOL_ID_LEN; Packet.UID_LEN = 4; Packet.TS_OFFSET = Packet.UID_OFFSET + Packet.UID_LEN; Packet.TS_LEN = 8; Packet.DATA32_OFFSET = Packet.TS_OFFSET + Packet.TS_LEN; Packet.DATA32_LEN = 4; Packet.DATA_ARRAY_SIZE = 250; Packet.TOTAL_LEN = Packet.PROTOCOL_ID_LEN + Packet.UID_LEN + Packet.TS_LEN + Packet.DATA32_LEN * Packet.DATA_ARRAY_SIZE; /** Parses all packet fields from this.data */ Packet.prototype.parseAllFields = function (data) { this.fields.protocolID = ''; for (var i=0; i<Packet.PROTOCOL_ID_LEN; i++) { this.fields.protocolID += String.fromCharCode(data[Packet.PROTOCOL_NAME_OFFSET + i]); } this.fields.uid = assembleLittleEndianFromBytesArray(data, Packet.UID_OFFSET, Packet.UID_LEN); this.fields.timestamp = assembleLittleEndianFromBytesArray(data, Packet.TS_OFFSET, Packet.TS_LEN); for (var i=0, len = this.fields.data32.length; i<len; i++) { var temp = assembleLittleEndianFromBytesArray(this.data, Packet.DATA32_OFFSET+i, Packet.DATA32_LEN); this.fields.data32[i] = parseHexFloat(temp); } }; /** Возвращает Number собраный в порядке LE из массива bytes */ function assembleLittleEndianFromBytesArray(bytes, begin, length){}; /** Принимает 32-битное float число IEEE 754 или строку - массив байт. Возвращает js number function parseHexFloat(str);Код громоздкий. Особенно по сравнению с Си. Хотелось бы как-то причесать, структурировать. Например, константы упаковать к полям, чтобы обращаться так: this.fields.uid.offset; this.fields.data32.lenЕсли записать их в конструкторе: /** Parsed fields */ this.fields = { protocolID : { value: '', offset: 0, len: 4 }, ... и т.д. };, но тогда в каждом экземпляре объекте будут соранятся эти "константы". Не годится. Подскажите как оптимизировать код. |
Для работы с raw на js рекомендую смотреть в сторону TypedArray и ArrayBuffer(если не нужна поддердка древних браузеров), с ними удобней.
А конкретно по вопросу - увы не понял что именно нужно. Покажи какая результирующая структура имеется сейчас и какую ты хочешь получить в итоге. |
Цитата:
Цитата:
Цитата:
|
Если эти offset и len уникальны для каждого экземпляра, то зачем их хранить на уровне класса, а если они общие, то в чём смысл выдавать их таким образом?
Проще всего не заворачиваться и добавить отдельно в прототип: Packet.prototype.params = { protocolID : { offset: 0, len: 4 }, ... и т.д. }; Но можно и по извращаться конечно.) |
Цитата:
|
Нет. Каждый экземпляр будет хранить ссылку на общий объект-прототип.
|
Отлично. Erolast, благодарю.
Можно ли определить в объекте поля OFFSET и LEN константами? Не просто "договориться" что мы это не меняем, а как в Java кл. слово final. Ключевое слово const сюда не вписать. |
Цитата:
Object.defineProperty(the_object, property, {...options...}) возможно Вам подойдет что-то вроде: set=function(source, target){ var d=Object.defineProperty for(var i in source) { if(source.hasOwnProperty(i)){ d(target, i, {value: source[i], writable: false}) } } } O=function(){} set({a:1, b:2, c:3}, O.prototype) o=new O alert([o.a, o.b, o.c]) // 1 2 3 o.a=10 o.b=20 o.c=30 alert([o.a, o.b, o.c]) // 1 2 3 |
terminator-101, парниша, используй табуляцию, мерзко же выглядит.
kyb, ответ выше, однако в js константы особого смысла не имеют, только лишние заморочки. |
terminator-101, спасибо. Интересно. Поковырял.
Aetae, теперь согласен. Не стоят константы таких кодовыкрутасов. Однако сишно-джавистская привычка к константам не дает покоя. С другой стороны и ежу понятно что константа. Поменял - сам дурак ) Теперь по теме. Нашел отличный фреймворк для Node node-ctype и просто js-ctypes (c ней не разбирался). Работатет на ура. То что нужно. |
Часовой пояс GMT +3, время: 09:14. |