Passed
Branch v15.x (2f4a9e)
by Rafael S.
01:34
created

packer.js ➔ setReaderAndWriter_   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 14
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 17
rs 9.7
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 {validateType} from './validation.js';
32
33
export default class Packer {
34
35
  constructor() {
36
    /**
37
     * Use a Typed Array to check if the host is BE or LE. This will impact
38
     * on how 64-bit floating point numbers are handled.
39
     * @type {boolean}
40
     * @private
41
     */
42
    const BE_ENV = new Uint8Array(new Uint32Array([1]).buffer)[0] === 0;
43
    /**
44
     * @type {number}
45
     * @private
46
     */
47
    this.HIGH = BE_ENV ? 1 : 0;
48
    /**
49
     * @type {number}
50
     * @private
51
     */
52
    this.LOW = BE_ENV ? 0 : 1;
53
    /**
54
     * @type {!Int8Array}
55
     * @private
56
     */
57
    let int8_ = new Int8Array(8);
58
    /**
59
     * @type {!Uint32Array}
60
     * @private
61
     */
62
    this.ui32_ = new Uint32Array(int8_.buffer);
63
    /**
64
     * @type {!Float32Array}
65
     * @private
66
     */
67
    this.f32_ = new Float32Array(int8_.buffer);
68
    /**
69
     * @type {!Float64Array}
70
     * @private
71
     */
72
    this.f64_ = new Float64Array(int8_.buffer);
73
    /**
74
     * @type {Object}
75
     * @private
76
     */
77
    this.gInt_ = {};
78
  }
79
80
  /**
81
   * Read a number from a byte buffer.
82
   * @param {!Uint8Array} bytes An array of bytes.
83
   * @param {number} i The index to read.
84
   * @return {number}
85
   */
86
  read(bytes, i) {}
0 ignored issues
show
Unused Code introduced by
The parameter i is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter bytes is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
87
88
  /**
89
   * Write a number to a byte buffer.
90
   * @param {!Uint8Array} bytes An array of bytes.
91
   * @param {number} number The number to write as bytes.
92
   * @param {number} j The index being written in the byte buffer.
93
   * @return {!number} The next index to write on the byte buffer.
94
   */
95
  write(bytes, number, j) {}
0 ignored issues
show
Unused Code introduced by
The parameter j is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter number is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter bytes is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
96
97
  /**
98
   * Validate the type and set up the packing/unpacking functions.
99
   * @param {!Object} theType The type definition.
100
   * @throws {Error} If the type definition is not valid.
101
   */
102
  setUp(theType) {
103
    validateType(theType);
104
    theType.offset = theType.bits < 8 ? 1 : Math.ceil(theType.bits / 8);
105
    this.setReaderAndWriter_(theType);
106
    this.gInt_ = new Integer(
107
      theType.bits == 64 ? 32 : theType.bits,
108
      theType.float ? false : theType.signed);
109
  }
110
111
  /**
112
   * Read int values from bytes.
113
   * @param {!Uint8Array} bytes An array of bytes.
114
   * @param {number} i The index to read.
115
   * @return {number}
116
   * @private
117
   */
118
  readInt_(bytes, i) {
119
    return this.gInt_.read(bytes, i);
120
  }
121
122
  /**
123
   * Read 1 16-bit float from bytes.
124
   * @see https://stackoverflow.com/a/8796597
125
   * @param {!Uint8Array} bytes An array of bytes.
126
   * @param {number} i The index to read.
127
   * @return {number}
128
   * @private
129
   */
130
  read16F_(bytes, i) {
131
    /** @type {number} */
132
    let int = this.gInt_.read(bytes, i);
133
    /** @type {number} */
134
    let exponent = (int & 0x7C00) >> 10;
135
    /** @type {number} */
136
    let fraction = int & 0x03FF;
137
    /** @type {number} */
138
    let floatValue;
139
    if (exponent) {
140
      floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
141
    } else {
142
      floatValue = 6.103515625e-5 * (fraction / 0x400);
143
    }
144
    return floatValue * (int >> 15 ? -1 : 1);
145
  }
146
147
  /**
148
   * Read 1 32-bit float from bytes.
149
   * @param {!Uint8Array} bytes An array of bytes.
150
   * @param {number} i The index to read.
151
   * @return {number}
152
   * @private
153
   */
154
  read32F_(bytes, i) {
155
    this.ui32_[0] = this.gInt_.read(bytes, i);
156
    return this.f32_[0];
157
  }
158
159
  /**
160
   * Read 1 64-bit float from bytes.
161
   * Thanks https://gist.github.com/kg/2192799
162
   * @param {!Uint8Array} bytes An array of bytes.
163
   * @param {number} i The index to read.
164
   * @return {number}
165
   * @private
166
   */
167
  read64F_(bytes, i) {
168
    this.ui32_[this.HIGH] = this.gInt_.read(bytes, i);
169
    this.ui32_[this.LOW] = this.gInt_.read(bytes, i + 4);
170
    return this.f64_[0];
171
  }
172
173
  /**
174
   * Write a integer value to a byte buffer.
175
   * @param {!Uint8Array} bytes An array of bytes.
176
   * @param {number} number The number to write as bytes.
177
   * @param {number} j The index being written in the byte buffer.
178
   * @return {!number} The next index to write on the byte buffer.
179
   * @private
180
   */
181
  writeInt_(bytes, number, j) {
182
    return this.gInt_.write(bytes, number, j);
183
  }
184
185
  /**
186
   * Write one 16-bit float as a binary value.
187
   * @param {!Uint8Array} bytes An array of bytes.
188
   * @param {number} number The number to write as bytes.
189
   * @param {number} j The index being written in the byte buffer.
190
   * @return {number} The next index to write on the byte buffer.
191
   * @private
192
   */
193
  write16F_(bytes, number, j) {
194
    this.f32_[0] = number;
195
    /** @type {number} */
196
    let x = this.ui32_[0];
197
    /** @type {number} */
198
    let bits = (x >> 16) & 0x8000;
199
    /** @type {number} */
200
    let m = (x >> 12) & 0x07ff;
201
    /** @type {number} */
202
    let e = (x >> 23) & 0xff;
203
    if (e >= 103) {
204
      bits |= ((e - 112) << 10) | (m >> 1);
205
      bits += m & 1;
206
    }
207
    bytes[j++] = bits & 0xFF;
208
    bytes[j++] = bits >>> 8 & 0xFF;
209
    return j;
210
  }
211
212
  /**
213
   * Write one 32-bit float as a binary value.
214
   * @param {!Uint8Array} bytes An array of bytes.
215
   * @param {number} number The number to write as bytes.
216
   * @param {number} j The index being written in the byte buffer.
217
   * @return {number} The next index to write on the byte buffer.
218
   * @private
219
   */
220
  write32F_(bytes, number, j) {
221
    this.f32_[0] = number;
222
    return this.gInt_.write(bytes, this.ui32_[0], j);
223
  }
224
225
  /**
226
   * Write one 64-bit float as a binary value.
227
   * @param {!Uint8Array} bytes An array of bytes.
228
   * @param {number} number The number to write as bytes.
229
   * @param {number} j The index being written in the byte buffer.
230
   * @return {number} The next index to write on the byte buffer.
231
   * @private
232
   */
233
  write64F_(bytes, number, j) {
234
    this.f64_[0] = number;
235
    j = this.gInt_.write(bytes, this.ui32_[this.HIGH], j);
236
    return this.gInt_.write(bytes, this.ui32_[this.LOW], j);
237
  }
238
239
  /**
240
   * Set the functions to pack and unpack numbers.
241
   * @param {!Object} theType The type definition.
242
   * @private
243
   */
244
  setReaderAndWriter_(theType) {
245
    if (theType.float) {
246
      if (theType.bits == 16) {
247
        this.read = this.read16F_;
248
        this.write = this.write16F_;
249
      } else if(theType.bits == 32) {
250
        this.read = this.read32F_;
251
        this.write = this.write32F_;
252
      } else {
253
        this.read = this.read64F_;
254
        this.write = this.write64F_;
255
      }
256
    } else {
257
      this.read = this.readInt_;
258
      this.write = this.writeInt_;
259
    }
260
  }
261
262
}
263
264
//export {reader, writer, setUp};
265