190 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
var conversions = {};
 | 
						|
module.exports = conversions;
 | 
						|
 | 
						|
function sign(x) {
 | 
						|
    return x < 0 ? -1 : 1;
 | 
						|
}
 | 
						|
 | 
						|
function evenRound(x) {
 | 
						|
    // Round x to the nearest integer, choosing the even integer if it lies halfway between two.
 | 
						|
    if ((x % 1) === 0.5 && (x & 1) === 0) { // [even number].5; round down (i.e. floor)
 | 
						|
        return Math.floor(x);
 | 
						|
    } else {
 | 
						|
        return Math.round(x);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
function createNumberConversion(bitLength, typeOpts) {
 | 
						|
    if (!typeOpts.unsigned) {
 | 
						|
        --bitLength;
 | 
						|
    }
 | 
						|
    const lowerBound = typeOpts.unsigned ? 0 : -Math.pow(2, bitLength);
 | 
						|
    const upperBound = Math.pow(2, bitLength) - 1;
 | 
						|
 | 
						|
    const moduloVal = typeOpts.moduloBitLength ? Math.pow(2, typeOpts.moduloBitLength) : Math.pow(2, bitLength);
 | 
						|
    const moduloBound = typeOpts.moduloBitLength ? Math.pow(2, typeOpts.moduloBitLength - 1) : Math.pow(2, bitLength - 1);
 | 
						|
 | 
						|
    return function(V, opts) {
 | 
						|
        if (!opts) opts = {};
 | 
						|
 | 
						|
        let x = +V;
 | 
						|
 | 
						|
        if (opts.enforceRange) {
 | 
						|
            if (!Number.isFinite(x)) {
 | 
						|
                throw new TypeError("Argument is not a finite number");
 | 
						|
            }
 | 
						|
 | 
						|
            x = sign(x) * Math.floor(Math.abs(x));
 | 
						|
            if (x < lowerBound || x > upperBound) {
 | 
						|
                throw new TypeError("Argument is not in byte range");
 | 
						|
            }
 | 
						|
 | 
						|
            return x;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!isNaN(x) && opts.clamp) {
 | 
						|
            x = evenRound(x);
 | 
						|
 | 
						|
            if (x < lowerBound) x = lowerBound;
 | 
						|
            if (x > upperBound) x = upperBound;
 | 
						|
            return x;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!Number.isFinite(x) || x === 0) {
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        x = sign(x) * Math.floor(Math.abs(x));
 | 
						|
        x = x % moduloVal;
 | 
						|
 | 
						|
        if (!typeOpts.unsigned && x >= moduloBound) {
 | 
						|
            return x - moduloVal;
 | 
						|
        } else if (typeOpts.unsigned) {
 | 
						|
            if (x < 0) {
 | 
						|
              x += moduloVal;
 | 
						|
            } else if (x === -0) { // don't return negative zero
 | 
						|
              return 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return x;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
conversions["void"] = function () {
 | 
						|
    return undefined;
 | 
						|
};
 | 
						|
 | 
						|
conversions["boolean"] = function (val) {
 | 
						|
    return !!val;
 | 
						|
};
 | 
						|
 | 
						|
conversions["byte"] = createNumberConversion(8, { unsigned: false });
 | 
						|
conversions["octet"] = createNumberConversion(8, { unsigned: true });
 | 
						|
 | 
						|
conversions["short"] = createNumberConversion(16, { unsigned: false });
 | 
						|
conversions["unsigned short"] = createNumberConversion(16, { unsigned: true });
 | 
						|
 | 
						|
conversions["long"] = createNumberConversion(32, { unsigned: false });
 | 
						|
conversions["unsigned long"] = createNumberConversion(32, { unsigned: true });
 | 
						|
 | 
						|
conversions["long long"] = createNumberConversion(32, { unsigned: false, moduloBitLength: 64 });
 | 
						|
conversions["unsigned long long"] = createNumberConversion(32, { unsigned: true, moduloBitLength: 64 });
 | 
						|
 | 
						|
conversions["double"] = function (V) {
 | 
						|
    const x = +V;
 | 
						|
 | 
						|
    if (!Number.isFinite(x)) {
 | 
						|
        throw new TypeError("Argument is not a finite floating-point value");
 | 
						|
    }
 | 
						|
 | 
						|
    return x;
 | 
						|
};
 | 
						|
 | 
						|
conversions["unrestricted double"] = function (V) {
 | 
						|
    const x = +V;
 | 
						|
 | 
						|
    if (isNaN(x)) {
 | 
						|
        throw new TypeError("Argument is NaN");
 | 
						|
    }
 | 
						|
 | 
						|
    return x;
 | 
						|
};
 | 
						|
 | 
						|
// not quite valid, but good enough for JS
 | 
						|
conversions["float"] = conversions["double"];
 | 
						|
conversions["unrestricted float"] = conversions["unrestricted double"];
 | 
						|
 | 
						|
conversions["DOMString"] = function (V, opts) {
 | 
						|
    if (!opts) opts = {};
 | 
						|
 | 
						|
    if (opts.treatNullAsEmptyString && V === null) {
 | 
						|
        return "";
 | 
						|
    }
 | 
						|
 | 
						|
    return String(V);
 | 
						|
};
 | 
						|
 | 
						|
conversions["ByteString"] = function (V, opts) {
 | 
						|
    const x = String(V);
 | 
						|
    let c = undefined;
 | 
						|
    for (let i = 0; (c = x.codePointAt(i)) !== undefined; ++i) {
 | 
						|
        if (c > 255) {
 | 
						|
            throw new TypeError("Argument is not a valid bytestring");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return x;
 | 
						|
};
 | 
						|
 | 
						|
conversions["USVString"] = function (V) {
 | 
						|
    const S = String(V);
 | 
						|
    const n = S.length;
 | 
						|
    const U = [];
 | 
						|
    for (let i = 0; i < n; ++i) {
 | 
						|
        const c = S.charCodeAt(i);
 | 
						|
        if (c < 0xD800 || c > 0xDFFF) {
 | 
						|
            U.push(String.fromCodePoint(c));
 | 
						|
        } else if (0xDC00 <= c && c <= 0xDFFF) {
 | 
						|
            U.push(String.fromCodePoint(0xFFFD));
 | 
						|
        } else {
 | 
						|
            if (i === n - 1) {
 | 
						|
                U.push(String.fromCodePoint(0xFFFD));
 | 
						|
            } else {
 | 
						|
                const d = S.charCodeAt(i + 1);
 | 
						|
                if (0xDC00 <= d && d <= 0xDFFF) {
 | 
						|
                    const a = c & 0x3FF;
 | 
						|
                    const b = d & 0x3FF;
 | 
						|
                    U.push(String.fromCodePoint((2 << 15) + (2 << 9) * a + b));
 | 
						|
                    ++i;
 | 
						|
                } else {
 | 
						|
                    U.push(String.fromCodePoint(0xFFFD));
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return U.join('');
 | 
						|
};
 | 
						|
 | 
						|
conversions["Date"] = function (V, opts) {
 | 
						|
    if (!(V instanceof Date)) {
 | 
						|
        throw new TypeError("Argument is not a Date object");
 | 
						|
    }
 | 
						|
    if (isNaN(V)) {
 | 
						|
        return undefined;
 | 
						|
    }
 | 
						|
 | 
						|
    return V;
 | 
						|
};
 | 
						|
 | 
						|
conversions["RegExp"] = function (V, opts) {
 | 
						|
    if (!(V instanceof RegExp)) {
 | 
						|
        V = new RegExp(V);
 | 
						|
    }
 | 
						|
 | 
						|
    return V;
 | 
						|
};
 |