Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Си-подобные структуры. Парсинг пакета, массива байт (https://javascript.ru/forum/misc/50954-si-podobnye-struktury-parsing-paketa-massiva-bajjt.html)

kyb 18.10.2014 16:43

Си-подобные структуры. Парсинг пакета, массива байт
 
Дан дамп некоторого количества пакетов, определённых Си-структурой (порядок байт 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
                },
		... и т.д.
	 };
, но тогда в каждом экземпляре объекте будут соранятся эти "константы". Не годится.
Подскажите как оптимизировать код.

Aetae 18.10.2014 20:50

Для работы с raw на js рекомендую смотреть в сторону TypedArray и ArrayBuffer(если не нужна поддердка древних браузеров), с ними удобней.

А конкретно по вопросу - увы не понял что именно нужно.
Покажи какая результирующая структура имеется сейчас и какую ты хочешь получить в итоге.

kyb 18.10.2014 22:20

Цитата:

Сообщение от Aetae (Сообщение 336379)
увы не понял что именно нужно.
Покажи какая результирующая структура имеется сейчас и какую ты хочешь получить в итоге.

Цитата:

Сообщение от kyb (Сообщение 336361)
, чтобы обращаться так:
this.fields.uid.offset; 
this.fields.data32.len

Но при этом хранить константы на уровне класса, а не в каждом экземпляре.
Цитата:

Сообщение от Aetae (Сообщение 336379)
смотреть в сторону TypedArray и ArrayBuffer

Тема. Это должно решить все вопросы. Переделаю всё на них. Благодарю.

Aetae 18.10.2014 22:56

Если эти offset и len уникальны для каждого экземпляра, то зачем их хранить на уровне класса, а если они общие, то в чём смысл выдавать их таким образом?
Проще всего не заворачиваться и добавить отдельно в прототип:
Packet.prototype.params = {
        protocolID : {
                      offset: 0,
                      len:     4
                },
        ... и т.д.
     };

Но можно и по извращаться конечно.)

kyb 19.10.2014 10:06

Цитата:

Сообщение от Aetae (Сообщение 336404)
добавить отдельно в прототип

Тогда каждый экземпляр будет хранить в памяти общие для класса константы. И при большом количестве экземпляров будет перерасход памяти. Так?

Erolast 19.10.2014 16:58

Нет. Каждый экземпляр будет хранить ссылку на общий объект-прототип.

kyb 20.10.2014 00:25

Отлично. Erolast, благодарю.

Можно ли определить в объекте поля OFFSET и LEN константами? Не просто "договориться" что мы это не меняем, а как в Java кл. слово final. Ключевое слово const сюда не вписать.

terminator-101 20.10.2014 01:54

Цитата:

Сообщение от kyb
Можно ли определить в объекте поля OFFSET и LEN константами? Не просто "договориться" что мы это не меняем,

Есть такая штука:
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

Aetae 20.10.2014 05:06

terminator-101, парниша, используй табуляцию, мерзко же выглядит.

kyb, ответ выше, однако в js константы особого смысла не имеют, только лишние заморочки.

kyb 21.10.2014 23:33

terminator-101, спасибо. Интересно. Поковырял.
Aetae, теперь согласен. Не стоят константы таких кодовыкрутасов.
Однако сишно-джавистская привычка к константам не дает покоя. С другой стороны и ежу понятно что константа. Поменял - сам дурак )

Теперь по теме. Нашел отличный фреймворк для Node node-ctype и просто js-ctypes (c ней не разбирался). Работатет на ура. То что нужно.


Часовой пояс GMT +3, время: 09:14.