Passed
Push — master ( 95c2bf...cd3c12 )
by Rafael S.
02:13
created

type.js ➔ ???   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 31
Bugs 14 Features 0
Metric Value
cc 2
c 31
b 14
f 0
nc 2
dl 0
loc 25
rs 8.8571
nop 1
1
/*
2
 * type: The Type class.
3
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
4
 * https://github.com/rochars/byte-data
5
 */
6
7
/** @private */
8
var int8 = new Int8Array(4);
9
/** @private */
10
var i32 = new Int32Array(int8.buffer, 0, 1);
11
/** @private */
12
var f32 = new Float32Array(int8.buffer, 0, 1);
13
14
/** @private */
15
var int8f64 = new Int8Array(8);
16
/** @private */
17
let f64 = new Float64Array(int8f64.buffer);
18
/** @private */
19
let ui32 = new Uint32Array(int8f64.buffer);
20
/** @private */
21
let GenericInteger = require("generic-integer");
22
23
/**
24
 * A class to represent byte-data types.
25
 */
26
class Type extends GenericInteger {
27
28
    /**
29
     * @param {Object} options The type definition.
30
     */
31
    constructor(options) {
32
        super(options["bits"], options["signed"]);
33
        /**
34
         * If this type is a char or not.
35
         * @type {boolean}
36
         */
37
        this.char = options["char"];
38
        /**
39
         * If this type is a floating-point number or not.
40
         * @type {boolean}
41
         */
42
        this.float = options["float"];
43
        /**
44
         * If this type is big-endian or not.
45
         * @type {boolean}
46
         */
47
        this.be = options["be"];
48
        /**
49
         * The base used to represent data of this type.
50
         * Default is 10.
51
         * @type {number}
52
         */
53
        this.base = options["base"] ? options["base"] : 10;
54
        this.buildType_();
55
    }
56
57
    /**
58
     * Read 1 16-bit float from from bytes.
59
     * Thanks https://stackoverflow.com/a/8796597
60
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
61
     * @param {number} i The index to read.
62
     * @return {number}
63
     * @private
64
     */
65
    read16F_(bytes, i) {
66
        let type = new GenericInteger(16);
67
        let int = type.read(bytes, i);
68
        let exponent = (int & 0x7C00) >> 10;
69
        let fraction = int & 0x03FF;
70
        let floatValue;
71
        if (exponent) {
72
            floatValue =  Math.pow(2, exponent - 15) * (1 + fraction / 0x400);
73
        } else {
74
            floatValue = 6.103515625e-5 * (fraction / 0x400);
75
        }
76
        return floatValue * (int >> 15 ? -1 : 1);
77
    }
78
79
    /**
80
     * Read 1 32-bit float from bytes.
81
     * @param {Array<number>|Uint8Array} bytes An array of bytes.
82
     * @param {number} i The index to read.
83
     * @return {number}
84
     * @private
85
     */
86
    read32F_(bytes, i) {
87
        let t = new GenericInteger(32);
0 ignored issues
show
Unused Code introduced by
The variable t seems to be never used. Consider removing it.
Loading history...
88
        i32[0] = this.read(bytes, i);
89
        return f32[0];
90
    }
91
92
    /**
93
     * Read 1 64-bit double from bytes.
94
     * Thanks https://gist.github.com/kg/2192799
95
     * @param {Array<number>|Uint8Array} bytes An array of bytes.
96
     * @param {number} i The index to read.
97
     * @return {number}
98
     * @private
99
     */
100
    read64F_(bytes, i) {
101
        let type32 = new Type({"bits": 32});
102
        ui32[0] = type32.read(bytes, i);
103
        ui32[1] = type32.read(bytes, i + 4);
104
        return f64[0];
105
    }
106
107
    /**
108
     * Read 1 char from bytes.
109
     * @param {!Array<number>|Uint8Array} bytes An array of bytes.
110
     * @param {number} i The index to read.
111
     * @return {string}
112
     * @private
113
     */
114
    readChar_(bytes, i) {
115
        let chrs = "";
116
        for(let j=0; j < this.offset; j++) {
117
            chrs += String.fromCharCode(bytes[i+j]);
118
        }
119
        return chrs;
120
    }
121
122
    /**
123
     * Write one 64-bit float as a binary value.
124
     * @param {!Array<number>} bytes An array of bytes.
125
     * @param {number} number The number to write as bytes.
126
     * @param {number} j The index being written in the byte buffer.
127
     * @return {number} The next index to write on the byte buffer.
128
     * @private
129
     */
130
    write64F_(bytes, number, j) {
131
        f64[0] = number;
132
        let type = new Type({"bits": 32});
133
        j = type.write(bytes, ui32[0], j);
134
        return type.write(bytes, ui32[1], j);
135
    }
136
137
    /**
138
     * Write one 32-bit float as a binary value.
139
     * @param {!Array<number>} bytes An array of bytes.
140
     * @param {number} number The number to write as bytes.
141
     * @param {number} j The index being written in the byte buffer.
142
     * @return {number} The next index to write on the byte buffer.
143
     * @private
144
     */
145
    write32F_(bytes, number, j) {
146
        f32[0] = number;
147
        j = this.write(bytes, i32[0], j);
148
        return j;
149
    }
150
151
    /**
152
     * Write one 16-bit float as a binary value.
153
     * @param {!Array<number>} bytes An array of bytes.
154
     * @param {number} number The number to write as bytes.
155
     * @param {number} j The index being written in the byte buffer.
156
     * @return {number} The next index to write on the byte buffer.
157
     * @private
158
     */
159
    write16F_(bytes, number, j) {
160
        f32[0] = number;
161
        let x = i32[0];
162
        let bits = (x >> 16) & 0x8000;
163
        let m = (x >> 12) & 0x07ff;
164
        let e = (x >> 23) & 0xff;
165
        if (e >= 103) {
166
            bits |= ((e - 112) << 10) | (m >> 1);
167
            bits += m & 1;
168
        }
169
        bytes[j++] = bits & 0xFF;
170
        bytes[j++] = bits >>> 8 & 0xFF;
171
        return j;
172
    }
173
    
174
    /**
175
     * Write one char as a byte.
176
     * @param {!Array<number>} bytes An array of bytes.
177
     * @param {string} string The string to write as bytes.
178
     * @param {number} j The index being written in the byte buffer.
179
     * @return {number} The next index to write on the byte buffer.
180
     * @private
181
     */
182
    writeChar_(bytes, string, j) {
183
        bytes[j++] = string.charCodeAt(0);
184
        return j;
185
    }
186
187
    /**
188
     * Build the type.
189
     * @private
190
     */
191
    buildType_() {
192
        this.setReader_();
193
        this.setWriter_();
194
        if (this.float) {
195
            this.min = -Infinity;
196
            this.max = Infinity;
197
        }
198
    }
199
200
    /**
201
     * Set the function to read data of this type.
202
     * @private
203
     */
204
    setReader_() {
205
        if (this.float) {
206
            if (this.bits == 16) {
207
                this.reader = this.read16F_;
208
            } else if(this.bits == 32) {
209
                this.reader = this.read32F_;
210
            } else if(this.bits == 64) {
211
                this.reader = this.read64F_;
212
            }
213
        } else if (this.char) {
214
            this.reader = this.readChar_;
215
        }
216
    }
217
218
    /**
219
     * Set the function to write data of this type.
220
     * @private
221
     */
222
    setWriter_() {
223
        if (this.float) {
224
            if (this.bits == 16) {
225
                this.writer = this.write16F_;
226
            } else if(this.bits == 32) {
227
                this.writer = this.write32F_;
228
            } else if(this.bits == 64) {
229
                this.writer = this.write64F_;
230
            }
231
        } else if (this.char) {
232
            this.writer = this.writeChar_;
233
        }
234
    }
235
}
236
237
module.exports = Type;
238