Passed
Push — master ( ea5ece...9c76fd )
by Rafael S.
01:41
created

type.js ➔ ???   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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