- Add GETTING_STARTED.md with quick start guide and development modes - Add INSTALL.sh automated installation script - Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md - Add QUICK_REFERENCE.md for common commands - Add SETUP_GUIDE.md with detailed setup instructions - Update README.md with improved project overview - Add did-wallet app dependencies and node_modules
179 lines
5.6 KiB
JavaScript
179 lines
5.6 KiB
JavaScript
import {
|
|
Token,
|
|
Type
|
|
} from './token.js';
|
|
import { decodeErrPrefix } from './common.js';
|
|
import { encodeUint } from './0uint.js';
|
|
const MINOR_FALSE = 20;
|
|
const MINOR_TRUE = 21;
|
|
const MINOR_NULL = 22;
|
|
const MINOR_UNDEFINED = 23;
|
|
export function decodeUndefined(_data, _pos, _minor, options) {
|
|
if (options.allowUndefined === false) {
|
|
throw new Error(`${ decodeErrPrefix } undefined values are not supported`);
|
|
} else if (options.coerceUndefinedToNull === true) {
|
|
return new Token(Type.null, null, 1);
|
|
}
|
|
return new Token(Type.undefined, undefined, 1);
|
|
}
|
|
export function decodeBreak(_data, _pos, _minor, options) {
|
|
if (options.allowIndefinite === false) {
|
|
throw new Error(`${ decodeErrPrefix } indefinite length items not allowed`);
|
|
}
|
|
return new Token(Type.break, undefined, 1);
|
|
}
|
|
function createToken(value, bytes, options) {
|
|
if (options) {
|
|
if (options.allowNaN === false && Number.isNaN(value)) {
|
|
throw new Error(`${ decodeErrPrefix } NaN values are not supported`);
|
|
}
|
|
if (options.allowInfinity === false && (value === Infinity || value === -Infinity)) {
|
|
throw new Error(`${ decodeErrPrefix } Infinity values are not supported`);
|
|
}
|
|
}
|
|
return new Token(Type.float, value, bytes);
|
|
}
|
|
export function decodeFloat16(data, pos, _minor, options) {
|
|
return createToken(readFloat16(data, pos + 1), 3, options);
|
|
}
|
|
export function decodeFloat32(data, pos, _minor, options) {
|
|
return createToken(readFloat32(data, pos + 1), 5, options);
|
|
}
|
|
export function decodeFloat64(data, pos, _minor, options) {
|
|
return createToken(readFloat64(data, pos + 1), 9, options);
|
|
}
|
|
export function encodeFloat(buf, token, options) {
|
|
const float = token.value;
|
|
if (float === false) {
|
|
buf.push([Type.float.majorEncoded | MINOR_FALSE]);
|
|
} else if (float === true) {
|
|
buf.push([Type.float.majorEncoded | MINOR_TRUE]);
|
|
} else if (float === null) {
|
|
buf.push([Type.float.majorEncoded | MINOR_NULL]);
|
|
} else if (float === undefined) {
|
|
buf.push([Type.float.majorEncoded | MINOR_UNDEFINED]);
|
|
} else {
|
|
let decoded;
|
|
let success = false;
|
|
if (!options || options.float64 !== true) {
|
|
encodeFloat16(float);
|
|
decoded = readFloat16(ui8a, 1);
|
|
if (float === decoded || Number.isNaN(float)) {
|
|
ui8a[0] = 249;
|
|
buf.push(ui8a.slice(0, 3));
|
|
success = true;
|
|
} else {
|
|
encodeFloat32(float);
|
|
decoded = readFloat32(ui8a, 1);
|
|
if (float === decoded) {
|
|
ui8a[0] = 250;
|
|
buf.push(ui8a.slice(0, 5));
|
|
success = true;
|
|
}
|
|
}
|
|
}
|
|
if (!success) {
|
|
encodeFloat64(float);
|
|
decoded = readFloat64(ui8a, 1);
|
|
ui8a[0] = 251;
|
|
buf.push(ui8a.slice(0, 9));
|
|
}
|
|
}
|
|
}
|
|
encodeFloat.encodedSize = function encodedSize(token, options) {
|
|
const float = token.value;
|
|
if (float === false || float === true || float === null || float === undefined) {
|
|
return 1;
|
|
}
|
|
if (!options || options.float64 !== true) {
|
|
encodeFloat16(float);
|
|
let decoded = readFloat16(ui8a, 1);
|
|
if (float === decoded || Number.isNaN(float)) {
|
|
return 3;
|
|
}
|
|
encodeFloat32(float);
|
|
decoded = readFloat32(ui8a, 1);
|
|
if (float === decoded) {
|
|
return 5;
|
|
}
|
|
}
|
|
return 9;
|
|
};
|
|
const buffer = new ArrayBuffer(9);
|
|
const dataView = new DataView(buffer, 1);
|
|
const ui8a = new Uint8Array(buffer, 0);
|
|
function encodeFloat16(inp) {
|
|
if (inp === Infinity) {
|
|
dataView.setUint16(0, 31744, false);
|
|
} else if (inp === -Infinity) {
|
|
dataView.setUint16(0, 64512, false);
|
|
} else if (Number.isNaN(inp)) {
|
|
dataView.setUint16(0, 32256, false);
|
|
} else {
|
|
dataView.setFloat32(0, inp);
|
|
const valu32 = dataView.getUint32(0);
|
|
const exponent = (valu32 & 2139095040) >> 23;
|
|
const mantissa = valu32 & 8388607;
|
|
if (exponent === 255) {
|
|
dataView.setUint16(0, 31744, false);
|
|
} else if (exponent === 0) {
|
|
dataView.setUint16(0, (inp & 2147483648) >> 16 | mantissa >> 13, false);
|
|
} else {
|
|
const logicalExponent = exponent - 127;
|
|
if (logicalExponent < -24) {
|
|
dataView.setUint16(0, 0);
|
|
} else if (logicalExponent < -14) {
|
|
dataView.setUint16(0, (valu32 & 2147483648) >> 16 | 1 << 24 + logicalExponent, false);
|
|
} else {
|
|
dataView.setUint16(0, (valu32 & 2147483648) >> 16 | logicalExponent + 15 << 10 | mantissa >> 13, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function readFloat16(ui8a, pos) {
|
|
if (ui8a.length - pos < 2) {
|
|
throw new Error(`${ decodeErrPrefix } not enough data for float16`);
|
|
}
|
|
const half = (ui8a[pos] << 8) + ui8a[pos + 1];
|
|
if (half === 31744) {
|
|
return Infinity;
|
|
}
|
|
if (half === 64512) {
|
|
return -Infinity;
|
|
}
|
|
if (half === 32256) {
|
|
return NaN;
|
|
}
|
|
const exp = half >> 10 & 31;
|
|
const mant = half & 1023;
|
|
let val;
|
|
if (exp === 0) {
|
|
val = mant * 2 ** -24;
|
|
} else if (exp !== 31) {
|
|
val = (mant + 1024) * 2 ** (exp - 25);
|
|
} else {
|
|
val = mant === 0 ? Infinity : NaN;
|
|
}
|
|
return half & 32768 ? -val : val;
|
|
}
|
|
function encodeFloat32(inp) {
|
|
dataView.setFloat32(0, inp, false);
|
|
}
|
|
function readFloat32(ui8a, pos) {
|
|
if (ui8a.length - pos < 4) {
|
|
throw new Error(`${ decodeErrPrefix } not enough data for float32`);
|
|
}
|
|
const offset = (ui8a.byteOffset || 0) + pos;
|
|
return new DataView(ui8a.buffer, offset, 4).getFloat32(0, false);
|
|
}
|
|
function encodeFloat64(inp) {
|
|
dataView.setFloat64(0, inp, false);
|
|
}
|
|
function readFloat64(ui8a, pos) {
|
|
if (ui8a.length - pos < 8) {
|
|
throw new Error(`${ decodeErrPrefix } not enough data for float64`);
|
|
}
|
|
const offset = (ui8a.byteOffset || 0) + pos;
|
|
return new DataView(ui8a.buffer, offset, 8).getFloat64(0, false);
|
|
}
|
|
encodeFloat.compareTokens = encodeUint.compareTokens; |