Passed
Branch v11-no-dependencies (fcadbf)
by Rafael S.
06:36
created

lib/parsers/binary/index.js   A

Complexity

Total Complexity 19
Complexity/F 1.58

Size

Lines of Code 226
Function Count 12

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 61
dl 0
loc 226
rs 10
c 0
b 0
f 0
wmc 19
mnd 7
bc 7
fnc 12
bpm 0.5833
cpm 1.5833
noi 0

12 Functions

Rating   Name   Duplication   Size   Complexity  
A index.js ➔ getUnpackLen_ 0 5 1
A index.js ➔ unpackString 0 3 1
A index.js ➔ unpack_ 0 7 2
A index.js ➔ copyBuffer_ 0 3 1
A index.js ➔ unpack 0 6 1
A index.js ➔ packTo 0 3 1
A index.js ➔ packArrayTo 0 18 3
A index.js ➔ getParser_ 0 8 3
A index.js ➔ packStringTo 0 3 1
A index.js ➔ packString 0 6 1
A index.js ➔ pack 0 6 1
A index.js ➔ unpackArrayTo 0 20 3
1
/*
2
 * Copyright (c) 2017-2019 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 JavaScript binary parser for any browser or environment.
27
 * @see https://github.com/rochars/byte-data
28
 */
29
30
/** @module byte-data */
31
32
import { endianness } from './lib/endianness';
33
import { pack as packUTF8, unpack as unpackUTF8 } from './lib/utf8-parser';
34
import { IntParser } from './lib/int-parser';
35
import { FloatParser } from './lib/float-parser';
36
37
/**
38
 * Read a string of UTF-8 characters from a byte buffer.
39
 * @param {!(Uint8Array|Array<number>)} buffer A byte buffer.
40
 * @param {number} [index=0] The buffer index to start reading.
41
 * @param {number} [end=buffer.length] The index to stop reading, non inclusive.
42
 * @return {string}
43
 */
44
export function unpackString(buffer, index=0, end=buffer.length) {
45
  return unpackUTF8(buffer, index, end);
46
}
47
48
/**
49
 * Write a string of UTF-8 characters as a byte buffer.
50
 * @param {string} str The string to pack.
51
 * @return {!Array<number>} The UTF-8 string bytes.
52
 * @throws {TypeError} If 'str' is not a string.
53
 */
54
export function packString(str) {
55
  /** @type {!Array<number>} */
56
  let buffer = [];
57
  packUTF8(str, buffer);
58
  return buffer;
59
}
60
61
/**
62
 * Write a string of UTF-8 characters to a byte buffer.
63
 * @param {string} str The string to pack.
64
 * @param {!(Uint8Array|Array<number>)} buffer The output buffer.
65
 * @param {number} [index=0] The buffer index to start writing.
66
 * @return {number} The next index to write in the buffer.
67
 * @throws {TypeError} If 'str' is not a string.
68
 */
69
export function packStringTo(str, buffer, index=0) {
70
  return packUTF8(str, buffer, index);
71
}
72
73
// Numbers
74
/**
75
 * Pack a array of numbers to a byte buffer.
76
 * All other packing functions are interfaces to this function.
77
 * @param {!(Array<number>|TypedArray)} values The values to pack.
78
 * @param {!{bits:number,
79
 *   fp: (boolean|undefined),
80
 *   signed: (boolean|undefined),
81
 *   be: (boolean|undefined)}} theType The type definition.
82
 * @param {!(Uint8Array|Array<number>)} buffer The buffer to write on.
83
 * @param {number} [index=0] The buffer index to start writing.
84
 * @return {number} The next index to write.
85
 * @throws {Error} If the type definition is not valid.
86
 * @throws {RangeError} On overflow if clamp is set to false.
87
 * @throws {TypeError} If 'values' is not a array of numbers.
88
 */
89
export function packArrayTo(values, theType, buffer, index=0) {
90
  theType = theType || {};
91
  /** @type {!Object} */
92
  let packer = getParser_(theType.bits, theType.fp, theType.signed);
93
  /** @type {number} */
94
  let offset = Math.ceil(theType.bits / 8);
95
  /** @type {number} */
96
  let i = 0;
97
  /** @type {number} */
98
  let start = index;
99
  for (let valuesLen = values.length; i < valuesLen; i++) {
100
    index = packer.pack(buffer, values[i], index);
101
  }
102
  if (theType.be) {
103
    endianness(buffer, offset, start, index);
104
  }
105
  return index;
106
}
107
108
/**
109
 * Unpack a array of numbers from a byte buffer to a array or a typed array.
110
 * All other unpacking functions are interfaces to this function.
111
 * @param {!(Uint8Array|Array<number>)} buffer The byte buffer.
112
 * @param {!{bits:number,
113
 *   fp: (boolean|undefined),
114
 *   signed: (boolean|undefined),
115
 *   be: (boolean|undefined)}} theType The type definition.
116
 * @param {!(TypedArray|Array<number>)} output The output array or typed array.
117
 * @param {number} [start=0] The buffer index to start reading.
118
 * @param {number} [end=buffer.length] The buffer index to stop reading.
119
 * @throws {Error} If the type definition is not valid.
120
 */
121
export function unpackArrayTo(
122
    buffer, theType, output, start=0, end=buffer.length) {
123
  theType = theType || {};
124
  /** @type {!Object} */
125
  let parser = getParser_(theType.bits, theType.fp, theType.signed);
126
  // getUnpackLen_ will adjust the end index according to the size
127
  // of the input buffer and the byte offset or throw a error on bad
128
  // end index if safe=true
129
  end = getUnpackLen_(buffer, start, end, parser.offset);
130
  if (theType.be) {
131
    /** @type {!(Uint8Array|Array<number>)} */
132
    let readBuffer = copyBuffer_(buffer);
133
    if (theType.be) {
134
      endianness(readBuffer, parser.offset, start, end);
135
    }
136
    unpack_(readBuffer, output, start, end, parser);
137
  } else {
138
    unpack_(buffer, output, start, end, parser);
139
  }
140
}
141
142
/**
143
 * Pack a number to a byte buffer.
144
 * @param {number} value The value.
145
 * @param {!{bits:number,
146
 *   fp: (boolean|undefined),
147
 *   signed: (boolean|undefined),
148
 *   be: (boolean|undefined)}} theType The type definition.
149
 * @param {!(Uint8Array|Array<number>)} buffer The byte buffer to write on.
150
 * @param {number} [index=0] The buffer index to write.
151
 * @return {number} The next index to write.
152
 * @throws {Error} If the type definition is not valid.
153
 * @throws {RangeError} On overflow if clamp is set to false.
154
 * @throws {TypeError} If 'value' is not a number.
155
 * @throws {TypeError} If 'value' is not a int and type is int.
156
 */
157
export function packTo(value, theType, buffer, index=0) {
158
  return packArrayTo([value], theType, buffer, index);
159
}
160
161
/**
162
 * Pack a number as a array of bytes.
163
 * @param {number} value The number to pack.
164
 * @param {!{bits:number,
165
 *   fp: (boolean|undefined),
166
 *   signed: (boolean|undefined),
167
 *   be: (boolean|undefined)}} theType The type definition.
168
 * @return {!Array<number>} The packed value.
169
 * @throws {Error} If the type definition is not valid.
170
 * @throws {TypeError} If 'value' is not a number.
171
 */
172
export function pack(value, theType) {
173
  /** @type {!Array<number>} */
174
  let output = [];
175
  packTo(value, theType, output, 0);
176
  return output;
177
}
178
179
/**
180
 * Unpack a number from a byte buffer.
181
 * @param {!(Uint8Array|Array<number>)} buffer The byte buffer.
182
 * @param {!{bits:number,
183
 *   fp: (boolean|undefined),
184
 *   signed: (boolean|undefined),
185
 *   be: (boolean|undefined)}} theType The type definition.
186
 * @param {number} [index=0] The buffer index to read.
187
 * @return {number}
188
 * @throws {Error} If the type definition is not valid.
189
 * @throws {Error} On bad input buffer length if on safe mode.
190
 */
191
export function unpack(buffer, theType, index=0) {
192
  let output = [];
193
  unpackArrayTo(buffer, theType, output,
194
    index, index + Math.ceil(theType.bits / 8));
195
  return output[0];
196
}
197
198
/**
199
 * Unpack a array of numbers from a byte buffer to a array or a typed array.
200
 * @param {!(Uint8Array|Array<number>)} buffer The byte buffer.
201
 * @param {!(TypedArray|Array<number>)} output The output array or typed array.
202
 * @param {number} start The buffer index to start reading.
203
 * @param {number} end The buffer index to stop reading.
204
 * @param {!Object} parser The parser.
205
 * @throws {Error} If the type definition is not valid.
206
 * @private
207
 */
208
function unpack_(buffer, output, start, end, parser) {
209
  /** @type {number} */
210
  let offset = parser.offset;
211
  for (let index = 0, j = start; j < end; j += offset, index++) {
212
    output[index] = parser.unpack(buffer, j);
213
  }
214
}
215
216
/**
217
 * Copy a byte buffer as a Array or Uint8Array.
218
 * @param {!(Uint8Array|Array<number>)} buffer The byte buffer.
219
 * @return {!(Uint8Array|Array<number>)}
220
 * @private
221
 */
222
function copyBuffer_(buffer) {
223
  return new Uint8Array(buffer);
224
}
225
226
/**
227
 * Adjust the end index according to the input buffer length and the
228
 * type offset.
229
 * @param {!(Uint8Array|Array<number>)} buffer The byte buffer.
230
 * @param {number} start The buffer index to start reading.
231
 * @param {number} end The buffer index to stop reading.
232
 * @param {number} offset The number of bytes used by the type.
233
 * @throws {Error} On bad buffer length, if safe.
234
 * @private
235
 */
236
function getUnpackLen_(buffer, start, end, offset) {
237
  /** @type {number} */
238
  let extra = (end - start) % offset;
239
  return end - extra;
240
}
241
242
/**
243
 * Return a parser for int, uint or fp numbers.
244
 * @param {number} bits The number of bits.
245
 * @param {boolean|undefined} fp True for fp numbers, false otherwise.
246
 * @param {boolean|undefined} signed True for signed ints, false otherwise.
247
 * @return {!Object}
248
 * @private
249
 */
250
function getParser_(bits, fp, signed) {
251
  if (fp && bits == 32) {
252
    return new FloatParser(8, 23);
253
  } else if(fp && bits == 64) {
254
    return new FloatParser(11, 52);
255
  }
256
  return new IntParser(bits, signed);
257
}
258