summaryrefslogtreecommitdiffstats
path: root/toolkit/components/certviewer/content/vendor/asn1js_bundle.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/certviewer/content/vendor/asn1js_bundle.js')
-rw-r--r--toolkit/components/certviewer/content/vendor/asn1js_bundle.js5877
1 files changed, 5877 insertions, 0 deletions
diff --git a/toolkit/components/certviewer/content/vendor/asn1js_bundle.js b/toolkit/components/certviewer/content/vendor/asn1js_bundle.js
new file mode 100644
index 0000000000..8e4dd5f2d9
--- /dev/null
+++ b/toolkit/components/certviewer/content/vendor/asn1js_bundle.js
@@ -0,0 +1,5877 @@
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.asn1js = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ const asn1js = require("asn1js"); // version 2.0.22
+
+ module.exports = {
+ asn1js,
+ };
+
+},{"asn1js":2}],2:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.RawData = exports.Repeated = exports.Any = exports.Choice = exports.TIME = exports.Duration = exports.DateTime = exports.TimeOfDay = exports.DATE = exports.GeneralizedTime = exports.UTCTime = exports.CharacterString = exports.GeneralString = exports.VisibleString = exports.GraphicString = exports.IA5String = exports.VideotexString = exports.TeletexString = exports.PrintableString = exports.NumericString = exports.UniversalString = exports.BmpString = exports.Utf8String = exports.ObjectIdentifier = exports.Enumerated = exports.Integer = exports.BitString = exports.OctetString = exports.Null = exports.Set = exports.Sequence = exports.Boolean = exports.EndOfContent = exports.Constructed = exports.Primitive = exports.BaseBlock = undefined;
+exports.fromBER = fromBER;
+exports.compareSchema = compareSchema;
+exports.verifySchema = verifySchema;
+exports.fromJSON = fromJSON;
+
+var _pvutils = require("pvutils");
+
+//**************************************************************************************
+//region Declaration of global variables
+//**************************************************************************************
+const powers2 = [new Uint8Array([1])]; /* eslint-disable indent */
+/*
+ * Copyright (c) 2016-2018, Peculiar Ventures
+ * All rights reserved.
+ *
+ * Author 2016-2018, Yury Strozhevsky <www.strozhevsky.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+//**************************************************************************************
+
+const digitsString = "0123456789";
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration for "LocalBaseBlock" class
+//**************************************************************************************
+/**
+ * Class used as a base block for all remaining ASN.1 classes
+ * @typedef LocalBaseBlock
+ * @interface
+ * @property {number} blockLength
+ * @property {string} error
+ * @property {Array.<string>} warnings
+ * @property {ArrayBuffer} valueBeforeDecode
+ */
+class LocalBaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalBaseBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueBeforeDecode]
+ */
+ constructor(parameters = {}) {
+ /**
+ * @type {number} blockLength
+ */
+ this.blockLength = (0, _pvutils.getParametersValue)(parameters, "blockLength", 0);
+ /**
+ * @type {string} error
+ */
+ this.error = (0, _pvutils.getParametersValue)(parameters, "error", "");
+ /**
+ * @type {Array.<string>} warnings
+ */
+ this.warnings = (0, _pvutils.getParametersValue)(parameters, "warnings", []);
+ //noinspection JSCheckFunctionSignatures
+ /**
+ * @type {ArrayBuffer} valueBeforeDecode
+ */
+ if ("valueBeforeDecode" in parameters) this.valueBeforeDecode = parameters.valueBeforeDecode.slice(0);else this.valueBeforeDecode = new ArrayBuffer(0);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "baseBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ return {
+ blockName: this.constructor.blockName(),
+ blockLength: this.blockLength,
+ error: this.error,
+ warnings: this.warnings,
+ valueBeforeDecode: (0, _pvutils.bufferToHexCodes)(this.valueBeforeDecode, 0, this.valueBeforeDecode.byteLength)
+ };
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Description for "LocalHexBlock" class
+//**************************************************************************************
+/**
+ * Class used as a base block for all remaining ASN.1 classes
+ * @extends LocalBaseBlock
+ * @typedef LocalHexBlock
+ * @property {number} blockLength
+ * @property {string} error
+ * @property {Array.<string>} warnings
+ * @property {ArrayBuffer} valueBeforeDecode
+ * @property {boolean} isHexOnly
+ * @property {ArrayBuffer} valueHex
+ */
+//noinspection JSUnusedLocalSymbols
+const LocalHexBlock = BaseClass => class LocalHexBlockMixin extends BaseClass {
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Constructor for "LocalHexBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ /**
+ * @type {boolean}
+ */
+ this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false);
+ /**
+ * @type {ArrayBuffer}
+ */
+ if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "hexBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ //region Initial checks
+ if (intBuffer.length === 0) {
+ this.warnings.push("Zero buffer length");
+ return inputOffset;
+ }
+ //endregion
+
+ //region Copy input buffer to internal buffer
+ this.valueHex = inputBuffer.slice(inputOffset, inputOffset + inputLength);
+ //endregion
+
+ this.blockLength = inputLength;
+
+ return inputOffset + inputLength;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ if (this.isHexOnly !== true) {
+ this.error = "Flag \"isHexOnly\" is not set, abort";
+ return new ArrayBuffer(0);
+ }
+
+ if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength);
+
+ //noinspection JSCheckFunctionSignatures
+ return this.valueHex.slice(0);
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.blockName = this.constructor.blockName();
+ object.isHexOnly = this.isHexOnly;
+ object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
+
+ return object;
+ }
+ //**********************************************************************************
+};
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of identification block class
+//**************************************************************************************
+class LocalIdentificationBlock extends LocalHexBlock(LocalBaseBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalBaseBlock" class
+ * @param {Object} [parameters={}]
+ * @property {Object} [idBlock]
+ */
+ constructor(parameters = {}) {
+ super();
+
+ if ("idBlock" in parameters) {
+ //region Properties from hexBlock class
+ this.isHexOnly = (0, _pvutils.getParametersValue)(parameters.idBlock, "isHexOnly", false);
+ this.valueHex = (0, _pvutils.getParametersValue)(parameters.idBlock, "valueHex", new ArrayBuffer(0));
+ //endregion
+
+ this.tagClass = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagClass", -1);
+ this.tagNumber = (0, _pvutils.getParametersValue)(parameters.idBlock, "tagNumber", -1);
+ this.isConstructed = (0, _pvutils.getParametersValue)(parameters.idBlock, "isConstructed", false);
+ } else {
+ this.tagClass = -1;
+ this.tagNumber = -1;
+ this.isConstructed = false;
+ }
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "identificationBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ //region Initial variables
+ let firstOctet = 0;
+ let retBuf;
+ let retView;
+ //endregion
+
+ switch (this.tagClass) {
+ case 1:
+ firstOctet |= 0x00; // UNIVERSAL
+ break;
+ case 2:
+ firstOctet |= 0x40; // APPLICATION
+ break;
+ case 3:
+ firstOctet |= 0x80; // CONTEXT-SPECIFIC
+ break;
+ case 4:
+ firstOctet |= 0xC0; // PRIVATE
+ break;
+ default:
+ this.error = "Unknown tag class";
+ return new ArrayBuffer(0);
+ }
+
+ if (this.isConstructed) firstOctet |= 0x20;
+
+ if (this.tagNumber < 31 && !this.isHexOnly) {
+ retBuf = new ArrayBuffer(1);
+ retView = new Uint8Array(retBuf);
+
+ if (!sizeOnly) {
+ let number = this.tagNumber;
+ number &= 0x1F;
+ firstOctet |= number;
+
+ retView[0] = firstOctet;
+ }
+
+ return retBuf;
+ }
+
+ if (this.isHexOnly === false) {
+ const encodedBuf = (0, _pvutils.utilToBase)(this.tagNumber, 7);
+ const encodedView = new Uint8Array(encodedBuf);
+ const size = encodedBuf.byteLength;
+
+ retBuf = new ArrayBuffer(size + 1);
+ retView = new Uint8Array(retBuf);
+ retView[0] = firstOctet | 0x1F;
+
+ if (!sizeOnly) {
+ for (let i = 0; i < size - 1; i++) retView[i + 1] = encodedView[i] | 0x80;
+
+ retView[size] = encodedView[size - 1];
+ }
+
+ return retBuf;
+ }
+
+ retBuf = new ArrayBuffer(this.valueHex.byteLength + 1);
+ retView = new Uint8Array(retBuf);
+
+ retView[0] = firstOctet | 0x1F;
+
+ if (sizeOnly === false) {
+ const curView = new Uint8Array(this.valueHex);
+
+ for (let i = 0; i < curView.length - 1; i++) retView[i + 1] = curView[i] | 0x80;
+
+ retView[this.valueHex.byteLength] = curView[curView.length - 1];
+ }
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ //region Initial checks
+ if (intBuffer.length === 0) {
+ this.error = "Zero buffer length";
+ return -1;
+ }
+ //endregion
+
+ //region Find tag class
+ const tagClassMask = intBuffer[0] & 0xC0;
+
+ switch (tagClassMask) {
+ case 0x00:
+ this.tagClass = 1; // UNIVERSAL
+ break;
+ case 0x40:
+ this.tagClass = 2; // APPLICATION
+ break;
+ case 0x80:
+ this.tagClass = 3; // CONTEXT-SPECIFIC
+ break;
+ case 0xC0:
+ this.tagClass = 4; // PRIVATE
+ break;
+ default:
+ this.error = "Unknown tag class";
+ return -1;
+ }
+ //endregion
+
+ //region Find it's constructed or not
+ this.isConstructed = (intBuffer[0] & 0x20) === 0x20;
+ //endregion
+
+ //region Find tag number
+ this.isHexOnly = false;
+
+ const tagNumberMask = intBuffer[0] & 0x1F;
+
+ //region Simple case (tag number < 31)
+ if (tagNumberMask !== 0x1F) {
+ this.tagNumber = tagNumberMask;
+ this.blockLength = 1;
+ }
+ //endregion
+ //region Tag number bigger or equal to 31
+ else {
+ let count = 1;
+
+ this.valueHex = new ArrayBuffer(255);
+ let tagNumberBufferMaxLength = 255;
+ let intTagNumberBuffer = new Uint8Array(this.valueHex);
+
+ //noinspection JSBitwiseOperatorUsage
+ while (intBuffer[count] & 0x80) {
+ intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F;
+ count++;
+
+ if (count >= intBuffer.length) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+
+ //region In case if tag number length is greater than 255 bytes (rare but possible case)
+ if (count === tagNumberBufferMaxLength) {
+ tagNumberBufferMaxLength += 255;
+
+ const tempBuffer = new ArrayBuffer(tagNumberBufferMaxLength);
+ const tempBufferView = new Uint8Array(tempBuffer);
+
+ for (let i = 0; i < intTagNumberBuffer.length; i++) tempBufferView[i] = intTagNumberBuffer[i];
+
+ this.valueHex = new ArrayBuffer(tagNumberBufferMaxLength);
+ intTagNumberBuffer = new Uint8Array(this.valueHex);
+ }
+ //endregion
+ }
+
+ this.blockLength = count + 1;
+ intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer
+
+ //region Cut buffer
+ const tempBuffer = new ArrayBuffer(count);
+ const tempBufferView = new Uint8Array(tempBuffer);
+
+ for (let i = 0; i < count; i++) tempBufferView[i] = intTagNumberBuffer[i];
+
+ this.valueHex = new ArrayBuffer(count);
+ intTagNumberBuffer = new Uint8Array(this.valueHex);
+ intTagNumberBuffer.set(tempBufferView);
+ //endregion
+
+ //region Try to convert long tag number to short form
+ if (this.blockLength <= 9) this.tagNumber = (0, _pvutils.utilFromBase)(intTagNumberBuffer, 7);else {
+ this.isHexOnly = true;
+ this.warnings.push("Tag too long, represented as hex-coded");
+ }
+ //endregion
+ }
+ //endregion
+ //endregion
+
+ //region Check if constructed encoding was using for primitive type
+ if (this.tagClass === 1 && this.isConstructed) {
+ switch (this.tagNumber) {
+ case 1: // Boolean
+ case 2: // REAL
+ case 5: // Null
+ case 6: // OBJECT IDENTIFIER
+ case 9: // REAL
+ case 14: // Time
+ case 23:
+ case 24:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ this.error = "Constructed encoding used for primitive type";
+ return -1;
+ default:
+ }
+ }
+ //endregion
+
+ return inputOffset + this.blockLength; // Return current offset in input buffer
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName: string,
+ * tagClass: number,
+ * tagNumber: number,
+ * isConstructed: boolean,
+ * isHexOnly: boolean,
+ * valueHex: ArrayBuffer,
+ * blockLength: number,
+ * error: string, warnings: Array.<string>,
+ * valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.blockName = this.constructor.blockName();
+ object.tagClass = this.tagClass;
+ object.tagNumber = this.tagNumber;
+ object.isConstructed = this.isConstructed;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of length block class
+//**************************************************************************************
+class LocalLengthBlock extends LocalBaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalLengthBlock" class
+ * @param {Object} [parameters={}]
+ * @property {Object} [lenBlock]
+ */
+ constructor(parameters = {}) {
+ super();
+
+ if ("lenBlock" in parameters) {
+ this.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters.lenBlock, "isIndefiniteForm", false);
+ this.longFormUsed = (0, _pvutils.getParametersValue)(parameters.lenBlock, "longFormUsed", false);
+ this.length = (0, _pvutils.getParametersValue)(parameters.lenBlock, "length", 0);
+ } else {
+ this.isIndefiniteForm = false;
+ this.longFormUsed = false;
+ this.length = 0;
+ }
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "lengthBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ //region Initial checks
+ if (intBuffer.length === 0) {
+ this.error = "Zero buffer length";
+ return -1;
+ }
+
+ if (intBuffer[0] === 0xFF) {
+ this.error = "Length block 0xFF is reserved by standard";
+ return -1;
+ }
+ //endregion
+
+ //region Check for length form type
+ this.isIndefiniteForm = intBuffer[0] === 0x80;
+ //endregion
+
+ //region Stop working in case of indefinite length form
+ if (this.isIndefiniteForm === true) {
+ this.blockLength = 1;
+ return inputOffset + this.blockLength;
+ }
+ //endregion
+
+ //region Check is long form of length encoding using
+ this.longFormUsed = !!(intBuffer[0] & 0x80);
+ //endregion
+
+ //region Stop working in case of short form of length value
+ if (this.longFormUsed === false) {
+ this.length = intBuffer[0];
+ this.blockLength = 1;
+ return inputOffset + this.blockLength;
+ }
+ //endregion
+
+ //region Calculate length value in case of long form
+ const count = intBuffer[0] & 0x7F;
+
+ if (count > 8) // Too big length value
+ {
+ this.error = "Too big integer";
+ return -1;
+ }
+
+ if (count + 1 > intBuffer.length) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+
+ const lengthBufferView = new Uint8Array(count);
+
+ for (let i = 0; i < count; i++) lengthBufferView[i] = intBuffer[i + 1];
+
+ if (lengthBufferView[count - 1] === 0x00) this.warnings.push("Needlessly long encoded length");
+
+ this.length = (0, _pvutils.utilFromBase)(lengthBufferView, 8);
+
+ if (this.longFormUsed && this.length <= 127) this.warnings.push("Unneccesary usage of long length form");
+
+ this.blockLength = count + 1;
+ //endregion
+
+ return inputOffset + this.blockLength; // Return current offset in input buffer
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ //region Initial variables
+ let retBuf;
+ let retView;
+ //endregion
+
+ if (this.length > 127) this.longFormUsed = true;
+
+ if (this.isIndefiniteForm) {
+ retBuf = new ArrayBuffer(1);
+
+ if (sizeOnly === false) {
+ retView = new Uint8Array(retBuf);
+ retView[0] = 0x80;
+ }
+
+ return retBuf;
+ }
+
+ if (this.longFormUsed === true) {
+ const encodedBuf = (0, _pvutils.utilToBase)(this.length, 8);
+
+ if (encodedBuf.byteLength > 127) {
+ this.error = "Too big length";
+ return new ArrayBuffer(0);
+ }
+
+ retBuf = new ArrayBuffer(encodedBuf.byteLength + 1);
+
+ if (sizeOnly === true) return retBuf;
+
+ const encodedView = new Uint8Array(encodedBuf);
+ retView = new Uint8Array(retBuf);
+
+ retView[0] = encodedBuf.byteLength | 0x80;
+
+ for (let i = 0; i < encodedBuf.byteLength; i++) retView[i + 1] = encodedView[i];
+
+ return retBuf;
+ }
+
+ retBuf = new ArrayBuffer(1);
+
+ if (sizeOnly === false) {
+ retView = new Uint8Array(retBuf);
+
+ retView[0] = this.length;
+ }
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.blockName = this.constructor.blockName();
+ object.isIndefiniteForm = this.isIndefiniteForm;
+ object.longFormUsed = this.longFormUsed;
+ object.length = this.length;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of value block class
+//**************************************************************************************
+class LocalValueBlock extends LocalBaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "valueBlock";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols,JSUnusedLocalSymbols
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Throw an exception for a function which needs to be specified in extended classes
+ throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\"");
+ //endregion
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ //region Throw an exception for a function which needs to be specified in extended classes
+ throw TypeError("User need to make a specific function in a class which extends \"LocalValueBlock\"");
+ //endregion
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of basic ASN.1 block class
+//**************************************************************************************
+class BaseBlock extends LocalBaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "BaseBlock" class
+ * @param {Object} [parameters={}]
+ * @property {Object} [primitiveSchema]
+ * @property {string} [name]
+ * @property {boolean} [optional]
+ * @param valueBlockType Type of value block
+ */
+ constructor(parameters = {}, valueBlockType = LocalValueBlock) {
+ super(parameters);
+
+ if ("name" in parameters) this.name = parameters.name;
+ if ("optional" in parameters) this.optional = parameters.optional;
+ if ("primitiveSchema" in parameters) this.primitiveSchema = parameters.primitiveSchema;
+
+ this.idBlock = new LocalIdentificationBlock(parameters);
+ this.lenBlock = new LocalLengthBlock(parameters);
+ this.valueBlock = new valueBlockType(parameters);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "BaseBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ let retBuf;
+
+ const idBlockBuf = this.idBlock.toBER(sizeOnly);
+ const valueBlockSizeBuf = this.valueBlock.toBER(true);
+
+ this.lenBlock.length = valueBlockSizeBuf.byteLength;
+ const lenBlockBuf = this.lenBlock.toBER(sizeOnly);
+
+ retBuf = (0, _pvutils.utilConcatBuf)(idBlockBuf, lenBlockBuf);
+
+ let valueBlockBuf;
+
+ if (sizeOnly === false) valueBlockBuf = this.valueBlock.toBER(sizeOnly);else valueBlockBuf = new ArrayBuffer(this.lenBlock.length);
+
+ retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBlockBuf);
+
+ if (this.lenBlock.isIndefiniteForm === true) {
+ const indefBuf = new ArrayBuffer(2);
+
+ if (sizeOnly === false) {
+ const indefView = new Uint8Array(indefBuf);
+
+ indefView[0] = 0x00;
+ indefView[1] = 0x00;
+ }
+
+ retBuf = (0, _pvutils.utilConcatBuf)(retBuf, indefBuf);
+ }
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.idBlock = this.idBlock.toJSON();
+ object.lenBlock = this.lenBlock.toJSON();
+ object.valueBlock = this.valueBlock.toJSON();
+
+ if ("name" in this) object.name = this.name;
+ if ("optional" in this) object.optional = this.optional;
+ if ("primitiveSchema" in this) object.primitiveSchema = this.primitiveSchema.toJSON();
+
+ return object;
+ }
+ //**********************************************************************************
+}
+exports.BaseBlock = BaseBlock; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of basic block for all PRIMITIVE types
+//**************************************************************************************
+
+class LocalPrimitiveValueBlock extends LocalValueBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalPrimitiveValueBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueBeforeDecode]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ //region Variables from "hexBlock" class
+ if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else this.valueHex = new ArrayBuffer(0);
+
+ this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", true);
+ //endregion
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ //region Initial checks
+ if (intBuffer.length === 0) {
+ this.warnings.push("Zero buffer length");
+ return inputOffset;
+ }
+ //endregion
+
+ //region Copy input buffer into internal buffer
+ this.valueHex = new ArrayBuffer(intBuffer.length);
+ const valueHexView = new Uint8Array(this.valueHex);
+
+ for (let i = 0; i < intBuffer.length; i++) valueHexView[i] = intBuffer[i];
+ //endregion
+
+ this.blockLength = inputLength;
+
+ return inputOffset + inputLength;
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ return this.valueHex.slice(0);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "PrimitiveValueBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
+ object.isHexOnly = this.isHexOnly;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class Primitive extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "Primitive" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalPrimitiveValueBlock);
+
+ this.idBlock.isConstructed = false;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "PRIMITIVE";
+ }
+ //**********************************************************************************
+}
+exports.Primitive = Primitive; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of basic block for all CONSTRUCTED types
+//**************************************************************************************
+
+class LocalConstructedValueBlock extends LocalValueBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalConstructedValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.value = (0, _pvutils.getParametersValue)(parameters, "value", []);
+ this.isIndefiniteForm = (0, _pvutils.getParametersValue)(parameters, "isIndefiniteForm", false);
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Store initial offset and length
+ const initialOffset = inputOffset;
+ const initialLength = inputLength;
+ //endregion
+
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ //region Initial checks
+ if (intBuffer.length === 0) {
+ this.warnings.push("Zero buffer length");
+ return inputOffset;
+ }
+ //endregion
+
+ //region Aux function
+ function checkLen(indefiniteLength, length) {
+ if (indefiniteLength === true) return 1;
+
+ return length;
+ }
+ //endregion
+
+ let currentOffset = inputOffset;
+
+ while (checkLen(this.isIndefiniteForm, inputLength) > 0) {
+ const returnObject = LocalFromBER(inputBuffer, currentOffset, inputLength);
+ if (returnObject.offset === -1) {
+ this.error = returnObject.result.error;
+ this.warnings.concat(returnObject.result.warnings);
+ return -1;
+ }
+
+ currentOffset = returnObject.offset;
+
+ this.blockLength += returnObject.result.blockLength;
+ inputLength -= returnObject.result.blockLength;
+
+ this.value.push(returnObject.result);
+
+ if (this.isIndefiniteForm === true && returnObject.result.constructor.blockName() === EndOfContent.blockName()) break;
+ }
+
+ if (this.isIndefiniteForm === true) {
+ if (this.value[this.value.length - 1].constructor.blockName() === EndOfContent.blockName()) this.value.pop();else this.warnings.push("No EndOfContent block encoded");
+ }
+
+ //region Copy "inputBuffer" to "valueBeforeDecode"
+ this.valueBeforeDecode = inputBuffer.slice(initialOffset, initialOffset + initialLength);
+ //endregion
+
+ return currentOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ let retBuf = new ArrayBuffer(0);
+
+ for (let i = 0; i < this.value.length; i++) {
+ const valueBuf = this.value[i].toBER(sizeOnly);
+ retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf);
+ }
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "ConstructedValueBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.isIndefiniteForm = this.isIndefiniteForm;
+ object.value = [];
+ for (let i = 0; i < this.value.length; i++) object.value.push(this.value[i].toJSON());
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class Constructed extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "Constructed" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalConstructedValueBlock);
+
+ this.idBlock.isConstructed = true;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "CONSTRUCTED";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
+
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+}
+exports.Constructed = Constructed; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 EndOfContent type class
+//**************************************************************************************
+
+class LocalEndOfContentValueBlock extends LocalValueBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalEndOfContentValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols,JSUnusedLocalSymbols
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number}
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region There is no "value block" for EndOfContent type and we need to return the same offset
+ return inputOffset;
+ //endregion
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ return new ArrayBuffer(0);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "EndOfContentValueBlock";
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class EndOfContent extends BaseBlock {
+ //**********************************************************************************
+ constructor(paramaters = {}) {
+ super(paramaters, LocalEndOfContentValueBlock);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 0; // EndOfContent
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "EndOfContent";
+ }
+ //**********************************************************************************
+}
+exports.EndOfContent = EndOfContent; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 Boolean type class
+//**************************************************************************************
+
+class LocalBooleanValueBlock extends LocalValueBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalBooleanValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.value = (0, _pvutils.getParametersValue)(parameters, "value", false);
+ this.isHexOnly = (0, _pvutils.getParametersValue)(parameters, "isHexOnly", false);
+
+ if ("valueHex" in parameters) this.valueHex = parameters.valueHex.slice(0);else {
+ this.valueHex = new ArrayBuffer(1);
+ if (this.value === true) {
+ const view = new Uint8Array(this.valueHex);
+ view[0] = 0xFF;
+ }
+ }
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ if (inputLength > 1) this.warnings.push("Boolean value encoded in more then 1 octet");
+
+ this.isHexOnly = true;
+
+ //region Copy input buffer to internal array
+ this.valueHex = new ArrayBuffer(intBuffer.length);
+ const view = new Uint8Array(this.valueHex);
+
+ for (let i = 0; i < intBuffer.length; i++) view[i] = intBuffer[i];
+ //endregion
+
+ if (_pvutils.utilDecodeTC.call(this) !== 0) this.value = true;else this.value = false;
+
+ this.blockLength = inputLength;
+
+ return inputOffset + inputLength;
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ return this.valueHex;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "BooleanValueBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.value = this.value;
+ object.isHexOnly = this.isHexOnly;
+ object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class Boolean extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "Boolean" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalBooleanValueBlock);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 1; // Boolean
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Boolean";
+ }
+ //**********************************************************************************
+}
+exports.Boolean = Boolean; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 Sequence and Set type classes
+//**************************************************************************************
+
+class Sequence extends Constructed {
+ //**********************************************************************************
+ /**
+ * Constructor for "Sequence" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 16; // Sequence
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Sequence";
+ }
+ //**********************************************************************************
+}
+exports.Sequence = Sequence; //**************************************************************************************
+
+class Set extends Constructed {
+ //**********************************************************************************
+ /**
+ * Constructor for "Set" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 17; // Set
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Set";
+ }
+ //**********************************************************************************
+}
+exports.Set = Set; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 Null type class
+//**************************************************************************************
+
+class Null extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "Null" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalBaseBlock); // We will not have a call to "Null value block" because of specified "fromBER" and "toBER" functions
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 5; // Null
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Null";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedLocalSymbols
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ if (this.lenBlock.length > 0) this.warnings.push("Non-zero length of value block for Null type");
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ this.blockLength += inputLength;
+
+ if (inputOffset + inputLength > inputBuffer.byteLength) {
+ this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
+ return -1;
+ }
+
+ return inputOffset + inputLength;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ const retBuf = new ArrayBuffer(2);
+
+ if (sizeOnly === true) return retBuf;
+
+ const retView = new Uint8Array(retBuf);
+ retView[0] = 0x05;
+ retView[1] = 0x00;
+
+ return retBuf;
+ }
+ //**********************************************************************************
+}
+exports.Null = Null; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 OctetString type class
+//**************************************************************************************
+
+class LocalOctetStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalOctetStringValueBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.isConstructed = (0, _pvutils.getParametersValue)(parameters, "isConstructed", false);
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ let resultOffset = 0;
+
+ if (this.isConstructed === true) {
+ this.isHexOnly = false;
+
+ resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
+ if (resultOffset === -1) return resultOffset;
+
+ for (let i = 0; i < this.value.length; i++) {
+ const currentBlockName = this.value[i].constructor.blockName();
+
+ if (currentBlockName === EndOfContent.blockName()) {
+ if (this.isIndefiniteForm === true) break;else {
+ this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only";
+ return -1;
+ }
+ }
+
+ if (currentBlockName !== OctetString.blockName()) {
+ this.error = "OCTET STRING may consists of OCTET STRINGs only";
+ return -1;
+ }
+ }
+ } else {
+ this.isHexOnly = true;
+
+ resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
+ this.blockLength = inputLength;
+ }
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly);
+
+ let retBuf = new ArrayBuffer(this.valueHex.byteLength);
+
+ if (sizeOnly === true) return retBuf;
+
+ if (this.valueHex.byteLength === 0) return retBuf;
+
+ retBuf = this.valueHex.slice(0);
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "OctetStringValueBlock";
+ }
+ //**********************************************************************************
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.isConstructed = this.isConstructed;
+ object.isHexOnly = this.isHexOnly;
+ object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class OctetString extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "OctetString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalOctetStringValueBlock);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 4; // OctetString
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ this.valueBlock.isConstructed = this.idBlock.isConstructed;
+ this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
+
+ //region Ability to encode empty OCTET STRING
+ if (inputLength === 0) {
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ return inputOffset;
+ }
+ //endregion
+
+ return super.fromBER(inputBuffer, inputOffset, inputLength);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "OctetString";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Checking that two OCTETSTRINGs are equal
+ * @param {OctetString} octetString
+ */
+ isEqual(octetString) {
+ //region Check input type
+ if (octetString instanceof OctetString === false) return false;
+ //endregion
+
+ //region Compare two JSON strings
+ if (JSON.stringify(this) !== JSON.stringify(octetString)) return false;
+ //endregion
+
+ return true;
+ }
+ //**********************************************************************************
+}
+exports.OctetString = OctetString; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 BitString type class
+//**************************************************************************************
+
+class LocalBitStringValueBlock extends LocalHexBlock(LocalConstructedValueBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalBitStringValueBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.unusedBits = (0, _pvutils.getParametersValue)(parameters, "unusedBits", 0);
+ this.isConstructed = (0, _pvutils.getParametersValue)(parameters, "isConstructed", false);
+ this.blockLength = this.valueHex.byteLength;
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Ability to decode zero-length BitString value
+ if (inputLength === 0) return inputOffset;
+ //endregion
+
+ let resultOffset = -1;
+
+ //region If the BISTRING supposed to be a constructed value
+ if (this.isConstructed === true) {
+ resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
+ if (resultOffset === -1) return resultOffset;
+
+ for (let i = 0; i < this.value.length; i++) {
+ const currentBlockName = this.value[i].constructor.blockName();
+
+ if (currentBlockName === EndOfContent.blockName()) {
+ if (this.isIndefiniteForm === true) break;else {
+ this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only";
+ return -1;
+ }
+ }
+
+ if (currentBlockName !== BitString.blockName()) {
+ this.error = "BIT STRING may consists of BIT STRINGs only";
+ return -1;
+ }
+
+ if (this.unusedBits > 0 && this.value[i].valueBlock.unusedBits > 0) {
+ this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only";
+ return -1;
+ }
+
+ this.unusedBits = this.value[i].valueBlock.unusedBits;
+ if (this.unusedBits > 7) {
+ this.error = "Unused bits for BitString must be in range 0-7";
+ return -1;
+ }
+ }
+
+ return resultOffset;
+ }
+ //endregion
+ //region If the BitString supposed to be a primitive value
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+
+ this.unusedBits = intBuffer[0];
+
+ if (this.unusedBits > 7) {
+ this.error = "Unused bits for BitString must be in range 0-7";
+ return -1;
+ }
+
+ //region Copy input buffer to internal buffer
+ this.valueHex = new ArrayBuffer(intBuffer.length - 1);
+ const view = new Uint8Array(this.valueHex);
+ for (let i = 0; i < inputLength - 1; i++) view[i] = intBuffer[i + 1];
+ //endregion
+
+ this.blockLength = intBuffer.length;
+
+ return inputOffset + inputLength;
+ //endregion
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ if (this.isConstructed === true) return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly);
+
+ if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength + 1);
+
+ if (this.valueHex.byteLength === 0) return new ArrayBuffer(0);
+
+ const curView = new Uint8Array(this.valueHex);
+
+ const retBuf = new ArrayBuffer(this.valueHex.byteLength + 1);
+ const retView = new Uint8Array(retBuf);
+
+ retView[0] = this.unusedBits;
+
+ for (let i = 0; i < this.valueHex.byteLength; i++) retView[i + 1] = curView[i];
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "BitStringValueBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {{blockName, blockLength, error, warnings, valueBeforeDecode}|{blockName: string, blockLength: number, error: string, warnings: Array.<string>, valueBeforeDecode: string}}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.unusedBits = this.unusedBits;
+ object.isConstructed = this.isConstructed;
+ object.isHexOnly = this.isHexOnly;
+ object.valueHex = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class BitString extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "BitString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalBitStringValueBlock);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 3; // BitString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "BitString";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ //region Ability to encode empty BitString
+ if (inputLength === 0) return inputOffset;
+ //endregion
+
+ this.valueBlock.isConstructed = this.idBlock.isConstructed;
+ this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
+
+ return super.fromBER(inputBuffer, inputOffset, inputLength);
+ }
+ //**********************************************************************************
+ /**
+ * Checking that two BITSTRINGs are equal
+ * @param {BitString} bitString
+ */
+ isEqual(bitString) {
+ //region Check input type
+ if (bitString instanceof BitString === false) return false;
+ //endregion
+
+ //region Compare two JSON strings
+ if (JSON.stringify(this) !== JSON.stringify(bitString)) return false;
+ //endregion
+
+ return true;
+ }
+ //**********************************************************************************
+}
+exports.BitString = BitString; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 Integer type class
+//**************************************************************************************
+/**
+ * @extends LocalValueBlock
+ */
+
+class LocalIntegerValueBlock extends LocalHexBlock(LocalValueBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalIntegerValueBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ if ("value" in parameters) this.valueDec = parameters.value;
+ }
+ //**********************************************************************************
+ /**
+ * Setter for "valueHex"
+ * @param {ArrayBuffer} _value
+ */
+ set valueHex(_value) {
+ this._valueHex = _value.slice(0);
+
+ if (_value.byteLength >= 4) {
+ this.warnings.push("Too big Integer for decoding, hex only");
+ this.isHexOnly = true;
+ this._valueDec = 0;
+ } else {
+ this.isHexOnly = false;
+
+ if (_value.byteLength > 0) this._valueDec = _pvutils.utilDecodeTC.call(this);
+ }
+ }
+ //**********************************************************************************
+ /**
+ * Getter for "valueHex"
+ * @returns {ArrayBuffer}
+ */
+ get valueHex() {
+ return this._valueHex;
+ }
+ //**********************************************************************************
+ /**
+ * Getter for "valueDec"
+ * @param {number} _value
+ */
+ set valueDec(_value) {
+ this._valueDec = _value;
+
+ this.isHexOnly = false;
+ this._valueHex = (0, _pvutils.utilEncodeTC)(_value);
+ }
+ //**********************************************************************************
+ /**
+ * Getter for "valueDec"
+ * @returns {number}
+ */
+ get valueDec() {
+ return this._valueDec;
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from DER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 DER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 DER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @param {number} [expectedLength=0] Expected length of converted "valueHex" buffer
+ * @returns {number} Offset after least decoded byte
+ */
+ fromDER(inputBuffer, inputOffset, inputLength, expectedLength = 0) {
+ const offset = this.fromBER(inputBuffer, inputOffset, inputLength);
+ if (offset === -1) return offset;
+
+ const view = new Uint8Array(this._valueHex);
+
+ if (view[0] === 0x00 && (view[1] & 0x80) !== 0) {
+ const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1);
+ const updatedView = new Uint8Array(updatedValueHex);
+
+ updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1));
+
+ this._valueHex = updatedValueHex.slice(0);
+ } else {
+ if (expectedLength !== 0) {
+ if (this._valueHex.byteLength < expectedLength) {
+ if (expectedLength - this._valueHex.byteLength > 1) expectedLength = this._valueHex.byteLength + 1;
+
+ const updatedValueHex = new ArrayBuffer(expectedLength);
+ const updatedView = new Uint8Array(updatedValueHex);
+
+ updatedView.set(view, expectedLength - this._valueHex.byteLength);
+
+ this._valueHex = updatedValueHex.slice(0);
+ }
+ }
+ }
+
+ return offset;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (DER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toDER(sizeOnly = false) {
+ const view = new Uint8Array(this._valueHex);
+
+ switch (true) {
+ case (view[0] & 0x80) !== 0:
+ {
+ const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength + 1);
+ const updatedView = new Uint8Array(updatedValueHex);
+
+ updatedView[0] = 0x00;
+ updatedView.set(view, 1);
+
+ this._valueHex = updatedValueHex.slice(0);
+ }
+ break;
+ case view[0] === 0x00 && (view[1] & 0x80) === 0:
+ {
+ const updatedValueHex = new ArrayBuffer(this._valueHex.byteLength - 1);
+ const updatedView = new Uint8Array(updatedValueHex);
+
+ updatedView.set(new Uint8Array(this._valueHex, 1, this._valueHex.byteLength - 1));
+
+ this._valueHex = updatedValueHex.slice(0);
+ }
+ break;
+ default:
+ }
+
+ return this.toBER(sizeOnly);
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
+ if (resultOffset === -1) return resultOffset;
+
+ this.blockLength = inputLength;
+
+ return inputOffset + inputLength;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ //noinspection JSCheckFunctionSignatures
+ return this.valueHex.slice(0);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "IntegerValueBlock";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.valueDec = this.valueDec;
+
+ return object;
+ }
+ //**********************************************************************************
+ /**
+ * Convert current value to decimal string representation
+ */
+ toString() {
+ //region Aux functions
+ function viewAdd(first, second) {
+ //region Initial variables
+ const c = new Uint8Array([0]);
+
+ let firstView = new Uint8Array(first);
+ let secondView = new Uint8Array(second);
+
+ let firstViewCopy = firstView.slice(0);
+ const firstViewCopyLength = firstViewCopy.length - 1;
+ let secondViewCopy = secondView.slice(0);
+ const secondViewCopyLength = secondViewCopy.length - 1;
+
+ let value = 0;
+
+ const max = secondViewCopyLength < firstViewCopyLength ? firstViewCopyLength : secondViewCopyLength;
+
+ let counter = 0;
+ //endregion
+
+ for (let i = max; i >= 0; i--, counter++) {
+ switch (true) {
+ case counter < secondViewCopy.length:
+ value = firstViewCopy[firstViewCopyLength - counter] + secondViewCopy[secondViewCopyLength - counter] + c[0];
+ break;
+ default:
+ value = firstViewCopy[firstViewCopyLength - counter] + c[0];
+ }
+
+ c[0] = value / 10;
+
+ switch (true) {
+ case counter >= firstViewCopy.length:
+ firstViewCopy = (0, _pvutils.utilConcatView)(new Uint8Array([value % 10]), firstViewCopy);
+ break;
+ default:
+ firstViewCopy[firstViewCopyLength - counter] = value % 10;
+ }
+ }
+
+ if (c[0] > 0) firstViewCopy = (0, _pvutils.utilConcatView)(c, firstViewCopy);
+
+ return firstViewCopy.slice(0);
+ }
+
+ function power2(n) {
+ if (n >= powers2.length) {
+ for (let p = powers2.length; p <= n; p++) {
+ const c = new Uint8Array([0]);
+ let digits = powers2[p - 1].slice(0);
+
+ for (let i = digits.length - 1; i >= 0; i--) {
+ const newValue = new Uint8Array([(digits[i] << 1) + c[0]]);
+ c[0] = newValue[0] / 10;
+ digits[i] = newValue[0] % 10;
+ }
+
+ if (c[0] > 0) digits = (0, _pvutils.utilConcatView)(c, digits);
+
+ powers2.push(digits);
+ }
+ }
+
+ return powers2[n];
+ }
+
+ function viewSub(first, second) {
+ //region Initial variables
+ let b = 0;
+
+ let firstView = new Uint8Array(first);
+ let secondView = new Uint8Array(second);
+
+ let firstViewCopy = firstView.slice(0);
+ const firstViewCopyLength = firstViewCopy.length - 1;
+ let secondViewCopy = secondView.slice(0);
+ const secondViewCopyLength = secondViewCopy.length - 1;
+
+ let value;
+
+ let counter = 0;
+ //endregion
+
+ for (let i = secondViewCopyLength; i >= 0; i--, counter++) {
+ value = firstViewCopy[firstViewCopyLength - counter] - secondViewCopy[secondViewCopyLength - counter] - b;
+
+ switch (true) {
+ case value < 0:
+ b = 1;
+ firstViewCopy[firstViewCopyLength - counter] = value + 10;
+ break;
+ default:
+ b = 0;
+ firstViewCopy[firstViewCopyLength - counter] = value;
+ }
+ }
+
+ if (b > 0) {
+ for (let i = firstViewCopyLength - secondViewCopyLength + 1; i >= 0; i--, counter++) {
+ value = firstViewCopy[firstViewCopyLength - counter] - b;
+
+ if (value < 0) {
+ b = 1;
+ firstViewCopy[firstViewCopyLength - counter] = value + 10;
+ } else {
+ b = 0;
+ firstViewCopy[firstViewCopyLength - counter] = value;
+ break;
+ }
+ }
+ }
+
+ return firstViewCopy.slice();
+ }
+ //endregion
+
+ //region Initial variables
+ const firstBit = this._valueHex.byteLength * 8 - 1;
+
+ let digits = new Uint8Array(this._valueHex.byteLength * 8 / 3);
+ let bitNumber = 0;
+ let currentByte;
+
+ const asn1View = new Uint8Array(this._valueHex);
+
+ let result = "";
+
+ let flag = false;
+ //endregion
+
+ //region Calculate number
+ for (let byteNumber = this._valueHex.byteLength - 1; byteNumber >= 0; byteNumber--) {
+ currentByte = asn1View[byteNumber];
+
+ for (let i = 0; i < 8; i++) {
+ if ((currentByte & 1) === 1) {
+ switch (bitNumber) {
+ case firstBit:
+ digits = viewSub(power2(bitNumber), digits);
+ result = "-";
+ break;
+ default:
+ digits = viewAdd(digits, power2(bitNumber));
+ }
+ }
+
+ bitNumber++;
+ currentByte >>= 1;
+ }
+ }
+ //endregion
+
+ //region Print number
+ for (let i = 0; i < digits.length; i++) {
+ if (digits[i]) flag = true;
+
+ if (flag) result += digitsString.charAt(digits[i]);
+ }
+
+ if (flag === false) result += digitsString.charAt(0);
+ //endregion
+
+ return result;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class Integer extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "Integer" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalIntegerValueBlock);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 2; // Integer
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Integer";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Compare two Integer object, or Integer and ArrayBuffer objects
+ * @param {!Integer|ArrayBuffer} otherValue
+ * @returns {boolean}
+ */
+ isEqual(otherValue) {
+ if (otherValue instanceof Integer) {
+ if (this.valueBlock.isHexOnly && otherValue.valueBlock.isHexOnly) // Compare two ArrayBuffers
+ return (0, _pvutils.isEqualBuffer)(this.valueBlock.valueHex, otherValue.valueBlock.valueHex);
+
+ if (this.valueBlock.isHexOnly === otherValue.valueBlock.isHexOnly) return this.valueBlock.valueDec === otherValue.valueBlock.valueDec;
+
+ return false;
+ }
+
+ if (otherValue instanceof ArrayBuffer) return (0, _pvutils.isEqualBuffer)(this.valueBlock.valueHex, otherValue);
+
+ return false;
+ }
+ //**********************************************************************************
+ /**
+ * Convert current Integer value from BER into DER format
+ * @returns {Integer}
+ */
+ convertToDER() {
+ const integer = new Integer({ valueHex: this.valueBlock.valueHex });
+ integer.valueBlock.toDER();
+
+ return integer;
+ }
+ //**********************************************************************************
+ /**
+ * Convert current Integer value from DER to BER format
+ * @returns {Integer}
+ */
+ convertFromDER() {
+ const expectedLength = this.valueBlock.valueHex.byteLength % 2 ? this.valueBlock.valueHex.byteLength + 1 : this.valueBlock.valueHex.byteLength;
+ const integer = new Integer({ valueHex: this.valueBlock.valueHex });
+ integer.valueBlock.fromDER(integer.valueBlock.valueHex, 0, integer.valueBlock.valueHex.byteLength, expectedLength);
+
+ return integer;
+ }
+ //**********************************************************************************
+}
+exports.Integer = Integer; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 Enumerated type class
+//**************************************************************************************
+
+class Enumerated extends Integer {
+ //**********************************************************************************
+ /**
+ * Constructor for "Enumerated" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 10; // Enumerated
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Enumerated";
+ }
+ //**********************************************************************************
+}
+exports.Enumerated = Enumerated; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of ASN.1 ObjectIdentifier type class
+//**************************************************************************************
+
+class LocalSidValueBlock extends LocalHexBlock(LocalBaseBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalSidValueBlock" class
+ * @param {Object} [parameters={}]
+ * @property {number} [valueDec]
+ * @property {boolean} [isFirstSid]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.valueDec = (0, _pvutils.getParametersValue)(parameters, "valueDec", -1);
+ this.isFirstSid = (0, _pvutils.getParametersValue)(parameters, "isFirstSid", false);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "sidBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ if (inputLength === 0) return inputOffset;
+
+ //region Basic check for parameters
+ //noinspection JSCheckFunctionSignatures
+ if ((0, _pvutils.checkBufferParams)(this, inputBuffer, inputOffset, inputLength) === false) return -1;
+ //endregion
+
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+
+ this.valueHex = new ArrayBuffer(inputLength);
+ let view = new Uint8Array(this.valueHex);
+
+ for (let i = 0; i < inputLength; i++) {
+ view[i] = intBuffer[i] & 0x7F;
+
+ this.blockLength++;
+
+ if ((intBuffer[i] & 0x80) === 0x00) break;
+ }
+
+ //region Ajust size of valueHex buffer
+ const tempValueHex = new ArrayBuffer(this.blockLength);
+ const tempView = new Uint8Array(tempValueHex);
+
+ for (let i = 0; i < this.blockLength; i++) tempView[i] = view[i];
+
+ //noinspection JSCheckFunctionSignatures
+ this.valueHex = tempValueHex.slice(0);
+ view = new Uint8Array(this.valueHex);
+ //endregion
+
+ if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) {
+ this.error = "End of input reached before message was fully decoded";
+ return -1;
+ }
+
+ if (view[0] === 0x00) this.warnings.push("Needlessly long format of SID encoding");
+
+ if (this.blockLength <= 8) this.valueDec = (0, _pvutils.utilFromBase)(view, 7);else {
+ this.isHexOnly = true;
+ this.warnings.push("Too big SID for decoding, hex only");
+ }
+
+ return inputOffset + this.blockLength;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ //region Initial variables
+ let retBuf;
+ let retView;
+ //endregion
+
+ if (this.isHexOnly) {
+ if (sizeOnly === true) return new ArrayBuffer(this.valueHex.byteLength);
+
+ const curView = new Uint8Array(this.valueHex);
+
+ retBuf = new ArrayBuffer(this.blockLength);
+ retView = new Uint8Array(retBuf);
+
+ for (let i = 0; i < this.blockLength - 1; i++) retView[i] = curView[i] | 0x80;
+
+ retView[this.blockLength - 1] = curView[this.blockLength - 1];
+
+ return retBuf;
+ }
+
+ const encodedBuf = (0, _pvutils.utilToBase)(this.valueDec, 7);
+ if (encodedBuf.byteLength === 0) {
+ this.error = "Error during encoding SID value";
+ return new ArrayBuffer(0);
+ }
+
+ retBuf = new ArrayBuffer(encodedBuf.byteLength);
+
+ if (sizeOnly === false) {
+ const encodedView = new Uint8Array(encodedBuf);
+ retView = new Uint8Array(retBuf);
+
+ for (let i = 0; i < encodedBuf.byteLength - 1; i++) retView[i] = encodedView[i] | 0x80;
+
+ retView[encodedBuf.byteLength - 1] = encodedView[encodedBuf.byteLength - 1];
+ }
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Create string representation of current SID block
+ * @returns {string}
+ */
+ toString() {
+ let result = "";
+
+ if (this.isHexOnly === true) result = (0, _pvutils.bufferToHexCodes)(this.valueHex, 0, this.valueHex.byteLength);else {
+ if (this.isFirstSid) {
+ let sidValue = this.valueDec;
+
+ if (this.valueDec <= 39) result = "0.";else {
+ if (this.valueDec <= 79) {
+ result = "1.";
+ sidValue -= 40;
+ } else {
+ result = "2.";
+ sidValue -= 80;
+ }
+ }
+
+ result += sidValue.toString();
+ } else result = this.valueDec.toString();
+ }
+
+ return result;
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.valueDec = this.valueDec;
+ object.isFirstSid = this.isFirstSid;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+class LocalObjectIdentifierValueBlock extends LocalValueBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalObjectIdentifierValueBlock" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.fromString((0, _pvutils.getParametersValue)(parameters, "value", ""));
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ let resultOffset = inputOffset;
+
+ while (inputLength > 0) {
+ const sidBlock = new LocalSidValueBlock();
+ resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength);
+ if (resultOffset === -1) {
+ this.blockLength = 0;
+ this.error = sidBlock.error;
+ return resultOffset;
+ }
+
+ if (this.value.length === 0) sidBlock.isFirstSid = true;
+
+ this.blockLength += sidBlock.blockLength;
+ inputLength -= sidBlock.blockLength;
+
+ this.value.push(sidBlock);
+ }
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ let retBuf = new ArrayBuffer(0);
+
+ for (let i = 0; i < this.value.length; i++) {
+ const valueBuf = this.value[i].toBER(sizeOnly);
+ if (valueBuf.byteLength === 0) {
+ this.error = this.value[i].error;
+ return new ArrayBuffer(0);
+ }
+
+ retBuf = (0, _pvutils.utilConcatBuf)(retBuf, valueBuf);
+ }
+
+ return retBuf;
+ }
+ //**********************************************************************************
+ /**
+ * Create "LocalObjectIdentifierValueBlock" class from string
+ * @param {string} string Input string to convert from
+ * @returns {boolean}
+ */
+ fromString(string) {
+ this.value = []; // Clear existing SID values
+
+ let pos1 = 0;
+ let pos2 = 0;
+
+ let sid = "";
+
+ let flag = false;
+
+ do {
+ pos2 = string.indexOf(".", pos1);
+ if (pos2 === -1) sid = string.substr(pos1);else sid = string.substr(pos1, pos2 - pos1);
+
+ pos1 = pos2 + 1;
+
+ if (flag) {
+ const sidBlock = this.value[0];
+
+ let plus = 0;
+
+ switch (sidBlock.valueDec) {
+ case 0:
+ break;
+ case 1:
+ plus = 40;
+ break;
+ case 2:
+ plus = 80;
+ break;
+ default:
+ this.value = []; // clear SID array
+ return false; // ???
+ }
+
+ const parsedSID = parseInt(sid, 10);
+ if (isNaN(parsedSID)) return true;
+
+ sidBlock.valueDec = parsedSID + plus;
+
+ flag = false;
+ } else {
+ const sidBlock = new LocalSidValueBlock();
+ sidBlock.valueDec = parseInt(sid, 10);
+ if (isNaN(sidBlock.valueDec)) return true;
+
+ if (this.value.length === 0) {
+ sidBlock.isFirstSid = true;
+ flag = true;
+ }
+
+ this.value.push(sidBlock);
+ }
+ } while (pos2 !== -1);
+
+ return true;
+ }
+ //**********************************************************************************
+ /**
+ * Converts "LocalObjectIdentifierValueBlock" class to string
+ * @returns {string}
+ */
+ toString() {
+ let result = "";
+ let isHexOnly = false;
+
+ for (let i = 0; i < this.value.length; i++) {
+ isHexOnly = this.value[i].isHexOnly;
+
+ let sidStr = this.value[i].toString();
+
+ if (i !== 0) result = `${result}.`;
+
+ if (isHexOnly) {
+ sidStr = `{${sidStr}}`;
+
+ if (this.value[i].isFirstSid) result = `2.{${sidStr} - 80}`;else result += sidStr;
+ } else result += sidStr;
+ }
+
+ return result;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "ObjectIdentifierValueBlock";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.value = this.toString();
+ object.sidArray = [];
+ for (let i = 0; i < this.value.length; i++) object.sidArray.push(this.value[i].toJSON());
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+/**
+ * @extends BaseBlock
+ */
+class ObjectIdentifier extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "ObjectIdentifier" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalObjectIdentifierValueBlock);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "ObjectIdentifier";
+ }
+ //**********************************************************************************
+}
+exports.ObjectIdentifier = ObjectIdentifier; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of all string's classes
+//**************************************************************************************
+
+class LocalUtf8StringValueBlock extends LocalHexBlock(LocalBaseBlock) {
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Constructor for "LocalUtf8StringValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.isHexOnly = true;
+ this.value = ""; // String representation of decoded ArrayBuffer
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Utf8StringValueBlock";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.value = this.value;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+/**
+ * @extends BaseBlock
+ */
+class Utf8String extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "Utf8String" class
+ * @param {Object} [parameters={}]
+ * @property {ArrayBuffer} [valueHex]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalUtf8StringValueBlock);
+
+ if ("value" in parameters) this.fromString(parameters.value);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 12; // Utf8String
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Utf8String";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ this.fromBuffer(this.valueBlock.valueHex);
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ArrayBuffer into ASN.1 internal string
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ */
+ fromBuffer(inputBuffer) {
+ this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer));
+
+ try {
+ //noinspection JSDeprecatedSymbols
+ this.valueBlock.value = decodeURIComponent(escape(this.valueBlock.value));
+ } catch (ex) {
+ this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`);
+ }
+ }
+ //**********************************************************************************
+ /**
+ * Function converting JavaScript string into ASN.1 internal class
+ * @param {!string} inputString ASN.1 BER encoded array
+ */
+ fromString(inputString) {
+ //noinspection JSDeprecatedSymbols
+ const str = unescape(encodeURIComponent(inputString));
+ const strLen = str.length;
+
+ this.valueBlock.valueHex = new ArrayBuffer(strLen);
+ const view = new Uint8Array(this.valueBlock.valueHex);
+
+ for (let i = 0; i < strLen; i++) view[i] = str.charCodeAt(i);
+
+ this.valueBlock.value = inputString;
+ }
+ //**********************************************************************************
+}
+exports.Utf8String = Utf8String; //**************************************************************************************
+/**
+ * @extends LocalBaseBlock
+ * @extends LocalHexBlock
+ */
+
+class LocalBmpStringValueBlock extends LocalHexBlock(LocalBaseBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalBmpStringValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.isHexOnly = true;
+ this.value = "";
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "BmpStringValueBlock";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.value = this.value;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+/**
+ * @extends BaseBlock
+ */
+class BmpString extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "BmpString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalBmpStringValueBlock);
+
+ if ("value" in parameters) this.fromString(parameters.value);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 30; // BmpString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "BmpString";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ this.fromBuffer(this.valueBlock.valueHex);
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ArrayBuffer into ASN.1 internal string
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ */
+ fromBuffer(inputBuffer) {
+ //noinspection JSCheckFunctionSignatures
+ const copyBuffer = inputBuffer.slice(0);
+ const valueView = new Uint8Array(copyBuffer);
+
+ for (let i = 0; i < valueView.length; i += 2) {
+ const temp = valueView[i];
+
+ valueView[i] = valueView[i + 1];
+ valueView[i + 1] = temp;
+ }
+
+ this.valueBlock.value = String.fromCharCode.apply(null, new Uint16Array(copyBuffer));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting JavaScript string into ASN.1 internal class
+ * @param {!string} inputString ASN.1 BER encoded array
+ */
+ fromString(inputString) {
+ const strLength = inputString.length;
+
+ this.valueBlock.valueHex = new ArrayBuffer(strLength * 2);
+ const valueHexView = new Uint8Array(this.valueBlock.valueHex);
+
+ for (let i = 0; i < strLength; i++) {
+ const codeBuf = (0, _pvutils.utilToBase)(inputString.charCodeAt(i), 8);
+ const codeView = new Uint8Array(codeBuf);
+ if (codeView.length > 2) continue;
+
+ const dif = 2 - codeView.length;
+
+ for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 2 + j + dif] = codeView[j];
+ }
+
+ this.valueBlock.value = inputString;
+ }
+ //**********************************************************************************
+}
+exports.BmpString = BmpString; //**************************************************************************************
+
+class LocalUniversalStringValueBlock extends LocalHexBlock(LocalBaseBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalUniversalStringValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.isHexOnly = true;
+ this.value = "";
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "UniversalStringValueBlock";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.value = this.value;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+/**
+ * @extends BaseBlock
+ */
+class UniversalString extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "UniversalString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalUniversalStringValueBlock);
+
+ if ("value" in parameters) this.fromString(parameters.value);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 28; // UniversalString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "UniversalString";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ this.fromBuffer(this.valueBlock.valueHex);
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ArrayBuffer into ASN.1 internal string
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ */
+ fromBuffer(inputBuffer) {
+ //noinspection JSCheckFunctionSignatures
+ const copyBuffer = inputBuffer.slice(0);
+ const valueView = new Uint8Array(copyBuffer);
+
+ for (let i = 0; i < valueView.length; i += 4) {
+ valueView[i] = valueView[i + 3];
+ valueView[i + 1] = valueView[i + 2];
+ valueView[i + 2] = 0x00;
+ valueView[i + 3] = 0x00;
+ }
+
+ this.valueBlock.value = String.fromCharCode.apply(null, new Uint32Array(copyBuffer));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting JavaScript string into ASN.1 internal class
+ * @param {!string} inputString ASN.1 BER encoded array
+ */
+ fromString(inputString) {
+ const strLength = inputString.length;
+
+ this.valueBlock.valueHex = new ArrayBuffer(strLength * 4);
+ const valueHexView = new Uint8Array(this.valueBlock.valueHex);
+
+ for (let i = 0; i < strLength; i++) {
+ const codeBuf = (0, _pvutils.utilToBase)(inputString.charCodeAt(i), 8);
+ const codeView = new Uint8Array(codeBuf);
+ if (codeView.length > 4) continue;
+
+ const dif = 4 - codeView.length;
+
+ for (let j = codeView.length - 1; j >= 0; j--) valueHexView[i * 4 + j + dif] = codeView[j];
+ }
+
+ this.valueBlock.value = inputString;
+ }
+ //**********************************************************************************
+}
+exports.UniversalString = UniversalString; //**************************************************************************************
+
+class LocalSimpleStringValueBlock extends LocalHexBlock(LocalBaseBlock) {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalSimpleStringValueBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.value = "";
+ this.isHexOnly = true;
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "SimpleStringValueBlock";
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.value = this.value;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+/**
+ * @extends BaseBlock
+ */
+class LocalSimpleStringBlock extends BaseBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "LocalSimpleStringBlock" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters, LocalSimpleStringValueBlock);
+
+ if ("value" in parameters) this.fromString(parameters.value);
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "SIMPLESTRING";
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ this.fromBuffer(this.valueBlock.valueHex);
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ArrayBuffer into ASN.1 internal string
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ */
+ fromBuffer(inputBuffer) {
+ this.valueBlock.value = String.fromCharCode.apply(null, new Uint8Array(inputBuffer));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting JavaScript string into ASN.1 internal class
+ * @param {!string} inputString ASN.1 BER encoded array
+ */
+ fromString(inputString) {
+ const strLen = inputString.length;
+
+ this.valueBlock.valueHex = new ArrayBuffer(strLen);
+ const view = new Uint8Array(this.valueBlock.valueHex);
+
+ for (let i = 0; i < strLen; i++) view[i] = inputString.charCodeAt(i);
+
+ this.valueBlock.value = inputString;
+ }
+ //**********************************************************************************
+}
+//**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+class NumericString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "NumericString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 18; // NumericString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "NumericString";
+ }
+ //**********************************************************************************
+}
+exports.NumericString = NumericString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class PrintableString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "PrintableString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 19; // PrintableString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "PrintableString";
+ }
+ //**********************************************************************************
+}
+exports.PrintableString = PrintableString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class TeletexString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "TeletexString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 20; // TeletexString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "TeletexString";
+ }
+ //**********************************************************************************
+}
+exports.TeletexString = TeletexString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class VideotexString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "VideotexString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 21; // VideotexString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "VideotexString";
+ }
+ //**********************************************************************************
+}
+exports.VideotexString = VideotexString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class IA5String extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "IA5String" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 22; // IA5String
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "IA5String";
+ }
+ //**********************************************************************************
+}
+exports.IA5String = IA5String; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class GraphicString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "GraphicString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 25; // GraphicString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "GraphicString";
+ }
+ //**********************************************************************************
+}
+exports.GraphicString = GraphicString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class VisibleString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "VisibleString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 26; // VisibleString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "VisibleString";
+ }
+ //**********************************************************************************
+}
+exports.VisibleString = VisibleString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class GeneralString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "GeneralString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 27; // GeneralString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "GeneralString";
+ }
+ //**********************************************************************************
+}
+exports.GeneralString = GeneralString; //**************************************************************************************
+/**
+ * @extends LocalSimpleStringBlock
+ */
+
+class CharacterString extends LocalSimpleStringBlock {
+ //**********************************************************************************
+ /**
+ * Constructor for "CharacterString" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 29; // CharacterString
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "CharacterString";
+ }
+ //**********************************************************************************
+}
+exports.CharacterString = CharacterString; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of all date and time classes
+//**************************************************************************************
+/**
+ * @extends VisibleString
+ */
+
+class UTCTime extends VisibleString {
+ //**********************************************************************************
+ /**
+ * Constructor for "UTCTime" class
+ * @param {Object} [parameters={}]
+ * @property {string} [value] String representatio of the date
+ * @property {Date} [valueDate] JavaScript "Date" object
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+ this.hour = 0;
+ this.minute = 0;
+ this.second = 0;
+
+ //region Create UTCTime from ASN.1 UTC string value
+ if ("value" in parameters) {
+ this.fromString(parameters.value);
+
+ this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length);
+ const view = new Uint8Array(this.valueBlock.valueHex);
+
+ for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i);
+ }
+ //endregion
+ //region Create GeneralizedTime from JavaScript Date type
+ if ("valueDate" in parameters) {
+ this.fromDate(parameters.valueDate);
+ this.valueBlock.valueHex = this.toBuffer();
+ }
+ //endregion
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 23; // UTCTime
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ this.fromBuffer(this.valueBlock.valueHex);
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ArrayBuffer into ASN.1 internal string
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ */
+ fromBuffer(inputBuffer) {
+ this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer)));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ASN.1 internal string into ArrayBuffer
+ * @returns {ArrayBuffer}
+ */
+ toBuffer() {
+ const str = this.toString();
+
+ const buffer = new ArrayBuffer(str.length);
+ const view = new Uint8Array(buffer);
+
+ for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i);
+
+ return buffer;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting "Date" object into ASN.1 internal string
+ * @param {!Date} inputDate JavaScript "Date" object
+ */
+ fromDate(inputDate) {
+ this.year = inputDate.getUTCFullYear();
+ this.month = inputDate.getUTCMonth() + 1;
+ this.day = inputDate.getUTCDate();
+ this.hour = inputDate.getUTCHours();
+ this.minute = inputDate.getUTCMinutes();
+ this.second = inputDate.getUTCSeconds();
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Function converting ASN.1 internal string into "Date" object
+ * @returns {Date}
+ */
+ toDate() {
+ return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting JavaScript string into ASN.1 internal class
+ * @param {!string} inputString ASN.1 BER encoded array
+ */
+ fromString(inputString) {
+ //region Parse input string
+ const parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig;
+ const parserArray = parser.exec(inputString);
+ if (parserArray === null) {
+ this.error = "Wrong input string for convertion";
+ return;
+ }
+ //endregion
+
+ //region Store parsed values
+ const year = parseInt(parserArray[1], 10);
+ if (year >= 50) this.year = 1900 + year;else this.year = 2000 + year;
+
+ this.month = parseInt(parserArray[2], 10);
+ this.day = parseInt(parserArray[3], 10);
+ this.hour = parseInt(parserArray[4], 10);
+ this.minute = parseInt(parserArray[5], 10);
+ this.second = parseInt(parserArray[6], 10);
+ //endregion
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ASN.1 internal class into JavaScript string
+ * @returns {string}
+ */
+ toString() {
+ const outputArray = new Array(7);
+
+ outputArray[0] = (0, _pvutils.padNumber)(this.year < 2000 ? this.year - 1900 : this.year - 2000, 2);
+ outputArray[1] = (0, _pvutils.padNumber)(this.month, 2);
+ outputArray[2] = (0, _pvutils.padNumber)(this.day, 2);
+ outputArray[3] = (0, _pvutils.padNumber)(this.hour, 2);
+ outputArray[4] = (0, _pvutils.padNumber)(this.minute, 2);
+ outputArray[5] = (0, _pvutils.padNumber)(this.second, 2);
+ outputArray[6] = "Z";
+
+ return outputArray.join("");
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "UTCTime";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.year = this.year;
+ object.month = this.month;
+ object.day = this.day;
+ object.hour = this.hour;
+ object.minute = this.minute;
+ object.second = this.second;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+exports.UTCTime = UTCTime; //**************************************************************************************
+/**
+ * @extends VisibleString
+ */
+
+class GeneralizedTime extends VisibleString {
+ //**********************************************************************************
+ /**
+ * Constructor for "GeneralizedTime" class
+ * @param {Object} [parameters={}]
+ * @property {string} [value] String representatio of the date
+ * @property {Date} [valueDate] JavaScript "Date" object
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+ this.hour = 0;
+ this.minute = 0;
+ this.second = 0;
+ this.millisecond = 0;
+
+ //region Create UTCTime from ASN.1 UTC string value
+ if ("value" in parameters) {
+ this.fromString(parameters.value);
+
+ this.valueBlock.valueHex = new ArrayBuffer(parameters.value.length);
+ const view = new Uint8Array(this.valueBlock.valueHex);
+
+ for (let i = 0; i < parameters.value.length; i++) view[i] = parameters.value.charCodeAt(i);
+ }
+ //endregion
+ //region Create GeneralizedTime from JavaScript Date type
+ if ("valueDate" in parameters) {
+ this.fromDate(parameters.valueDate);
+ this.valueBlock.valueHex = this.toBuffer();
+ }
+ //endregion
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 24; // GeneralizedTime
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, this.lenBlock.isIndefiniteForm === true ? inputLength : this.lenBlock.length);
+ if (resultOffset === -1) {
+ this.error = this.valueBlock.error;
+ return resultOffset;
+ }
+
+ this.fromBuffer(this.valueBlock.valueHex);
+
+ if (this.idBlock.error.length === 0) this.blockLength += this.idBlock.blockLength;
+
+ if (this.lenBlock.error.length === 0) this.blockLength += this.lenBlock.blockLength;
+
+ if (this.valueBlock.error.length === 0) this.blockLength += this.valueBlock.blockLength;
+
+ return resultOffset;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ArrayBuffer into ASN.1 internal string
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ */
+ fromBuffer(inputBuffer) {
+ this.fromString(String.fromCharCode.apply(null, new Uint8Array(inputBuffer)));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ASN.1 internal string into ArrayBuffer
+ * @returns {ArrayBuffer}
+ */
+ toBuffer() {
+ const str = this.toString();
+
+ const buffer = new ArrayBuffer(str.length);
+ const view = new Uint8Array(buffer);
+
+ for (let i = 0; i < str.length; i++) view[i] = str.charCodeAt(i);
+
+ return buffer;
+ }
+ //**********************************************************************************
+ /**
+ * Function converting "Date" object into ASN.1 internal string
+ * @param {!Date} inputDate JavaScript "Date" object
+ */
+ fromDate(inputDate) {
+ this.year = inputDate.getUTCFullYear();
+ this.month = inputDate.getUTCMonth() + 1;
+ this.day = inputDate.getUTCDate();
+ this.hour = inputDate.getUTCHours();
+ this.minute = inputDate.getUTCMinutes();
+ this.second = inputDate.getUTCSeconds();
+ this.millisecond = inputDate.getUTCMilliseconds();
+ }
+ //**********************************************************************************
+ //noinspection JSUnusedGlobalSymbols
+ /**
+ * Function converting ASN.1 internal string into "Date" object
+ * @returns {Date}
+ */
+ toDate() {
+ return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond));
+ }
+ //**********************************************************************************
+ /**
+ * Function converting JavaScript string into ASN.1 internal class
+ * @param {!string} inputString ASN.1 BER encoded array
+ */
+ fromString(inputString) {
+ //region Initial variables
+ let isUTC = false;
+
+ let timeString = "";
+ let dateTimeString = "";
+ let fractionPart = 0;
+
+ let parser;
+
+ let hourDifference = 0;
+ let minuteDifference = 0;
+ //endregion
+
+ //region Convert as UTC time
+ if (inputString[inputString.length - 1] === "Z") {
+ timeString = inputString.substr(0, inputString.length - 1);
+
+ isUTC = true;
+ }
+ //endregion
+ //region Convert as local time
+ else {
+ //noinspection JSPrimitiveTypeWrapperUsage
+ const number = new Number(inputString[inputString.length - 1]);
+
+ if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion");
+
+ timeString = inputString;
+ }
+ //endregion
+
+ //region Check that we do not have a "+" and "-" symbols inside UTC time
+ if (isUTC) {
+ if (timeString.indexOf("+") !== -1) throw new Error("Wrong input string for convertion");
+
+ if (timeString.indexOf("-") !== -1) throw new Error("Wrong input string for convertion");
+ }
+ //endregion
+ //region Get "UTC time difference" in case of local time
+ else {
+ let multiplier = 1;
+ let differencePosition = timeString.indexOf("+");
+ let differenceString = "";
+
+ if (differencePosition === -1) {
+ differencePosition = timeString.indexOf("-");
+ multiplier = -1;
+ }
+
+ if (differencePosition !== -1) {
+ differenceString = timeString.substr(differencePosition + 1);
+ timeString = timeString.substr(0, differencePosition);
+
+ if (differenceString.length !== 2 && differenceString.length !== 4) throw new Error("Wrong input string for convertion");
+
+ //noinspection JSPrimitiveTypeWrapperUsage
+ let number = new Number(differenceString.substr(0, 2));
+
+ if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion");
+
+ hourDifference = multiplier * number;
+
+ if (differenceString.length === 4) {
+ //noinspection JSPrimitiveTypeWrapperUsage
+ number = new Number(differenceString.substr(2, 2));
+
+ if (isNaN(number.valueOf())) throw new Error("Wrong input string for convertion");
+
+ minuteDifference = multiplier * number;
+ }
+ }
+ }
+ //endregion
+
+ //region Get position of fraction point
+ let fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol
+ if (fractionPointPosition === -1) fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol
+ //endregion
+
+ //region Get fraction part
+ if (fractionPointPosition !== -1) {
+ //noinspection JSPrimitiveTypeWrapperUsage
+ const fractionPartCheck = new Number(`0${timeString.substr(fractionPointPosition)}`);
+
+ if (isNaN(fractionPartCheck.valueOf())) throw new Error("Wrong input string for convertion");
+
+ fractionPart = fractionPartCheck.valueOf();
+
+ dateTimeString = timeString.substr(0, fractionPointPosition);
+ } else dateTimeString = timeString;
+ //endregion
+
+ //region Parse internal date
+ switch (true) {
+ case dateTimeString.length === 8:
+ // "YYYYMMDD"
+ parser = /(\d{4})(\d{2})(\d{2})/ig;
+ if (fractionPointPosition !== -1) throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point"
+ break;
+ case dateTimeString.length === 10:
+ // "YYYYMMDDHH"
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig;
+
+ if (fractionPointPosition !== -1) {
+ let fractionResult = 60 * fractionPart;
+ this.minute = Math.floor(fractionResult);
+
+ fractionResult = 60 * (fractionResult - this.minute);
+ this.second = Math.floor(fractionResult);
+
+ fractionResult = 1000 * (fractionResult - this.second);
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ case dateTimeString.length === 12:
+ // "YYYYMMDDHHMM"
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
+
+ if (fractionPointPosition !== -1) {
+ let fractionResult = 60 * fractionPart;
+ this.second = Math.floor(fractionResult);
+
+ fractionResult = 1000 * (fractionResult - this.second);
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ case dateTimeString.length === 14:
+ // "YYYYMMDDHHMMSS"
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
+
+ if (fractionPointPosition !== -1) {
+ const fractionResult = 1000 * fractionPart;
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ default:
+ throw new Error("Wrong input string for convertion");
+ }
+ //endregion
+
+ //region Put parsed values at right places
+ const parserArray = parser.exec(dateTimeString);
+ if (parserArray === null) throw new Error("Wrong input string for convertion");
+
+ for (let j = 1; j < parserArray.length; j++) {
+ switch (j) {
+ case 1:
+ this.year = parseInt(parserArray[j], 10);
+ break;
+ case 2:
+ this.month = parseInt(parserArray[j], 10);
+ break;
+ case 3:
+ this.day = parseInt(parserArray[j], 10);
+ break;
+ case 4:
+ this.hour = parseInt(parserArray[j], 10) + hourDifference;
+ break;
+ case 5:
+ this.minute = parseInt(parserArray[j], 10) + minuteDifference;
+ break;
+ case 6:
+ this.second = parseInt(parserArray[j], 10);
+ break;
+ default:
+ throw new Error("Wrong input string for convertion");
+ }
+ }
+ //endregion
+
+ //region Get final date
+ if (isUTC === false) {
+ const tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+
+ this.year = tempDate.getUTCFullYear();
+ this.month = tempDate.getUTCMonth();
+ this.day = tempDate.getUTCDay();
+ this.hour = tempDate.getUTCHours();
+ this.minute = tempDate.getUTCMinutes();
+ this.second = tempDate.getUTCSeconds();
+ this.millisecond = tempDate.getUTCMilliseconds();
+ }
+ //endregion
+ }
+ //**********************************************************************************
+ /**
+ * Function converting ASN.1 internal class into JavaScript string
+ * @returns {string}
+ */
+ toString() {
+ const outputArray = [];
+
+ outputArray.push((0, _pvutils.padNumber)(this.year, 4));
+ outputArray.push((0, _pvutils.padNumber)(this.month, 2));
+ outputArray.push((0, _pvutils.padNumber)(this.day, 2));
+ outputArray.push((0, _pvutils.padNumber)(this.hour, 2));
+ outputArray.push((0, _pvutils.padNumber)(this.minute, 2));
+ outputArray.push((0, _pvutils.padNumber)(this.second, 2));
+ if (this.millisecond !== 0) {
+ outputArray.push(".");
+ outputArray.push((0, _pvutils.padNumber)(this.millisecond, 3));
+ }
+ outputArray.push("Z");
+
+ return outputArray.join("");
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "GeneralizedTime";
+ }
+ //**********************************************************************************
+ /**
+ * Convertion for the block to JSON object
+ * @returns {Object}
+ */
+ toJSON() {
+ let object = {};
+
+ //region Seems at the moment (Sep 2016) there is no way how to check method is supported in "super" object
+ try {
+ object = super.toJSON();
+ } catch (ex) {}
+ //endregion
+
+ object.year = this.year;
+ object.month = this.month;
+ object.day = this.day;
+ object.hour = this.hour;
+ object.minute = this.minute;
+ object.second = this.second;
+ object.millisecond = this.millisecond;
+
+ return object;
+ }
+ //**********************************************************************************
+}
+exports.GeneralizedTime = GeneralizedTime; //**************************************************************************************
+/**
+ * @extends Utf8String
+ */
+
+class DATE extends Utf8String {
+ //**********************************************************************************
+ /**
+ * Constructor for "DATE" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 31; // DATE
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "DATE";
+ }
+ //**********************************************************************************
+}
+exports.DATE = DATE; //**************************************************************************************
+/**
+ * @extends Utf8String
+ */
+
+class TimeOfDay extends Utf8String {
+ //**********************************************************************************
+ /**
+ * Constructor for "TimeOfDay" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 32; // TimeOfDay
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "TimeOfDay";
+ }
+ //**********************************************************************************
+}
+exports.TimeOfDay = TimeOfDay; //**************************************************************************************
+/**
+ * @extends Utf8String
+ */
+
+class DateTime extends Utf8String {
+ //**********************************************************************************
+ /**
+ * Constructor for "DateTime" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 33; // DateTime
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "DateTime";
+ }
+ //**********************************************************************************
+}
+exports.DateTime = DateTime; //**************************************************************************************
+/**
+ * @extends Utf8String
+ */
+
+class Duration extends Utf8String {
+ //**********************************************************************************
+ /**
+ * Constructor for "Duration" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 34; // Duration
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "Duration";
+ }
+ //**********************************************************************************
+}
+exports.Duration = Duration; //**************************************************************************************
+/**
+ * @extends Utf8String
+ */
+
+class TIME extends Utf8String {
+ //**********************************************************************************
+ /**
+ * Constructor for "Time" class
+ * @param {Object} [parameters={}]
+ */
+ constructor(parameters = {}) {
+ super(parameters);
+
+ this.idBlock.tagClass = 1; // UNIVERSAL
+ this.idBlock.tagNumber = 14; // Time
+ }
+ //**********************************************************************************
+ /**
+ * Aux function, need to get a block name. Need to have it here for inhiritence
+ * @returns {string}
+ */
+ static blockName() {
+ return "TIME";
+ }
+ //**********************************************************************************
+}
+exports.TIME = TIME; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of special ASN.1 schema type Choice
+//**************************************************************************************
+
+class Choice {
+ //**********************************************************************************
+ /**
+ * Constructor for "Choice" class
+ * @param {Object} [parameters={}]
+ * @property {Array} [value] Array of ASN.1 types for make a choice from
+ * @property {boolean} [optional]
+ */
+ constructor(parameters = {}) {
+ this.value = (0, _pvutils.getParametersValue)(parameters, "value", []);
+ this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false);
+ }
+ //**********************************************************************************
+}
+exports.Choice = Choice; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of special ASN.1 schema type Any
+//**************************************************************************************
+
+class Any {
+ //**********************************************************************************
+ /**
+ * Constructor for "Any" class
+ * @param {Object} [parameters={}]
+ * @property {string} [name]
+ * @property {boolean} [optional]
+ */
+ constructor(parameters = {}) {
+ this.name = (0, _pvutils.getParametersValue)(parameters, "name", "");
+ this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false);
+ }
+ //**********************************************************************************
+}
+exports.Any = Any; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of special ASN.1 schema type Repeated
+//**************************************************************************************
+
+class Repeated {
+ //**********************************************************************************
+ /**
+ * Constructor for "Repeated" class
+ * @param {Object} [parameters={}]
+ * @property {string} [name]
+ * @property {boolean} [optional]
+ */
+ constructor(parameters = {}) {
+ this.name = (0, _pvutils.getParametersValue)(parameters, "name", "");
+ this.optional = (0, _pvutils.getParametersValue)(parameters, "optional", false);
+ this.value = (0, _pvutils.getParametersValue)(parameters, "value", new Any());
+ this.local = (0, _pvutils.getParametersValue)(parameters, "local", false); // Could local or global array to store elements
+ }
+ //**********************************************************************************
+}
+exports.Repeated = Repeated; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Declaration of special ASN.1 schema type RawData
+//**************************************************************************************
+/**
+ * @description Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer
+ */
+
+class RawData {
+ //**********************************************************************************
+ /**
+ * Constructor for "Repeated" class
+ * @param {Object} [parameters={}]
+ * @property {string} [name]
+ * @property {boolean} [optional]
+ */
+ constructor(parameters = {}) {
+ this.data = (0, _pvutils.getParametersValue)(parameters, "data", new ArrayBuffer(0));
+ }
+ //**********************************************************************************
+ /**
+ * Base function for converting block from BER encoded array of bytes
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {number} Offset after least decoded byte
+ */
+ fromBER(inputBuffer, inputOffset, inputLength) {
+ this.data = inputBuffer.slice(inputOffset, inputLength);
+ return inputOffset + inputLength;
+ }
+ //**********************************************************************************
+ /**
+ * Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ * @param {boolean} [sizeOnly=false] Flag that we need only a size of encoding, not a real array of bytes
+ * @returns {ArrayBuffer}
+ */
+ toBER(sizeOnly = false) {
+ return this.data;
+ }
+ //**********************************************************************************
+}
+exports.RawData = RawData; //**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Major ASN.1 BER decoding function
+//**************************************************************************************
+/**
+ * Internal library function for decoding ASN.1 BER
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array
+ * @param {!number} inputOffset Offset in ASN.1 BER encoded array where decoding should be started
+ * @param {!number} inputLength Maximum length of array of bytes which can be using in this function
+ * @returns {{offset: number, result: Object}}
+ */
+
+function LocalFromBER(inputBuffer, inputOffset, inputLength) {
+ const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function
+
+ //region Local function changing a type for ASN.1 classes
+ function localChangeType(inputObject, newType) {
+ if (inputObject instanceof newType) return inputObject;
+
+ const newObject = new newType();
+ newObject.idBlock = inputObject.idBlock;
+ newObject.lenBlock = inputObject.lenBlock;
+ newObject.warnings = inputObject.warnings;
+ //noinspection JSCheckFunctionSignatures
+ newObject.valueBeforeDecode = inputObject.valueBeforeDecode.slice(0);
+
+ return newObject;
+ }
+ //endregion
+
+ //region Create a basic ASN.1 type since we need to return errors and warnings from the function
+ let returnObject = new BaseBlock({}, Object);
+ //endregion
+
+ //region Basic check for parameters
+ if ((0, _pvutils.checkBufferParams)(new LocalBaseBlock(), inputBuffer, inputOffset, inputLength) === false) {
+ returnObject.error = "Wrong input parameters";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ //endregion
+
+ //region Getting Uint8Array from ArrayBuffer
+ const intBuffer = new Uint8Array(inputBuffer, inputOffset, inputLength);
+ //endregion
+
+ //region Initial checks
+ if (intBuffer.length === 0) {
+ this.error = "Zero buffer length";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ //endregion
+
+ //region Decode indentifcation block of ASN.1 BER structure
+ let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength);
+ returnObject.warnings.concat(returnObject.idBlock.warnings);
+ if (resultOffset === -1) {
+ returnObject.error = returnObject.idBlock.error;
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+
+ inputOffset = resultOffset;
+ inputLength -= returnObject.idBlock.blockLength;
+ //endregion
+
+ //region Decode length block of ASN.1 BER structure
+ resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength);
+ returnObject.warnings.concat(returnObject.lenBlock.warnings);
+ if (resultOffset === -1) {
+ returnObject.error = returnObject.lenBlock.error;
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+
+ inputOffset = resultOffset;
+ inputLength -= returnObject.lenBlock.blockLength;
+ //endregion
+
+ //region Check for usign indefinite length form in encoding for primitive types
+ if (returnObject.idBlock.isConstructed === false && returnObject.lenBlock.isIndefiniteForm === true) {
+ returnObject.error = "Indefinite length form used for primitive encoding form";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ //endregion
+
+ //region Switch ASN.1 block type
+ let newASN1Type = BaseBlock;
+
+ switch (returnObject.idBlock.tagClass) {
+ //region UNIVERSAL
+ case 1:
+ //region Check for reserved tag numbers
+ if (returnObject.idBlock.tagNumber >= 37 && returnObject.idBlock.isHexOnly === false) {
+ returnObject.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ //endregion
+
+ switch (returnObject.idBlock.tagNumber) {
+ //region EndOfContent type
+ case 0:
+ //region Check for EndOfContent type
+ if (returnObject.idBlock.isConstructed === true && returnObject.lenBlock.length > 0) {
+ returnObject.error = "Type [UNIVERSAL 0] is reserved";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ }
+ //endregion
+
+ newASN1Type = EndOfContent;
+
+ break;
+ //endregion
+ //region Boolean type
+ case 1:
+ newASN1Type = Boolean;
+ break;
+ //endregion
+ //region Integer type
+ case 2:
+ newASN1Type = Integer;
+ break;
+ //endregion
+ //region BitString type
+ case 3:
+ newASN1Type = BitString;
+ break;
+ //endregion
+ //region OctetString type
+ case 4:
+ newASN1Type = OctetString;
+ break;
+ //endregion
+ //region Null type
+ case 5:
+ newASN1Type = Null;
+ break;
+ //endregion
+ //region OBJECT IDENTIFIER type
+ case 6:
+ newASN1Type = ObjectIdentifier;
+ break;
+ //endregion
+ //region Enumerated type
+ case 10:
+ newASN1Type = Enumerated;
+ break;
+ //endregion
+ //region Utf8String type
+ case 12:
+ newASN1Type = Utf8String;
+ break;
+ //endregion
+ //region Time type
+ case 14:
+ newASN1Type = TIME;
+ break;
+ //endregion
+ //region ASN.1 reserved type
+ case 15:
+ returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard";
+ return {
+ offset: -1,
+ result: returnObject
+ };
+ //endregion
+ //region Sequence type
+ case 16:
+ newASN1Type = Sequence;
+ break;
+ //endregion
+ //region Set type
+ case 17:
+ newASN1Type = Set;
+ break;
+ //endregion
+ //region NumericString type
+ case 18:
+ newASN1Type = NumericString;
+ break;
+ //endregion
+ //region PrintableString type
+ case 19:
+ newASN1Type = PrintableString;
+ break;
+ //endregion
+ //region TeletexString type
+ case 20:
+ newASN1Type = TeletexString;
+ break;
+ //endregion
+ //region VideotexString type
+ case 21:
+ newASN1Type = VideotexString;
+ break;
+ //endregion
+ //region IA5String type
+ case 22:
+ newASN1Type = IA5String;
+ break;
+ //endregion
+ //region UTCTime type
+ case 23:
+ newASN1Type = UTCTime;
+ break;
+ //endregion
+ //region GeneralizedTime type
+ case 24:
+ newASN1Type = GeneralizedTime;
+ break;
+ //endregion
+ //region GraphicString type
+ case 25:
+ newASN1Type = GraphicString;
+ break;
+ //endregion
+ //region VisibleString type
+ case 26:
+ newASN1Type = VisibleString;
+ break;
+ //endregion
+ //region GeneralString type
+ case 27:
+ newASN1Type = GeneralString;
+ break;
+ //endregion
+ //region UniversalString type
+ case 28:
+ newASN1Type = UniversalString;
+ break;
+ //endregion
+ //region CharacterString type
+ case 29:
+ newASN1Type = CharacterString;
+ break;
+ //endregion
+ //region BmpString type
+ case 30:
+ newASN1Type = BmpString;
+ break;
+ //endregion
+ //region DATE type
+ case 31:
+ newASN1Type = DATE;
+ break;
+ //endregion
+ //region TimeOfDay type
+ case 32:
+ newASN1Type = TimeOfDay;
+ break;
+ //endregion
+ //region Date-Time type
+ case 33:
+ newASN1Type = DateTime;
+ break;
+ //endregion
+ //region Duration type
+ case 34:
+ newASN1Type = Duration;
+ break;
+ //endregion
+ //region default
+ default:
+ {
+ let newObject;
+
+ if (returnObject.idBlock.isConstructed === true) newObject = new Constructed();else newObject = new Primitive();
+
+ newObject.idBlock = returnObject.idBlock;
+ newObject.lenBlock = returnObject.lenBlock;
+ newObject.warnings = returnObject.warnings;
+
+ returnObject = newObject;
+
+ resultOffset = returnObject.fromBER(inputBuffer, inputOffset, inputLength);
+ }
+ //endregion
+ }
+ break;
+ //endregion
+ //region All other tag classes
+ case 2: // APPLICATION
+ case 3: // CONTEXT-SPECIFIC
+ case 4: // PRIVATE
+ default:
+ {
+ if (returnObject.idBlock.isConstructed === true) newASN1Type = Constructed;else newASN1Type = Primitive;
+ }
+ //endregion
+ }
+ //endregion
+
+ //region Change type and perform BER decoding
+ returnObject = localChangeType(returnObject, newASN1Type);
+ resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm === true ? inputLength : returnObject.lenBlock.length);
+ //endregion
+
+ //region Coping incoming buffer for entire ASN.1 block
+ returnObject.valueBeforeDecode = inputBuffer.slice(incomingOffset, incomingOffset + returnObject.blockLength);
+ //endregion
+
+ return {
+ offset: resultOffset,
+ result: returnObject
+ };
+}
+//**************************************************************************************
+/**
+ * Major function for decoding ASN.1 BER array into internal library structuries
+ * @param {!ArrayBuffer} inputBuffer ASN.1 BER encoded array of bytes
+ */
+function fromBER(inputBuffer) {
+ if (inputBuffer.byteLength === 0) {
+ const result = new BaseBlock({}, Object);
+ result.error = "Input buffer has zero length";
+
+ return {
+ offset: -1,
+ result
+ };
+ }
+
+ return LocalFromBER(inputBuffer, 0, inputBuffer.byteLength);
+}
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Major scheme verification function
+//**************************************************************************************
+/**
+ * Compare of two ASN.1 object trees
+ * @param {!Object} root Root of input ASN.1 object tree
+ * @param {!Object} inputData Input ASN.1 object tree
+ * @param {!Object} inputSchema Input ASN.1 schema to compare with
+ * @return {{verified: boolean}|{verified:boolean, result: Object}}
+ */
+function compareSchema(root, inputData, inputSchema) {
+ //region Special case for Choice schema element type
+ if (inputSchema instanceof Choice) {
+ const choiceResult = false;
+
+ for (let j = 0; j < inputSchema.value.length; j++) {
+ const result = compareSchema(root, inputData, inputSchema.value[j]);
+ if (result.verified === true) {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ }
+
+ if (choiceResult === false) {
+ const _result = {
+ verified: false,
+ result: {
+ error: "Wrong values for Choice type"
+ }
+ };
+
+ if (inputSchema.hasOwnProperty("name")) _result.name = inputSchema.name;
+
+ return _result;
+ }
+ }
+ //endregion
+
+ //region Special case for Any schema element type
+ if (inputSchema instanceof Any) {
+ //region Add named component of ASN.1 schema
+ if (inputSchema.hasOwnProperty("name")) root[inputSchema.name] = inputData;
+ //endregion
+
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ //endregion
+
+ //region Initial check
+ if (root instanceof Object === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong root object" }
+ };
+ }
+
+ if (inputData instanceof Object === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 data" }
+ };
+ }
+
+ if (inputSchema instanceof Object === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ if ("idBlock" in inputSchema === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+ //endregion
+
+ //region Comparing idBlock properties in ASN.1 data and ASN.1 schema
+ //region Encode and decode ASN.1 schema idBlock
+ /// <remarks>This encoding/decoding is neccessary because could be an errors in schema definition</remarks>
+ if ("fromBER" in inputSchema.idBlock === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ if ("toBER" in inputSchema.idBlock === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ const encodedId = inputSchema.idBlock.toBER(false);
+ if (encodedId.byteLength === 0) {
+ return {
+ verified: false,
+ result: { error: "Error encoding idBlock for ASN.1 schema" }
+ };
+ }
+
+ const decodedOffset = inputSchema.idBlock.fromBER(encodedId, 0, encodedId.byteLength);
+ if (decodedOffset === -1) {
+ return {
+ verified: false,
+ result: { error: "Error decoding idBlock for ASN.1 schema" }
+ };
+ }
+ //endregion
+
+ //region tagClass
+ if (inputSchema.idBlock.hasOwnProperty("tagClass") === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ if (inputSchema.idBlock.tagClass !== inputData.idBlock.tagClass) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ //endregion
+ //region tagNumber
+ if (inputSchema.idBlock.hasOwnProperty("tagNumber") === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ if (inputSchema.idBlock.tagNumber !== inputData.idBlock.tagNumber) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ //endregion
+ //region isConstructed
+ if (inputSchema.idBlock.hasOwnProperty("isConstructed") === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ if (inputSchema.idBlock.isConstructed !== inputData.idBlock.isConstructed) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ //endregion
+ //region isHexOnly
+ if ("isHexOnly" in inputSchema.idBlock === false) // Since 'isHexOnly' is an inhirited property
+ {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ if (inputSchema.idBlock.isHexOnly !== inputData.idBlock.isHexOnly) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ //endregion
+ //region valueHex
+ if (inputSchema.idBlock.isHexOnly === true) {
+ if ("valueHex" in inputSchema.idBlock === false) // Since 'valueHex' is an inhirited property
+ {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ }
+
+ const schemaView = new Uint8Array(inputSchema.idBlock.valueHex);
+ const asn1View = new Uint8Array(inputData.idBlock.valueHex);
+
+ if (schemaView.length !== asn1View.length) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+
+ for (let i = 0; i < schemaView.length; i++) {
+ if (schemaView[i] !== asn1View[1]) {
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ }
+ }
+ //endregion
+ //endregion
+
+ //region Add named component of ASN.1 schema
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") root[inputSchema.name] = inputData;
+ }
+ //endregion
+
+ //region Getting next ASN.1 block for comparition
+ if (inputSchema.idBlock.isConstructed === true) {
+ let admission = 0;
+ let result = { verified: false };
+
+ let maxLength = inputSchema.valueBlock.value.length;
+
+ if (maxLength > 0) {
+ if (inputSchema.valueBlock.value[0] instanceof Repeated) maxLength = inputData.valueBlock.value.length;
+ }
+
+ //region Special case when constructive value has no elements
+ if (maxLength === 0) {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ //endregion
+
+ //region Special case when "inputData" has no values and "inputSchema" has all optional values
+ if (inputData.valueBlock.value.length === 0 && inputSchema.valueBlock.value.length !== 0) {
+ let _optional = true;
+
+ for (let i = 0; i < inputSchema.valueBlock.value.length; i++) _optional = _optional && (inputSchema.valueBlock.value[i].optional || false);
+
+ if (_optional === true) {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+
+ //region Delete early added name of block
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") delete root[inputSchema.name];
+ }
+ //endregion
+
+ root.error = "Inconsistent object length";
+
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ //endregion
+
+ for (let i = 0; i < maxLength; i++) {
+ //region Special case when there is an "optional" element of ASN.1 schema at the end
+ if (i - admission >= inputData.valueBlock.value.length) {
+ if (inputSchema.valueBlock.value[i].optional === false) {
+ const _result = {
+ verified: false,
+ result: root
+ };
+
+ root.error = "Inconsistent length between ASN.1 data and schema";
+
+ //region Delete early added name of block
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") {
+ delete root[inputSchema.name];
+ _result.name = inputSchema.name;
+ }
+ }
+ //endregion
+
+ return _result;
+ }
+ }
+ //endregion
+ else {
+ //region Special case for Repeated type of ASN.1 schema element
+ if (inputSchema.valueBlock.value[0] instanceof Repeated) {
+ result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value);
+ if (result.verified === false) {
+ if (inputSchema.valueBlock.value[0].optional === true) admission++;else {
+ //region Delete early added name of block
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") delete root[inputSchema.name];
+ }
+ //endregion
+
+ return result;
+ }
+ }
+
+ if ("name" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].name.length > 0) {
+ let arrayRoot = {};
+
+ if ("local" in inputSchema.valueBlock.value[0] && inputSchema.valueBlock.value[0].local === true) arrayRoot = inputData;else arrayRoot = root;
+
+ if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined") arrayRoot[inputSchema.valueBlock.value[0].name] = [];
+
+ arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]);
+ }
+ }
+ //endregion
+ else {
+ result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]);
+ if (result.verified === false) {
+ if (inputSchema.valueBlock.value[i].optional === true) admission++;else {
+ //region Delete early added name of block
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") delete root[inputSchema.name];
+ }
+ //endregion
+
+ return result;
+ }
+ }
+ }
+ }
+ }
+
+ if (result.verified === false) // The situation may take place if last element is "optional" and verification failed
+ {
+ const _result = {
+ verified: false,
+ result: root
+ };
+
+ //region Delete early added name of block
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") {
+ delete root[inputSchema.name];
+ _result.name = inputSchema.name;
+ }
+ }
+ //endregion
+
+ return _result;
+ }
+
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ //endregion
+ //region Ability to parse internal value for primitive-encoded value (value of OctetString, for example)
+ if ("primitiveSchema" in inputSchema && "valueHex" in inputData.valueBlock) {
+ //region Decoding of raw ASN.1 data
+ const asn1 = fromBER(inputData.valueBlock.valueHex);
+ if (asn1.offset === -1) {
+ const _result = {
+ verified: false,
+ result: asn1.result
+ };
+
+ //region Delete early added name of block
+ if (inputSchema.hasOwnProperty("name")) {
+ inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, "");
+ if (inputSchema.name !== "") {
+ delete root[inputSchema.name];
+ _result.name = inputSchema.name;
+ }
+ }
+ //endregion
+
+ return _result;
+ }
+ //endregion
+
+ return compareSchema(root, asn1.result, inputSchema.primitiveSchema);
+ }
+
+ return {
+ verified: true,
+ result: root
+ };
+ //endregion
+}
+//**************************************************************************************
+//noinspection JSUnusedGlobalSymbols
+/**
+ * ASN.1 schema verification for ArrayBuffer data
+ * @param {!ArrayBuffer} inputBuffer Input BER-encoded ASN.1 data
+ * @param {!Object} inputSchema Input ASN.1 schema to verify against to
+ * @return {{verified: boolean}|{verified:boolean, result: Object}}
+ */
+function verifySchema(inputBuffer, inputSchema) {
+ //region Initial check
+ if (inputSchema instanceof Object === false) {
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema type" }
+ };
+ }
+ //endregion
+
+ //region Decoding of raw ASN.1 data
+ const asn1 = fromBER(inputBuffer);
+ if (asn1.offset === -1) {
+ return {
+ verified: false,
+ result: asn1.result
+ };
+ }
+ //endregion
+
+ //region Compare ASN.1 struct with input schema
+ return compareSchema(asn1.result, asn1.result, inputSchema);
+ //endregion
+}
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+//region Major function converting JSON to ASN.1 objects
+//**************************************************************************************
+//noinspection JSUnusedGlobalSymbols
+/**
+ * Converting from JSON to ASN.1 objects
+ * @param {string|Object} json JSON string or object to convert to ASN.1 objects
+ */
+function fromJSON(json) {}
+// TODO Implement
+
+//**************************************************************************************
+//endregion
+//**************************************************************************************
+
+},{"pvutils":3}],3:[function(require,module,exports){
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.getUTCDate = getUTCDate;
+exports.getParametersValue = getParametersValue;
+exports.bufferToHexCodes = bufferToHexCodes;
+exports.checkBufferParams = checkBufferParams;
+exports.utilFromBase = utilFromBase;
+exports.utilToBase = utilToBase;
+exports.utilConcatBuf = utilConcatBuf;
+exports.utilConcatView = utilConcatView;
+exports.utilDecodeTC = utilDecodeTC;
+exports.utilEncodeTC = utilEncodeTC;
+exports.isEqualBuffer = isEqualBuffer;
+exports.padNumber = padNumber;
+exports.toBase64 = toBase64;
+exports.fromBase64 = fromBase64;
+exports.arrayBufferToString = arrayBufferToString;
+exports.stringToArrayBuffer = stringToArrayBuffer;
+exports.nearestPowerOf2 = nearestPowerOf2;
+exports.clearProps = clearProps;
+//**************************************************************************************
+/**
+ * Making UTC date from local date
+ * @param {Date} date Date to convert from
+ * @returns {Date}
+ */
+function getUTCDate(date) {
+ // noinspection NestedFunctionCallJS, MagicNumberJS
+ return new Date(date.getTime() + date.getTimezoneOffset() * 60000);
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleReturnPointsJS
+/**
+ * Get value for input parameters, or set a default value
+ * @param {Object} parameters
+ * @param {string} name
+ * @param defaultValue
+ */
+function getParametersValue(parameters, name, defaultValue) {
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
+ if (parameters instanceof Object === false) return defaultValue;
+
+ // noinspection NonBlockStatementBodyJS
+ if (name in parameters) return parameters[name];
+
+ return defaultValue;
+}
+//**************************************************************************************
+/**
+ * Converts "ArrayBuffer" into a hexdecimal string
+ * @param {ArrayBuffer} inputBuffer
+ * @param {number} [inputOffset=0]
+ * @param {number} [inputLength=inputBuffer.byteLength]
+ * @param {boolean} [insertSpace=false]
+ * @returns {string}
+ */
+function bufferToHexCodes(inputBuffer, inputOffset = 0, inputLength = inputBuffer.byteLength - inputOffset, insertSpace = false) {
+ let result = "";
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = new Uint8Array(inputBuffer, inputOffset, inputLength)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ const item = _step.value;
+
+ // noinspection ChainedFunctionCallJS
+ const str = item.toString(16).toUpperCase();
+
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
+ if (str.length === 1) result += "0";
+
+ result += str;
+
+ // noinspection NonBlockStatementBodyJS
+ if (insertSpace) result += " ";
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ return result.trim();
+}
+//**************************************************************************************
+// noinspection JSValidateJSDoc, FunctionWithMultipleReturnPointsJS
+/**
+ * Check input "ArrayBuffer" for common functions
+ * @param {LocalBaseBlock} baseBlock
+ * @param {ArrayBuffer} inputBuffer
+ * @param {number} inputOffset
+ * @param {number} inputLength
+ * @returns {boolean}
+ */
+function checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength) {
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (inputBuffer instanceof ArrayBuffer === false) {
+ // noinspection JSUndefinedPropertyAssignment
+ baseBlock.error = "Wrong parameter: inputBuffer must be \"ArrayBuffer\"";
+ return false;
+ }
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (inputBuffer.byteLength === 0) {
+ // noinspection JSUndefinedPropertyAssignment
+ baseBlock.error = "Wrong parameter: inputBuffer has zero length";
+ return false;
+ }
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (inputOffset < 0) {
+ // noinspection JSUndefinedPropertyAssignment
+ baseBlock.error = "Wrong parameter: inputOffset less than zero";
+ return false;
+ }
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (inputLength < 0) {
+ // noinspection JSUndefinedPropertyAssignment
+ baseBlock.error = "Wrong parameter: inputLength less than zero";
+ return false;
+ }
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (inputBuffer.byteLength - inputOffset - inputLength < 0) {
+ // noinspection JSUndefinedPropertyAssignment
+ baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
+ return false;
+ }
+
+ return true;
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleReturnPointsJS
+/**
+ * Convert number from 2^base to 2^10
+ * @param {Uint8Array} inputBuffer
+ * @param {number} inputBase
+ * @returns {number}
+ */
+function utilFromBase(inputBuffer, inputBase) {
+ let result = 0;
+
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
+ if (inputBuffer.length === 1) return inputBuffer[0];
+
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS
+ for (let i = inputBuffer.length - 1; i >= 0; i--) result += inputBuffer[inputBuffer.length - 1 - i] * Math.pow(2, inputBase * i);
+
+ return result;
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS
+/**
+ * Convert number from 2^10 to 2^base
+ * @param {!number} value The number to convert
+ * @param {!number} base The base for 2^base
+ * @param {number} [reserved=0] Pre-defined number of bytes in output array (-1 = limited by function itself)
+ * @returns {ArrayBuffer}
+ */
+function utilToBase(value, base, reserved = -1) {
+ const internalReserved = reserved;
+ let internalValue = value;
+
+ let result = 0;
+ let biggest = Math.pow(2, base);
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ for (let i = 1; i < 8; i++) {
+ if (value < biggest) {
+ let retBuf;
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (internalReserved < 0) {
+ retBuf = new ArrayBuffer(i);
+ result = i;
+ } else {
+ // noinspection NonBlockStatementBodyJS
+ if (internalReserved < i) return new ArrayBuffer(0);
+
+ retBuf = new ArrayBuffer(internalReserved);
+
+ result = internalReserved;
+ }
+
+ const retView = new Uint8Array(retBuf);
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ for (let j = i - 1; j >= 0; j--) {
+ const basis = Math.pow(2, j * base);
+
+ retView[result - j - 1] = Math.floor(internalValue / basis);
+ internalValue -= retView[result - j - 1] * basis;
+ }
+
+ return retBuf;
+ }
+
+ biggest *= Math.pow(2, base);
+ }
+
+ return new ArrayBuffer(0);
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleLoopsJS
+/**
+ * Concatenate two ArrayBuffers
+ * @param {...ArrayBuffer} buffers Set of ArrayBuffer
+ */
+function utilConcatBuf(...buffers) {
+ //region Initial variables
+ let outputLength = 0;
+ let prevLength = 0;
+ //endregion
+
+ //region Calculate output length
+
+ // noinspection NonBlockStatementBodyJS
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = buffers[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ const buffer = _step2.value;
+
+ outputLength += buffer.byteLength;
+ } //endregion
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ const retBuf = new ArrayBuffer(outputLength);
+ const retView = new Uint8Array(retBuf);
+
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = buffers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ const buffer = _step3.value;
+
+ // noinspection NestedFunctionCallJS
+ retView.set(new Uint8Array(buffer), prevLength);
+ prevLength += buffer.byteLength;
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ return retBuf;
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleLoopsJS
+/**
+ * Concatenate two Uint8Array
+ * @param {...Uint8Array} views Set of Uint8Array
+ */
+function utilConcatView(...views) {
+ //region Initial variables
+ let outputLength = 0;
+ let prevLength = 0;
+ //endregion
+
+ //region Calculate output length
+ // noinspection NonBlockStatementBodyJS
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = views[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ const view = _step4.value;
+
+ outputLength += view.length;
+ } //endregion
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ const retBuf = new ArrayBuffer(outputLength);
+ const retView = new Uint8Array(retBuf);
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = views[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ const view = _step5.value;
+
+ retView.set(view, prevLength);
+ prevLength += view.length;
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ return retView;
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleLoopsJS
+/**
+ * Decoding of "two complement" values
+ * The function must be called in scope of instance of "hexBlock" class ("valueHex" and "warnings" properties must be present)
+ * @returns {number}
+ */
+function utilDecodeTC() {
+ const buf = new Uint8Array(this.valueHex);
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (this.valueHex.byteLength >= 2) {
+ //noinspection JSBitwiseOperatorUsage, ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ const condition1 = buf[0] === 0xFF && buf[1] & 0x80;
+ // noinspection ConstantOnRightSideOfComparisonJS, LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ const condition2 = buf[0] === 0x00 && (buf[1] & 0x80) === 0x00;
+
+ // noinspection NonBlockStatementBodyJS
+ if (condition1 || condition2) this.warnings.push("Needlessly long format");
+ }
+
+ //region Create big part of the integer
+ const bigIntBuffer = new ArrayBuffer(this.valueHex.byteLength);
+ const bigIntView = new Uint8Array(bigIntBuffer);
+ // noinspection NonBlockStatementBodyJS
+ for (let i = 0; i < this.valueHex.byteLength; i++) bigIntView[i] = 0;
+
+ // noinspection MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ bigIntView[0] = buf[0] & 0x80; // mask only the biggest bit
+
+ const bigInt = utilFromBase(bigIntView, 8);
+ //endregion
+
+ //region Create small part of the integer
+ const smallIntBuffer = new ArrayBuffer(this.valueHex.byteLength);
+ const smallIntView = new Uint8Array(smallIntBuffer);
+ // noinspection NonBlockStatementBodyJS
+ for (let j = 0; j < this.valueHex.byteLength; j++) smallIntView[j] = buf[j];
+
+ // noinspection MagicNumberJS
+ smallIntView[0] &= 0x7F; // mask biggest bit
+
+ const smallInt = utilFromBase(smallIntView, 8);
+ //endregion
+
+ return smallInt - bigInt;
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleLoopsJS, FunctionWithMultipleReturnPointsJS
+/**
+ * Encode integer value to "two complement" format
+ * @param {number} value Value to encode
+ * @returns {ArrayBuffer}
+ */
+function utilEncodeTC(value) {
+ // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS
+ const modValue = value < 0 ? value * -1 : value;
+ let bigInt = 128;
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ for (let i = 1; i < 8; i++) {
+ if (modValue <= bigInt) {
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (value < 0) {
+ const smallInt = bigInt - modValue;
+
+ const retBuf = utilToBase(smallInt, 8, i);
+ const retView = new Uint8Array(retBuf);
+
+ // noinspection MagicNumberJS
+ retView[0] |= 0x80;
+
+ return retBuf;
+ }
+
+ let retBuf = utilToBase(modValue, 8, i);
+ let retView = new Uint8Array(retBuf);
+
+ //noinspection JSBitwiseOperatorUsage, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ if (retView[0] & 0x80) {
+ //noinspection JSCheckFunctionSignatures
+ const tempBuf = retBuf.slice(0);
+ const tempView = new Uint8Array(tempBuf);
+
+ retBuf = new ArrayBuffer(retBuf.byteLength + 1);
+ // noinspection ReuseOfLocalVariableJS
+ retView = new Uint8Array(retBuf);
+
+ // noinspection NonBlockStatementBodyJS
+ for (let k = 0; k < tempBuf.byteLength; k++) retView[k + 1] = tempView[k];
+
+ // noinspection MagicNumberJS
+ retView[0] = 0x00;
+ }
+
+ return retBuf;
+ }
+
+ bigInt *= Math.pow(2, 8);
+ }
+
+ return new ArrayBuffer(0);
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleReturnPointsJS, ParameterNamingConventionJS
+/**
+ * Compare two array buffers
+ * @param {!ArrayBuffer} inputBuffer1
+ * @param {!ArrayBuffer} inputBuffer2
+ * @returns {boolean}
+ */
+function isEqualBuffer(inputBuffer1, inputBuffer2) {
+ // noinspection NonBlockStatementBodyJS
+ if (inputBuffer1.byteLength !== inputBuffer2.byteLength) return false;
+
+ // noinspection LocalVariableNamingConventionJS
+ const view1 = new Uint8Array(inputBuffer1);
+ // noinspection LocalVariableNamingConventionJS
+ const view2 = new Uint8Array(inputBuffer2);
+
+ for (let i = 0; i < view1.length; i++) {
+ // noinspection NonBlockStatementBodyJS
+ if (view1[i] !== view2[i]) return false;
+ }
+
+ return true;
+}
+//**************************************************************************************
+// noinspection FunctionWithMultipleReturnPointsJS
+/**
+ * Pad input number with leade "0" if needed
+ * @returns {string}
+ * @param {number} inputNumber
+ * @param {number} fullLength
+ */
+function padNumber(inputNumber, fullLength) {
+ const str = inputNumber.toString(10);
+
+ // noinspection NonBlockStatementBodyJS
+ if (fullLength < str.length) return "";
+
+ const dif = fullLength - str.length;
+
+ const padding = new Array(dif);
+ // noinspection NonBlockStatementBodyJS
+ for (let i = 0; i < dif; i++) padding[i] = "0";
+
+ const paddingString = padding.join("");
+
+ return paddingString.concat(str);
+}
+//**************************************************************************************
+const base64Template = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+const base64UrlTemplate = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
+//**************************************************************************************
+// noinspection FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionTooLongJS, FunctionNamingConventionJS
+/**
+ * Encode string into BASE64 (or "base64url")
+ * @param {string} input
+ * @param {boolean} useUrlTemplate If "true" then output would be encoded using "base64url"
+ * @param {boolean} skipPadding Skip BASE-64 padding or not
+ * @param {boolean} skipLeadingZeros Skip leading zeros in input data or not
+ * @returns {string}
+ */
+function toBase64(input, useUrlTemplate = false, skipPadding = false, skipLeadingZeros = false) {
+ let i = 0;
+
+ // noinspection LocalVariableNamingConventionJS
+ let flag1 = 0;
+ // noinspection LocalVariableNamingConventionJS
+ let flag2 = 0;
+
+ let output = "";
+
+ // noinspection ConditionalExpressionJS
+ const template = useUrlTemplate ? base64UrlTemplate : base64Template;
+
+ if (skipLeadingZeros) {
+ let nonZeroPosition = 0;
+
+ for (let i = 0; i < input.length; i++) {
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (input.charCodeAt(i) !== 0) {
+ nonZeroPosition = i;
+ // noinspection BreakStatementJS
+ break;
+ }
+ }
+
+ // noinspection AssignmentToFunctionParameterJS
+ input = input.slice(nonZeroPosition);
+ }
+
+ while (i < input.length) {
+ // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
+ const chr1 = input.charCodeAt(i++);
+ // noinspection NonBlockStatementBodyJS
+ if (i >= input.length) flag1 = 1;
+ // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
+ const chr2 = input.charCodeAt(i++);
+ // noinspection NonBlockStatementBodyJS
+ if (i >= input.length) flag2 = 1;
+ // noinspection LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
+ const chr3 = input.charCodeAt(i++);
+
+ // noinspection LocalVariableNamingConventionJS
+ const enc1 = chr1 >> 2;
+ // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ const enc2 = (chr1 & 0x03) << 4 | chr2 >> 4;
+ // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ let enc3 = (chr2 & 0x0F) << 2 | chr3 >> 6;
+ // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ let enc4 = chr3 & 0x3F;
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (flag1 === 1) {
+ // noinspection NestedAssignmentJS, AssignmentResultUsedJS, MagicNumberJS
+ enc3 = enc4 = 64;
+ } else {
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (flag2 === 1) {
+ // noinspection MagicNumberJS
+ enc4 = 64;
+ }
+ }
+
+ // noinspection NonBlockStatementBodyJS
+ if (skipPadding) {
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
+ if (enc3 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}`;else {
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
+ if (enc4 === 64) output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}`;else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`;
+ }
+ } else output += `${template.charAt(enc1)}${template.charAt(enc2)}${template.charAt(enc3)}${template.charAt(enc4)}`;
+ }
+
+ return output;
+}
+//**************************************************************************************
+// noinspection FunctionWithMoreThanThreeNegationsJS, FunctionWithMultipleLoopsJS, OverlyComplexFunctionJS, FunctionNamingConventionJS
+/**
+ * Decode string from BASE64 (or "base64url")
+ * @param {string} input
+ * @param {boolean} [useUrlTemplate=false] If "true" then output would be encoded using "base64url"
+ * @param {boolean} [cutTailZeros=false] If "true" then cut tailing zeroz from function result
+ * @returns {string}
+ */
+function fromBase64(input, useUrlTemplate = false, cutTailZeros = false) {
+ // noinspection ConditionalExpressionJS
+ const template = useUrlTemplate ? base64UrlTemplate : base64Template;
+
+ //region Aux functions
+ // noinspection FunctionWithMultipleReturnPointsJS, NestedFunctionJS
+ function indexof(toSearch) {
+ // noinspection ConstantOnRightSideOfComparisonJS, MagicNumberJS
+ for (let i = 0; i < 64; i++) {
+ // noinspection NonBlockStatementBodyJS
+ if (template.charAt(i) === toSearch) return i;
+ }
+
+ // noinspection MagicNumberJS
+ return 64;
+ }
+
+ // noinspection NestedFunctionJS
+ function test(incoming) {
+ // noinspection ConstantOnRightSideOfComparisonJS, ConditionalExpressionJS, MagicNumberJS
+ return incoming === 64 ? 0x00 : incoming;
+ }
+ //endregion
+
+ let i = 0;
+
+ let output = "";
+
+ while (i < input.length) {
+ // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, IncrementDecrementResultUsedJS
+ const enc1 = indexof(input.charAt(i++));
+ // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS
+ const enc2 = i >= input.length ? 0x00 : indexof(input.charAt(i++));
+ // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS
+ const enc3 = i >= input.length ? 0x00 : indexof(input.charAt(i++));
+ // noinspection NestedFunctionCallJS, LocalVariableNamingConventionJS, ConditionalExpressionJS, MagicNumberJS, IncrementDecrementResultUsedJS
+ const enc4 = i >= input.length ? 0x00 : indexof(input.charAt(i++));
+
+ // noinspection LocalVariableNamingConventionJS, NonShortCircuitBooleanExpressionJS
+ const chr1 = test(enc1) << 2 | test(enc2) >> 4;
+ // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ const chr2 = (test(enc2) & 0x0F) << 4 | test(enc3) >> 2;
+ // noinspection LocalVariableNamingConventionJS, MagicNumberJS, NonShortCircuitBooleanExpressionJS
+ const chr3 = (test(enc3) & 0x03) << 6 | test(enc4);
+
+ output += String.fromCharCode(chr1);
+
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
+ if (enc3 !== 64) output += String.fromCharCode(chr2);
+
+ // noinspection ConstantOnRightSideOfComparisonJS, NonBlockStatementBodyJS, MagicNumberJS
+ if (enc4 !== 64) output += String.fromCharCode(chr3);
+ }
+
+ if (cutTailZeros) {
+ const outputLength = output.length;
+ let nonZeroStart = -1;
+
+ // noinspection ConstantOnRightSideOfComparisonJS
+ for (let i = outputLength - 1; i >= 0; i--) {
+ // noinspection ConstantOnRightSideOfComparisonJS
+ if (output.charCodeAt(i) !== 0) {
+ nonZeroStart = i;
+ // noinspection BreakStatementJS
+ break;
+ }
+ }
+
+ // noinspection NonBlockStatementBodyJS, NegatedIfStatementJS
+ if (nonZeroStart !== -1) output = output.slice(0, nonZeroStart + 1);else output = "";
+ }
+
+ return output;
+}
+//**************************************************************************************
+function arrayBufferToString(buffer) {
+ let resultString = "";
+ const view = new Uint8Array(buffer);
+
+ // noinspection NonBlockStatementBodyJS
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = view[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ const element = _step6.value;
+
+ resultString += String.fromCharCode(element);
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
+ _iterator6.return();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ return resultString;
+}
+//**************************************************************************************
+function stringToArrayBuffer(str) {
+ const stringLength = str.length;
+
+ const resultBuffer = new ArrayBuffer(stringLength);
+ const resultView = new Uint8Array(resultBuffer);
+
+ // noinspection NonBlockStatementBodyJS
+ for (let i = 0; i < stringLength; i++) resultView[i] = str.charCodeAt(i);
+
+ return resultBuffer;
+}
+//**************************************************************************************
+const log2 = Math.log(2);
+//**************************************************************************************
+// noinspection FunctionNamingConventionJS
+/**
+ * Get nearest to input length power of 2
+ * @param {number} length Current length of existing array
+ * @returns {number}
+ */
+function nearestPowerOf2(length) {
+ const base = Math.log(length) / log2;
+
+ const floor = Math.floor(base);
+ const round = Math.round(base);
+
+ // noinspection ConditionalExpressionJS
+ return floor === round ? floor : round;
+}
+//**************************************************************************************
+/**
+ * Delete properties by name from specified object
+ * @param {Object} object Object to delete properties from
+ * @param {Array.<string>} propsArray Array of properties names
+ */
+function clearProps(object, propsArray) {
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = propsArray[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ const prop = _step7.value;
+
+ delete object[prop];
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7.return) {
+ _iterator7.return();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+}
+//**************************************************************************************
+
+},{}]},{},[1])(1)
+});