-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnstruct.js
188 lines (182 loc) · 5.63 KB
/
nstruct.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*!
* nstruct JavaScript Library v1.0
* Author: zhaopuyang
* Date: 2019-08-07
* City: Harbin in China
*/
/**
* define basetype and type data length
*/
const type_map = new Map();
type_map.set('UInt8', 1);
type_map.set('UInt16', 2);
type_map.set('UInt32', 4);
type_map.set('Int8', 1);
type_map.set('Int16', 2);
type_map.set('Int32', 4);
type_map.set('Float', 4);
type_map.set('Double', 8);
type_map.set('Char', 1);
/**
*
* @param {*} order (BE:big Endian | LE:little Endian)
*/
function NStruct(order = 'BE') {
this.$order = order;
}
var fn = NStruct.prototype;
/**
* clone object
*/
fn.clone = function (obj) {
var o;
if (typeof obj == "object") {
if (obj === null) {
o = null;
} else {
o = {};
for (var k in obj) {
o[k] = this.clone(obj[k]);
}
}
} else {
o = obj;
}
return o;
}
/**
* verify type in template
*/
fn.verify = function (template) {
if (typeof template !== 'object') {
(/(\w+)(\[(\d+)\])*/g).exec(template);
var type = RegExp.$1;
if (!type_map.has(type)) {
throw new Error('Error type found in template!')
}
return;
}
Object.keys(template).forEach(key => {
if (typeof template[key] !== 'object') {
(/(\w+)(\[(\d+)\])*/g).exec(template[key]);
var type = RegExp.$1;
if (!type_map.has(type)) {
throw new Error('Error type found in template!')
}
} else {
this.verify(template[key]);
}
})
}
/**
* calculate bytes of template
*/
fn.sizeof = function (template) {
this.verify(template);
if (typeof template !== 'object') {
(/(\w+)(\[(\d+)\])*/g).exec(template);
var type = RegExp.$1;
var type_array_len = RegExp.$3;
var size = type_array_len == "" ? type_map.get(type) : type_map.get(type) * parseInt(type_array_len);
return size;
}
template.$size = 0;
for (var key in template) {
if (key == '$size') continue;
if (typeof template[key] !== 'object') {
(/(\w+)(\[(\d+)\])*/g).exec(template[key]);
var type = RegExp.$1;
var type_array_len = RegExp.$3;
if (type_array_len == "") {
template.$size += type_map.get(type);
} else {
template.$size += type_map.get(type) * parseInt(type_array_len);
}
} else {
template.$size += this.sizeof(template[key]);
}
}
var size = template.$size;
delete template.$size;
return size;
}
/**
* calculate field offset in template
*/
fn.offset = function (template, field) {
this.verify(template);
if (typeof template !== 'object') {
throw new Error('template must be an object type!')
}
var index = 0;
for (var key in template) {
if (key === field) break;
index += this.sizeof(template[key]);
}
return index;
}
/**
* convert to struct from buffer
*/
fn.bufferToStruct = function (buffer, template) {
if (this.sizeof(template) > buffer.length) {
throw new Error('buffer is too short!');
}
var struct = this.clone(template);
for (var key in template) {
var start = this.offset(template, key);
var end = start + this.sizeof(template[key]);
var buf_bytes = buffer.slice(start, end);
if (typeof template[key] === 'object') {
struct[key] = this.bufferToStruct(buf_bytes, template[key]);
} else {
(/(\w+)(\[(\d+)\])*/g).exec(template[key]);
var type = RegExp.$1;
var len = RegExp.$3;
var strbyteorder = type_map.get(type) != 1 ? this.$order : '';
if (len == "") {
struct[key] = (type !== 'Char') ? eval('buf_bytes.read' + type + (strbyteorder) + '()') : buf_bytes.toString('ascii');
} else {
struct[key] = [];
len = parseInt(len);
for (var i = 0; i < len; i++) {
(type !== 'Char') ? struct[key].push(eval('buf_bytes.read' + type + (strbyteorder) + '(' + i + ')')): struct[key].push(String.fromCharCode(buf_bytes[i]));
}
}
}
}
return struct;
}
/**
* convert to buffer from struct
*/
fn.structToBuffer = function (struct, template) {
var buffer = Buffer.alloc(this.sizeof(template));
for (var key in template) {
var start = this.offset(template, key);
var end = start + this.sizeof(template[key]);
var subarray_buffer = buffer.subarray(start, end);
if (typeof template[key] === 'object') {
var obj_buffer = this.structToBuffer(struct[key], template[key]);
var index = 0;
for (var value of obj_buffer.values()) {
subarray_buffer[index++] = value;
}
} else {
(/(\w+)(\[(\d+)\])*/g).exec(template[key]);
var type = RegExp.$1;
var len = RegExp.$3;
var strbyteorder = type_map.get(type) != 1 ? this.$order : '';
if (len == "") {
(type !== 'Char') ? eval('subarray_buffer.write' + type + (strbyteorder) + '(' + struct[key] + ')'): subarray_buffer[0] = struct[key].charCodeAt(0);
} else {
len = parseInt(len);
for (var i = 0; i < len; i++) {
(type !== 'Char') ? eval('subarray_buffer.write' + type + (strbyteorder) + '(' + struct[key][i] + ',' + i + ')'): subarray_buffer[i] = struct[key][i].charCodeAt(0);
}
}
}
}
return buffer;
}
module.exports = NStruct