126 lines
2.3 KiB
JavaScript
126 lines
2.3 KiB
JavaScript
'use strict';
|
|
|
|
const readDigit = (buffer, index) => {
|
|
const digit = buffer.readUInt16BE(8 + 2 * index);
|
|
|
|
if (digit > 9999) {
|
|
throw new RangeError('Invalid numeric digit: ' + digit);
|
|
}
|
|
|
|
return digit;
|
|
};
|
|
|
|
const readNumeric = buffer => {
|
|
const ndigits = buffer.readUInt16BE(0);
|
|
let weight = buffer.readInt16BE(2);
|
|
const sign = buffer.readUInt16BE(4);
|
|
const dscale = buffer.readUInt16BE(6);
|
|
let signText;
|
|
let isNegativeZero;
|
|
|
|
switch (sign) {
|
|
case 0x0000:
|
|
signText = '';
|
|
isNegativeZero = false;
|
|
break;
|
|
|
|
case 0x4000:
|
|
signText = '-';
|
|
isNegativeZero = true;
|
|
break;
|
|
|
|
case 0xc000:
|
|
return 'NaN';
|
|
|
|
default:
|
|
throw new RangeError('Invalid numeric sign: 0x' + sign.toString(16));
|
|
}
|
|
|
|
if (2 * ndigits !== buffer.length - 8) {
|
|
throw new RangeError('Invalid numeric length: ' + buffer.length + ' bytes of data representing ' + ndigits + ' digits');
|
|
}
|
|
|
|
if (dscale > 0x3fff) {
|
|
throw new RangeError('Invalid numeric dscale: 0x' + dscale.toString(16));
|
|
}
|
|
|
|
let result = signText;
|
|
let i = 0;
|
|
|
|
integerPart: {
|
|
for (;;) {
|
|
if (i >= ndigits) {
|
|
// no non-zero digits
|
|
weight = -1;
|
|
}
|
|
if (weight < 0) {
|
|
result += '0';
|
|
break integerPart;
|
|
}
|
|
|
|
const digit = readDigit(buffer, i);
|
|
i++;
|
|
weight--;
|
|
|
|
if (digit !== 0) {
|
|
isNegativeZero = false;
|
|
result += String(digit);
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (weight >= 0 && i < ndigits) {
|
|
const digit = readDigit(buffer, i);
|
|
i++;
|
|
weight--;
|
|
|
|
result += String(10000 + digit).substring(1);
|
|
}
|
|
|
|
while (weight >= 0) {
|
|
result += '0000';
|
|
weight--;
|
|
}
|
|
}
|
|
|
|
fractionalPart: if (dscale !== 0) {
|
|
result += '.';
|
|
|
|
const omitted = -1 - weight;
|
|
|
|
if (omitted > 0) {
|
|
if (4 * omitted > dscale) {
|
|
result += '0'.repeat(dscale);
|
|
break fractionalPart;
|
|
}
|
|
|
|
result += '0'.repeat(4 * omitted);
|
|
}
|
|
|
|
while (-4 * weight <= dscale) {
|
|
const digit = i < ndigits ? readDigit(buffer, i) : 0;
|
|
i++;
|
|
weight--;
|
|
|
|
if (isNegativeZero && digit !== 0) {
|
|
isNegativeZero = false;
|
|
}
|
|
|
|
result += String(10000 + digit).substring(1);
|
|
}
|
|
|
|
{
|
|
const digit = i < ndigits ? readDigit(buffer, i) : 0;
|
|
result += String(10000 + digit).substr(1, dscale % 4);
|
|
|
|
if (isNegativeZero && digit >= Math.pow(10, 4 - dscale % 4)) {
|
|
isNegativeZero = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return isNegativeZero ? result.substring(1) : result;
|
|
};
|
|
|
|
module.exports = readNumeric;
|