Passed
Push — master ( a136fe...5c7065 )
by Rafael S.
02:01
created

T_IMPORT   A

Complexity

Total Complexity 34
Complexity/F 2.43

Size

Lines of Code 1
Function Count 14

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 1
noi 0
c 0
b 0
f 0
cc 0
wmc 34
mnd 4
bc 33
fnc 14
rs 9.68
bpm 2.3571
cpm 2.4285
1
/*
2
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview Function to serialize binary data.
27
 * @see https://github.com/rochars/byte-data
28
 */
29
30
import Integer from './integer.js';
31
import endianness from './endianness.js';
32
import {validateType, validateNotUndefined} from './validation.js';
33
34
/**
35
 * @type {!Int8Array}
36
 * @private
37
 */
38
const int8_ = new Int8Array(8);
39
/**
40
 * @type {!Uint32Array}
41
 * @private
42
 */
43
const ui32_ = new Uint32Array(int8_.buffer);
44
/**
45
 * @type {!Float32Array}
46
 * @private
47
 */
48
const f32_ = new Float32Array(int8_.buffer);
49
/**
50
 * @type {!Float64Array}
51
 * @private
52
 */
53
const f64_ = new Float64Array(int8_.buffer);
54
/**
55
 * @type {Function}
56
 * @private
57
 */
58
let reader_;
59
/**
60
 * @type {Function}
61
 * @private
62
 */
63
let writer_;
64
/**
65
 * @type {Object}
66
 * @private
67
 */
68
let gInt_ = {};
69
70
/**
71
 * Validate the type and set up the packing/unpacking functions.
72
 * @param {!Object} theType The type definition.
73
 * @throws {Error} If the type definition is not valid.
74
 * @private
75
 */
76
export function setUp_(theType) {
77
  validateType(theType);
78
  theType.offset = theType.bits < 8 ? 1 : Math.ceil(theType.bits / 8);
79
  theType.be = theType.be || false;
80
  setReader(theType);
81
  setWriter(theType);
82
  gInt_ = new Integer(
83
    theType.bits == 64 ? 32 : theType.bits,
84
    theType.float ? false : theType.signed);
85
}
86
87
/**
88
 * Turn numbers to bytes.
89
 * @param {number} value The value to be packed.
90
 * @param {!Object} theType The type definition.
91
 * @param {!Uint8Array} buffer The buffer to write the bytes to.
92
 * @param {number} index The index to start writing.
93
 * @param {number} len The end index.
94
 * @param {!Function} validate The function used to validate input.
95
 * @param {boolean} be True if big-endian.
96
 * @return {number} the new index to be written.
97
 * @private
98
 */
99
export function writeBytes_(value, theType, buffer, index, len, validate, be) {
100
  while (index < len) {
101
    validate(value, theType);
102
    index = writer_(buffer, value, index);
103
  }
104
  if (be) {
105
    endianness(
106
      buffer, theType.offset, index - theType.offset, index);
107
  }
108
  return index;
109
}
110
111
/**
112
 * Turn a byte buffer into what the bytes represent.
113
 * @param {!Uint8Array} buffer An array of bytes.
114
 * @param {!Object} theType The type definition.
115
 * @return {!Array<number>}
116
 * @private
117
 */
118
export function fromBytes_(buffer, theType) {
119
  if (theType.be) {
120
    endianness(buffer, theType.offset);
121
  }
122
  let len = buffer.length;
123
  let values = [];
124
  len = len - (theType.offset - 1);
125
  for (let i=0; i<len; i+=theType.offset) {
126
    values.push(reader_(buffer, i));
127
  }
128
  return values;
129
}
130
131
/**
132
 * Turn numbers to bytes.
133
 * @param {!Array<number>} values The data.
134
 * @param {!Object} theType The type definition.
135
 * @return {!Array<number>} the data as a byte buffer.
136
 * @private
137
 */
138
export function toBytes_(values, theType) {
139
  let j = 0;
140
  let bytes = [];
141
  let len = values.length;
142
  for(let i=0; i < len; i++) {
143
    validateNotUndefined(values[i]);
144
    j = writer_(bytes, values[i], j);
145
  }
146
  if (theType.be) {
147
    endianness(bytes, theType.offset);
148
  }
149
  return bytes;
150
}
151
152
/**
153
 * Read int values from bytes.
154
 * @param {!Uint8Array} bytes An array of bytes.
155
 * @param {number} i The index to read.
156
 * @return {number}
157
 * @private
158
 */
159
function readInt_(bytes, i) {
160
  return gInt_.read(bytes, i);
161
}
162
163
/**
164
 * Read 1 16-bit float from bytes.
165
 * Thanks https://stackoverflow.com/a/8796597
166
 * @param {!Uint8Array} bytes An array of bytes.
167
 * @param {number} i The index to read.
168
 * @return {number}
169
 * @private
170
 */
171
function read16F_(bytes, i) {
172
  let int = gInt_.read(bytes, i);
173
  let exponent = (int & 0x7C00) >> 10;
174
  let fraction = int & 0x03FF;
175
  let floatValue;
176
  if (exponent) {
177
    floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
178
  } else {
179
    floatValue = 6.103515625e-5 * (fraction / 0x400);
180
  }
181
  return floatValue * (int >> 15 ? -1 : 1);
182
}
183
184
/**
185
 * Read 1 32-bit float from bytes.
186
 * @param {!Uint8Array} bytes An array of bytes.
187
 * @param {number} i The index to read.
188
 * @return {number}
189
 * @private
190
 */
191
function read32F_(bytes, i) {
192
  ui32_[0] = gInt_.read(bytes, i);
193
  return f32_[0];
194
}
195
196
/**
197
 * Read 1 64-bit float from bytes.
198
 * Thanks https://gist.github.com/kg/2192799
199
 * @param {!Uint8Array} bytes An array of bytes.
200
 * @param {number} i The index to read.
201
 * @return {number}
202
 * @private
203
 */
204
function read64F_(bytes, i) {
205
  ui32_[0] = gInt_.read(bytes, i);
206
  ui32_[1] = gInt_.read(bytes, i + 4);
207
  return f64_[0];
208
}
209
210
/**
211
 * Write a integer value to a byte buffer.
212
 * @param {!Uint8Array} bytes An array of bytes.
213
 * @param {number} number The number to write as bytes.
214
 * @param {number} j The index being written in the byte buffer.
215
 * @return {!number} The next index to write on the byte buffer.
216
 * @private
217
 */
218
function writeInt_(bytes, number, j) {
219
  return gInt_.write(bytes, number, j);
220
}
221
222
/**
223
 * Write one 16-bit float as a binary value.
224
 * @param {!Uint8Array} bytes An array of bytes.
225
 * @param {number} number The number to write as bytes.
226
 * @param {number} j The index being written in the byte buffer.
227
 * @return {number} The next index to write on the byte buffer.
228
 * @private
229
 */
230
function write16F_(bytes, number, j) {
231
  f32_[0] = number;
232
  let x = ui32_[0];
233
  let bits = (x >> 16) & 0x8000;
234
  let m = (x >> 12) & 0x07ff;
235
  let e = (x >> 23) & 0xff;
236
  if (e >= 103) {
237
    bits |= ((e - 112) << 10) | (m >> 1);
238
    bits += m & 1;
239
  }
240
  bytes[j++] = bits & 0xFF;
241
  bytes[j++] = bits >>> 8 & 0xFF;
242
  return j;
243
}
244
245
/**
246
 * Write one 32-bit float as a binary value.
247
 * @param {!Uint8Array} bytes An array of bytes.
248
 * @param {number} number The number to write as bytes.
249
 * @param {number} j The index being written in the byte buffer.
250
 * @return {number} The next index to write on the byte buffer.
251
 * @private
252
 */
253
function write32F_(bytes, number, j) {
254
  f32_[0] = number;
255
  return gInt_.write(bytes, ui32_[0], j);
256
}
257
258
/**
259
 * Write one 64-bit float as a binary value.
260
 * @param {!Uint8Array} bytes An array of bytes.
261
 * @param {number} number The number to write as bytes.
262
 * @param {number} j The index being written in the byte buffer.
263
 * @return {number} The next index to write on the byte buffer.
264
 * @private
265
 */
266
function write64F_(bytes, number, j) {
267
  f64_[0] = number;
268
  j = gInt_.write(bytes, ui32_[0], j);
269
  return gInt_.write(bytes, ui32_[1], j);
270
}
271
272
/**
273
 * Set the function to unpack the data.
274
 * @param {!Object} theType The type definition.
275
 * @private
276
 */
277
function setReader(theType) {
278
  if (theType.float) {
279
    if (theType.bits == 16) {
280
      reader_ = read16F_;
281
    } else if(theType.bits == 32) {
282
      reader_ = read32F_;
283
    } else if(theType.bits == 64) {
284
      reader_ = read64F_;
285
    }
286
  } else {
287
    reader_ = readInt_;
288
  }
289
}
290
291
/**
292
 * Set the function to pack the data.
293
 * @param {!Object} theType The type definition.
294
 * @private
295
 */
296
function setWriter(theType) {
297
  if (theType.float) {
298
    if (theType.bits == 16) {
299
      writer_ = write16F_;
300
    } else if(theType.bits == 32) {
301
      writer_ = write32F_;
302
    } else if(theType.bits == 64) {
303
      writer_ = write64F_;
304
    }
305
  } else {
306
    writer_ = writeInt_;
307
  }   
308
}
309
310
export {reader_};
311