UNPKG

asn1-ts

Version:

ASN.1 encoding and decoding, including BER, CER, and DER.

96 lines (95 loc) 4.7 kB
import * as errors from "../../../errors.mjs"; import { ASN1SpecialRealValue, ASN1RealEncodingBase, ASN1RealEncodingScale, nr3Regex, } from "../../../values.mjs"; import convertBytesToText from "../../../utils/convertBytesToText.mjs"; import decodeUnsignedBigEndianInteger from "../../../utils/decodeUnsignedBigEndianInteger.mjs"; import decodeSignedBigEndianInteger from "../../../utils/decodeSignedBigEndianInteger.mjs"; export default function decodeReal(value) { if (value.length === 0) return 0.0; switch (value[0] & 0b11000000) { case (0b01000000): { if (value[0] === ASN1SpecialRealValue.notANumber) return NaN; if (value[0] === ASN1SpecialRealValue.minusZero) return -0.0; if (value[0] === ASN1SpecialRealValue.plusInfinity) return Infinity; if (value[0] === ASN1SpecialRealValue.minusInfinity) return -Infinity; throw new errors.ASN1UndefinedError("Unrecognized special REAL value!"); } case (0b00000000): { const realString = convertBytesToText(value.subarray(1)); switch (value[0] & 0b00111111) { case 1: case 2: throw new errors.ASN1Error("DER prohibits NR1 and NR2 Base-10 REAL"); case 3: { if (!nr3Regex.test(realString)) throw new errors.ASN1Error("Malformed NR3 Base-10 REAL"); return Number.parseFloat(realString.replace(",", ".")); } default: throw new errors.ASN1UndefinedError("Undefined Base-10 REAL encoding."); } } case (0b10000000): case (0b11000000): { const sign = ((value[0] & 0b01000000) ? -1 : 1); const base = ((flag) => { switch (flag) { case (ASN1RealEncodingBase.base2): return 2; case (ASN1RealEncodingBase.base8): return 8; case (ASN1RealEncodingBase.base16): return 16; default: throw new errors.ASN1Error("Impossible REAL encoding base encountered."); } })(value[0] & 0b00110000); const scale = ((flag) => { switch (flag) { case (ASN1RealEncodingScale.scale0): return 0; case (ASN1RealEncodingScale.scale1): return 1; case (ASN1RealEncodingScale.scale2): return 2; case (ASN1RealEncodingScale.scale3): return 3; default: throw new errors.ASN1Error("Impossible REAL encoding scale encountered."); } })(value[0] & 0b00001100); let exponent; let mantissa; switch (value[0] & 0b00000011) { case (0b00000000): { if (value.length < 3) throw new errors.ASN1TruncationError("Binary-encoded REAL truncated."); exponent = decodeSignedBigEndianInteger(value.subarray(1, 2)); mantissa = decodeUnsignedBigEndianInteger(value.subarray(2)); break; } case (0b00000001): { if (value.length < 4) throw new errors.ASN1TruncationError("Binary-encoded REAL truncated."); exponent = decodeSignedBigEndianInteger(value.subarray(1, 3)); mantissa = decodeUnsignedBigEndianInteger(value.subarray(3)); if (exponent <= 127 && exponent >= -128) { throw new errors.ASN1Error("DER-encoded binary-encoded REAL could have encoded exponent on fewer octets."); } break; } case (0b00000010): case (0b00000011): { throw new errors.ASN1Error("DER-encoded binary REAL encoded in a way that would " + "either overflow or encode on too many octets."); } default: throw new errors.ASN1Error("Impossible binary REAL exponent encoding encountered."); } if (mantissa !== 0 && !(mantissa % 2)) { throw new errors.ASN1Error("DER-encoded REAL may not have an even non-zero mantissa."); } return (sign * mantissa * Math.pow(2, scale) * Math.pow(base, exponent)); } default: { throw new errors.ASN1Error("Impossible REAL format encountered."); } } }