zhangnaisong
2023-08-05 24d66c8d82b628a06e93dbb1abfea2049b3d45ab
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
'use strict';
 
var GetIntrinsic = require('get-intrinsic');
var callBound = require('call-bind/callBound');
 
var $pow = GetIntrinsic('%Math.pow%');
var $RangeError = GetIntrinsic('%RangeError%');
var $TypeError = GetIntrinsic('%TypeError%');
 
var $charAt = callBound('String.prototype.charAt');
var $reverse = callBound('Array.prototype.reverse');
var $slice = callBound('Array.prototype.slice');
 
var hasOwnProperty = require('./HasOwnProperty');
var IsArray = require('./IsArray');
var Type = require('./Type');
 
var every = require('../helpers/every');
var isByteValue = require('../helpers/isByteValue');
 
var keys = require('object-keys');
 
// https://262.ecma-international.org/8.0/#table-50
var TypeToSizes = {
    __proto__: null,
    Int8: 1,
    Uint8: 1,
    Uint8C: 1,
    Int16: 2,
    Uint16: 2,
    Int32: 4,
    Uint32: 4,
    Float32: 4,
    Float64: 8
};
 
// https://262.ecma-international.org/8.0/#sec-rawbytestonumber
 
module.exports = function RawBytesToNumber(type, rawBytes, isLittleEndian) {
    if (typeof type !== 'string' || !hasOwnProperty(TypeToSizes, type)) {
        throw new $TypeError('Assertion failed: `type` must be a TypedArray element type: ' + keys(TypeToSizes));
    }
    if (!IsArray(rawBytes) || !every(rawBytes, isByteValue)) {
        throw new $TypeError('Assertion failed: `rawBytes` must be an Array of bytes');
    }
    if (Type(isLittleEndian) !== 'Boolean') {
        throw new $TypeError('Assertion failed: `isLittleEndian` must be a Boolean');
    }
 
    var elementSize = TypeToSizes[type]; // step 1
 
    if (rawBytes.length !== elementSize) {
        // this assertion is not in the spec, but it'd be an editorial error if it were ever violated
        throw new $RangeError('Assertion failed: `rawBytes` must have a length of ' + elementSize + ' for type ' + type);
    }
 
    // eslint-disable-next-line no-param-reassign
    rawBytes = $slice(rawBytes, 0, elementSize);
    if (!isLittleEndian) {
        // eslint-disable-next-line no-param-reassign
        rawBytes = $reverse(rawBytes); // step 2
    }
 
    /* eslint no-redeclare: 1 */
    if (type === 'Float32') { // step 3
        /*
        Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2008 binary32 value.
If value is an IEEE 754-2008 binary32 NaN value, return the NaN Number value.
Return the Number value that corresponds to value.
        */
        var sign = (rawBytes[3] & 0x80) >> 7; // first bit
        var exponent = ((rawBytes[3] & 0x7F) << 1) // 7 bits from index 3
            | ((rawBytes[2] & 0x80) >> 7); // 1 bit from index 2
        var mantissa = ((rawBytes[2] & 0x7F) << 16) // 7 bits from index 2
            | (rawBytes[1] << 8) // 8 bits from index 1
            | rawBytes[0]; // 8 bits from index 0
 
        if (exponent === 0 && mantissa === 0) {
            return sign === 0 ? 0 : -0;
        }
        if (exponent === 0xFF && mantissa === 0) {
            return sign === 0 ? Infinity : -Infinity;
        }
        if (exponent === 0xFF && mantissa !== 0) {
            return NaN;
        }
 
        exponent -= 127; // subtract the bias
 
        // return $pow(-1, sign) * mantissa / $pow(2, 23) * $pow(2, exponent);
        // return $pow(-1, sign) * (mantissa + 0x1000000) * $pow(2, exponent - 23);
        return $pow(-1, sign) * (1 + (mantissa / $pow(2, 23))) * $pow(2, exponent);
    }
 
    if (type === 'Float64') { // step 4
        /*
        Let value be the byte elements of rawBytes concatenated and interpreted as a little-endian bit string encoding of an IEEE 754-2008 binary64 value.
If value is an IEEE 754-2008 binary64 NaN value, return the NaN Number value.
Return the Number value that corresponds to value.
        */
        var sign = rawBytes[7] & 0x80 ? -1 : 1; // first bit
        var exponent = ((rawBytes[7] & 0x7F) << 4) // 7 bits from index 7
            | ((rawBytes[6] & 0xF0) >> 4); // 4 bits from index 6
        var mantissa = ((rawBytes[6] & 0x0F) * 0x1000000000000) // 4 bits from index 6
            + (rawBytes[5] * 0x10000000000) // 8 bits from index 5
            + (rawBytes[4] * 0x100000000) // 8 bits from index 4
            + (rawBytes[3] * 0x1000000) // 8 bits from index 3
            + (rawBytes[2] * 0x10000) // 8 bits from index 2
            + (rawBytes[1] * 0x100) // 8 bits from index 1
            + rawBytes[0]; // 8 bits from index 0
 
        if (exponent === 0 && mantissa === 0) {
            return sign * 0;
        }
        if (exponent === 0x7FF && mantissa !== 0) {
            return NaN;
        }
        if (exponent === 0x7FF && mantissa === 0) {
            return sign * Infinity;
        }
 
        exponent -= 1023; // subtract the bias
 
        return sign * (mantissa + 0x10000000000000) * $pow(2, exponent - 52);
    }
 
    // this is common to both branches
    var intValue = 0;
    for (var i = 0; i < rawBytes.length; i++) {
        intValue |= rawBytes[i] << (8 * i);
    }
    /*
    Let intValue be the byte elements of rawBytes concatenated and interpreted as a bit string encoding of an unsigned little-endian binary number.
    */
 
    if ($charAt(type, 0) !== 'U') { // steps 5-6
        // Let intValue be the byte elements of rawBytes concatenated and interpreted as a bit string encoding of a binary little-endian 2's complement number of bit length elementSize × 8.
        var bitLength = elementSize * 8;
        if (bitLength < 32) {
            intValue = (intValue << (32 - bitLength)) >> (32 - bitLength);
        }
    }
 
    return intValue; // step 7
};