Bug 1813034 - mach vendor asn1js. r=mkmelin
Executed: ../mach vendor -r v3.0.5 -f third_party/asn1js/moz.yaml Differential Revision: https://phabricator.services.mozilla.com/D168736 --HG-- extra : amend_source : 8b73b92f1e2a13c6212c5fb3000874a8dd366f56
This commit is contained in:
Родитель
9ee43ceb82
Коммит
5f85a03d25
|
@ -3,7 +3,7 @@ https://github.com/PeculiarVentures/asn1.js
|
|||
|
||||
For licensing information, please refer to the included documentation.
|
||||
|
||||
[tag v3.0.4]
|
||||
[tag v3.0.5]
|
||||
|
||||
Updating:
|
||||
- cd $topsrcdir/comm
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,77 @@
|
|||
{
|
||||
"author": {
|
||||
"email": "yury@strozhevsky.com",
|
||||
"name": "Yury Strozhevsky"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"email": "rmh@unmitigatedrisk.com",
|
||||
"name": "Ryan Hurst"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^9.1.1",
|
||||
"@types/node": "^17.0.32",
|
||||
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
||||
"@typescript-eslint/parser": "^5.23.0",
|
||||
"asn1-test-suite": "^1.0.2",
|
||||
"eslint": "^8.15.0",
|
||||
"eslint-plugin-deprecation": "^1.3.2",
|
||||
"mocha": "^10.0.0",
|
||||
"nyc": "^15.1.0",
|
||||
"rollup": "^2.72.1",
|
||||
"rollup-plugin-dts": "^4.2.1",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-typescript2": "^0.31.2",
|
||||
"ts-node": "^10.7.0",
|
||||
"typescript": "^4.6.4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/PeculiarVentures/asn1.js.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"pvtsutils": "^1.3.2",
|
||||
"pvutils": "^1.1.3",
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"description": "asn1js is a pure JavaScript library implementing this standard. ASN.1 is the basis of all X.509 related data structures and numerous other protocols used on the web",
|
||||
"keywords": [
|
||||
"asn1",
|
||||
"parser",
|
||||
"asn.1",
|
||||
"ber",
|
||||
"der",
|
||||
"sequence",
|
||||
"set",
|
||||
"bitstring",
|
||||
"octetstring",
|
||||
"utctime",
|
||||
"utf8string",
|
||||
"bmpstring",
|
||||
"universalstring",
|
||||
"generalizedtime"
|
||||
],
|
||||
"main": "build/index.js",
|
||||
"module": "build/index.es.js",
|
||||
"types": "build/index.d.ts",
|
||||
"name": "asn1js",
|
||||
"files": [
|
||||
"build",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"test": "mocha",
|
||||
"prepublishOnly": "npm run build",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"lint:fix": "eslint --fix . --ext .ts",
|
||||
"coverage": "nyc npm test"
|
||||
},
|
||||
"version": "3.0.5",
|
||||
"license": "BSD-3-Clause"
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { EMPTY_STRING } from "./internals/constants";
|
||||
|
||||
export interface IAny {
|
||||
name: string;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
export type AnyParams = Partial<IAny>;
|
||||
|
||||
export class Any implements IAny {
|
||||
|
||||
public name: string;
|
||||
public optional: boolean;
|
||||
|
||||
constructor({
|
||||
name = EMPTY_STRING, optional = false,
|
||||
}: AnyParams = {}) {
|
||||
this.name = name;
|
||||
this.optional = optional;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { IBerConvertible } from "./types";
|
||||
import { LocalBaseBlockJson, LocalBaseBlockParams, LocalBaseBlock } from "./internals/LocalBaseBlock";
|
||||
import { LocalIdentificationBlock, LocalIdentificationBlockJson, LocalIdentificationBlockParams } from "./internals/LocalIdentificationBlock";
|
||||
import { LocalLengthBlock, LocalLengthBlockJson, LocalLengthBlockParams } from "./internals/LocalLengthBlock";
|
||||
import { ViewWriter } from "./ViewWriter";
|
||||
import { ValueBlock, ValueBlockJson } from "./ValueBlock";
|
||||
import { EMPTY_BUFFER, EMPTY_STRING } from "./internals/constants";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface IBaseBlock {
|
||||
name: string;
|
||||
optional: boolean;
|
||||
primitiveSchema?: BaseBlock;
|
||||
}
|
||||
|
||||
export interface BaseBlockParams extends LocalBaseBlockParams, LocalIdentificationBlockParams, LocalLengthBlockParams, Partial<IBaseBlock> { }
|
||||
|
||||
export interface ValueBlockConstructor<T extends ValueBlock = ValueBlock> {
|
||||
new(...args: any[]): T;
|
||||
}
|
||||
|
||||
export interface BaseBlockJson<T extends LocalBaseBlockJson = LocalBaseBlockJson> extends LocalBaseBlockJson, Omit<IBaseBlock, "primitiveSchema"> {
|
||||
idBlock: LocalIdentificationBlockJson;
|
||||
lenBlock: LocalLengthBlockJson;
|
||||
valueBlock: T;
|
||||
primitiveSchema?: BaseBlockJson;
|
||||
}
|
||||
|
||||
export type StringEncoding = "ascii" | "hex";
|
||||
|
||||
export class BaseBlock<T extends ValueBlock = ValueBlock, J extends ValueBlockJson = ValueBlockJson> extends LocalBaseBlock implements IBaseBlock, IBerConvertible {
|
||||
|
||||
static {
|
||||
|
||||
}
|
||||
|
||||
public static override NAME = "BaseBlock";
|
||||
|
||||
public idBlock: LocalIdentificationBlock;
|
||||
public lenBlock: LocalLengthBlock;
|
||||
public valueBlock: T;
|
||||
public name: string;
|
||||
public optional: boolean;
|
||||
public primitiveSchema?: BaseBlock;
|
||||
|
||||
constructor({
|
||||
name = EMPTY_STRING,
|
||||
optional = false,
|
||||
primitiveSchema,
|
||||
...parameters
|
||||
}: BaseBlockParams = {}, valueBlockType?: ValueBlockConstructor<T>) {
|
||||
super(parameters);
|
||||
|
||||
this.name = name;
|
||||
this.optional = optional;
|
||||
if (primitiveSchema) {
|
||||
this.primitiveSchema = primitiveSchema;
|
||||
}
|
||||
|
||||
this.idBlock = new LocalIdentificationBlock(parameters);
|
||||
this.lenBlock = new LocalLengthBlock(parameters);
|
||||
this.valueBlock = valueBlockType ? new valueBlockType(parameters) : new ValueBlock(parameters) as unknown as T;
|
||||
}
|
||||
|
||||
public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
|
||||
if (resultOffset === -1) {
|
||||
this.error = this.valueBlock.error;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
if (!this.idBlock.error.length)
|
||||
this.blockLength += this.idBlock.blockLength;
|
||||
|
||||
if (!this.lenBlock.error.length)
|
||||
this.blockLength += this.lenBlock.blockLength;
|
||||
|
||||
if (!this.valueBlock.error.length)
|
||||
this.blockLength += this.valueBlock.blockLength;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
public toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
const _writer = writer || new ViewWriter();
|
||||
|
||||
if (!writer) {
|
||||
prepareIndefiniteForm(this);
|
||||
}
|
||||
|
||||
const idBlockBuf = this.idBlock.toBER(sizeOnly);
|
||||
|
||||
_writer.write(idBlockBuf);
|
||||
|
||||
if (this.lenBlock.isIndefiniteForm) {
|
||||
_writer.write(new Uint8Array([0x80]).buffer);
|
||||
|
||||
this.valueBlock.toBER(sizeOnly, _writer);
|
||||
|
||||
_writer.write(new ArrayBuffer(2));
|
||||
}
|
||||
else {
|
||||
const valueBlockBuf = this.valueBlock.toBER(sizeOnly);
|
||||
this.lenBlock.length = valueBlockBuf.byteLength;
|
||||
const lenBlockBuf = this.lenBlock.toBER(sizeOnly);
|
||||
|
||||
_writer.write(lenBlockBuf);
|
||||
_writer.write(valueBlockBuf);
|
||||
}
|
||||
|
||||
if (!writer) {
|
||||
return _writer.final();
|
||||
}
|
||||
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
public override toJSON(): BaseBlockJson<J> {
|
||||
const object: BaseBlockJson = {
|
||||
...super.toJSON(),
|
||||
idBlock: this.idBlock.toJSON(),
|
||||
lenBlock: this.lenBlock.toJSON(),
|
||||
valueBlock: this.valueBlock.toJSON(),
|
||||
name: this.name,
|
||||
optional: this.optional,
|
||||
};
|
||||
|
||||
|
||||
if (this.primitiveSchema)
|
||||
object.primitiveSchema = this.primitiveSchema.toJSON();
|
||||
|
||||
return object as BaseBlockJson<J>;
|
||||
}
|
||||
public override toString(encoding: StringEncoding = "ascii"): string {
|
||||
if (encoding === "ascii") {
|
||||
return this.onAsciiEncoding();
|
||||
}
|
||||
|
||||
return pvtsutils.Convert.ToHex(this.toBER());
|
||||
}
|
||||
|
||||
protected onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof BaseBlock).NAME} : ${pvtsutils.Convert.ToHex(this.valueBlock.valueBeforeDecodeView)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether two object instances are equal
|
||||
* @param other Object to compare with the current object
|
||||
*/
|
||||
public isEqual(other: unknown): other is this {
|
||||
if (this === other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check input type
|
||||
if (!(other instanceof this.constructor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const thisRaw = this.toBER();
|
||||
const otherRaw = (other as BaseBlock).toBER();
|
||||
|
||||
return pvutils.isEqualBuffer(thisRaw, otherRaw);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive function which checks and enables isIndefiniteForm flag for constructed blocks if any child has that flag enabled
|
||||
* @param baseBlock Base ASN.1 block
|
||||
* @returns Returns `true` if incoming block is `indefinite form`
|
||||
*/
|
||||
function prepareIndefiniteForm(baseBlock: BaseBlock): boolean {
|
||||
if (baseBlock instanceof typeStore.Constructed) {
|
||||
for (const value of baseBlock.valueBlock.value) {
|
||||
if (prepareIndefiniteForm(value)) {
|
||||
baseBlock.lenBlock.isIndefiniteForm = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return !!baseBlock.lenBlock.isIndefiniteForm;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
import { BaseBlock, BaseBlockParams } from "./BaseBlock";
|
||||
import { IStringConvertible } from "./types";
|
||||
import { EMPTY_STRING } from "./internals/constants";
|
||||
import { LocalStringValueBlock, LocalStringValueBlockJson, LocalStringValueBlockParams } from "./internals/LocalStringValueBlock";
|
||||
|
||||
export interface BaseStringBlockParams extends BaseBlockParams, LocalStringValueBlockParams { }
|
||||
export type BaseStringBlockJson = LocalStringValueBlockJson;
|
||||
|
||||
export abstract class BaseStringBlock<T extends LocalStringValueBlock = LocalStringValueBlock, J extends BaseStringBlockJson = BaseStringBlockJson> extends BaseBlock<T, J> implements IStringConvertible {
|
||||
|
||||
public static override NAME = "BaseStringBlock";
|
||||
|
||||
/**
|
||||
* String value
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public getValue(): string {
|
||||
return this.valueBlock.value;
|
||||
}
|
||||
/**
|
||||
* String value
|
||||
* @param value String value
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public setValue(value: string): void {
|
||||
this.valueBlock.value = value;
|
||||
}
|
||||
|
||||
constructor({
|
||||
value = EMPTY_STRING,
|
||||
...parameters
|
||||
}: BaseStringBlockParams = {}, stringValueBlockType: new () => T) {
|
||||
super(parameters, stringValueBlockType);
|
||||
|
||||
if (value) {
|
||||
this.fromString(value);
|
||||
}
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
|
||||
if (resultOffset === -1) {
|
||||
this.error = this.valueBlock.error;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
this.fromBuffer(this.valueBlock.valueHexView);
|
||||
|
||||
if (!this.idBlock.error.length)
|
||||
this.blockLength += this.idBlock.blockLength;
|
||||
|
||||
if (!this.lenBlock.error.length)
|
||||
this.blockLength += this.lenBlock.blockLength;
|
||||
|
||||
if (!this.valueBlock.error.length)
|
||||
this.blockLength += this.valueBlock.blockLength;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function converting ArrayBuffer into ASN.1 internal string
|
||||
* @param inputBuffer ASN.1 BER encoded array
|
||||
*/
|
||||
public abstract fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void;
|
||||
|
||||
public abstract fromString(inputString: string): void;
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof BaseStringBlock).NAME} : '${this.valueBlock.value}'`;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { Constructed } from "./Constructed";
|
||||
import { BIT_STRING_NAME } from "./internals/constants";
|
||||
import { LocalBitStringValueBlockParams, LocalBitStringValueBlock, LocalBitStringValueBlockJson } from "./internals/LocalBitStringValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface BitStringParams extends BaseBlockParams, LocalBitStringValueBlockParams { }
|
||||
export type BitStringJson = BaseBlockJson<LocalBitStringValueBlockJson>;
|
||||
|
||||
export class BitString extends BaseBlock<LocalBitStringValueBlock, LocalBitStringValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.BitString = this;
|
||||
}
|
||||
|
||||
public static override NAME = BIT_STRING_NAME;
|
||||
|
||||
constructor({
|
||||
idBlock = {},
|
||||
lenBlock = {},
|
||||
...parameters
|
||||
}: BitStringParams = {}) {
|
||||
parameters.isConstructed ??= !!parameters.value?.length;
|
||||
super({
|
||||
idBlock: {
|
||||
isConstructed: parameters.isConstructed,
|
||||
...idBlock,
|
||||
},
|
||||
lenBlock: {
|
||||
...lenBlock,
|
||||
isIndefiniteForm: !!parameters.isIndefiniteForm,
|
||||
},
|
||||
...parameters,
|
||||
}, LocalBitStringValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 3; // BitString
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
this.valueBlock.isConstructed = this.idBlock.isConstructed;
|
||||
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
|
||||
|
||||
return super.fromBER(inputBuffer, inputOffset, inputLength);
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
if (this.valueBlock.isConstructed || (this.valueBlock.value && this.valueBlock.value.length)) {
|
||||
return Constructed.prototype.onAsciiEncoding.call(this);
|
||||
} else {
|
||||
// convert bytes to bits
|
||||
const bits = [];
|
||||
const valueHex = this.valueBlock.valueHexView;
|
||||
for (const byte of valueHex) {
|
||||
bits.push(byte.toString(2).padStart(8, "0"));
|
||||
}
|
||||
|
||||
const bitsStr = bits.join("");
|
||||
|
||||
return `${(this.constructor as typeof BitString).NAME} : ${bitsStr.substring(0, bitsStr.length - this.valueBlock.unusedBits)}`;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { LocalBmpStringValueBlockParams, LocalBmpStringValueBlock, LocalBmpStringValueBlockJson } from "./internals/LocalBmpStringValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type BmpStringParams = LocalBmpStringValueBlockParams;
|
||||
export type BmpStringJson = LocalBmpStringValueBlockJson;
|
||||
|
||||
export class BmpString extends LocalBmpStringValueBlock {
|
||||
|
||||
static {
|
||||
typeStore.BmpString = this;
|
||||
}
|
||||
public static override NAME = "BMPString";
|
||||
|
||||
constructor({
|
||||
...parameters
|
||||
}: BmpStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 30; // BmpString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { LocalBooleanValueBlockParams, LocalBooleanValueBlock, LocalBooleanValueBlockJson } from "./internals/LocalBooleanValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface BooleanParams extends BaseBlockParams, LocalBooleanValueBlockParams { }
|
||||
export type BooleanJson = BaseBlockJson<LocalBooleanValueBlockJson>;
|
||||
|
||||
export class Boolean extends BaseBlock<LocalBooleanValueBlock, LocalBooleanValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.Boolean = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public getValue(): boolean {
|
||||
return this.valueBlock.value;
|
||||
}
|
||||
/**
|
||||
* Sets value
|
||||
* @param value Boolean value
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public setValue(value: boolean): void {
|
||||
this.valueBlock.value = value;
|
||||
}
|
||||
|
||||
public static override NAME = "BOOLEAN";
|
||||
|
||||
constructor(parameters: BooleanParams = {}) {
|
||||
super(parameters, LocalBooleanValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 1; // Boolean
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof Boolean).NAME} : ${this.getValue}`;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type CharacterStringParams = LocalSimpleStringBlockParams;
|
||||
export type CharacterStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class CharacterString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.CharacterString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "CharacterString";
|
||||
|
||||
constructor(parameters: CharacterStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 29; // CharacterString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { BaseBlock } from "./BaseBlock";
|
||||
import { IAny, Any } from "./Any";
|
||||
|
||||
export interface IChoice extends IAny {
|
||||
value: BaseBlock[];
|
||||
}
|
||||
|
||||
export type ChoiceParams = Partial<IChoice>;
|
||||
|
||||
export class Choice extends Any implements IChoice {
|
||||
public value: BaseBlock[];
|
||||
|
||||
constructor({
|
||||
value = [],
|
||||
...parameters
|
||||
}: ChoiceParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { LocalConstructedValueBlock, LocalConstructedValueBlockJson, LocalConstructedValueBlockParams } from "./internals/LocalConstructedValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface ConstructedParams extends BaseBlockParams, LocalConstructedValueBlockParams { }
|
||||
export type ConstructedJson = BaseBlockJson<LocalConstructedValueBlockJson>;
|
||||
|
||||
export class Constructed extends BaseBlock<LocalConstructedValueBlock, LocalConstructedValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.Constructed = this;
|
||||
}
|
||||
|
||||
public static override NAME = "CONSTRUCTED";
|
||||
|
||||
constructor(parameters: ConstructedParams = {}) {
|
||||
super(parameters, LocalConstructedValueBlock);
|
||||
|
||||
this.idBlock.isConstructed = true;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
|
||||
|
||||
const resultOffset = this.valueBlock.fromBER(inputBuffer, inputOffset, (this.lenBlock.isIndefiniteForm) ? inputLength : this.lenBlock.length);
|
||||
if (resultOffset === -1) {
|
||||
this.error = this.valueBlock.error;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
if (!this.idBlock.error.length)
|
||||
this.blockLength += this.idBlock.blockLength;
|
||||
|
||||
if (!this.lenBlock.error.length)
|
||||
this.blockLength += this.lenBlock.blockLength;
|
||||
|
||||
if (!this.valueBlock.error.length)
|
||||
this.blockLength += this.valueBlock.blockLength;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public override onAsciiEncoding(): string {
|
||||
const values = [];
|
||||
for (const value of this.valueBlock.value) {
|
||||
values.push(value.toString("ascii").split("\n").map(o => ` ${o}`).join("\n"));
|
||||
}
|
||||
const blockName = this.idBlock.tagClass === 3
|
||||
? `[${this.idBlock.tagNumber}]`
|
||||
: (this.constructor as typeof Constructed).NAME;
|
||||
|
||||
return values.length
|
||||
? `${blockName} :\n${values.join("\n")}` // items
|
||||
: `${blockName} :`; // empty
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { typeStore } from "./TypeStore";
|
||||
import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String";
|
||||
|
||||
export type DATEParams = Utf8StringParams;
|
||||
export type DATEJson = Utf8StringJson;
|
||||
|
||||
export class DATE extends Utf8String {
|
||||
|
||||
static {
|
||||
typeStore.DATE = this;
|
||||
}
|
||||
|
||||
public static override NAME = "DATE";
|
||||
|
||||
constructor(parameters: DATEParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 31; // DATE
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { typeStore } from "./TypeStore";
|
||||
import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String";
|
||||
|
||||
export type DateTimeParams = Utf8StringParams;
|
||||
export type DateTimeJson = Utf8StringJson;
|
||||
|
||||
export class DateTime extends Utf8String {
|
||||
|
||||
static {
|
||||
typeStore.DateTime = this;
|
||||
}
|
||||
|
||||
public static override NAME = "DateTime";
|
||||
|
||||
constructor(parameters: DateTimeParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 33; // DateTime
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { typeStore } from "./TypeStore";
|
||||
import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String";
|
||||
|
||||
export type DurationParams = Utf8StringParams;
|
||||
export type DurationJson = Utf8StringJson;
|
||||
|
||||
export class Duration extends Utf8String {
|
||||
|
||||
static {
|
||||
typeStore.Duration = this;
|
||||
}
|
||||
public static override NAME = "Duration";
|
||||
|
||||
constructor(parameters: DurationParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 34; // Duration
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { END_OF_CONTENT_NAME } from "./internals/constants";
|
||||
import { LocalEndOfContentValueBlock } from "./internals/LocalEndOfContentValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type EndOfContentParams = BaseBlockParams;
|
||||
export type EndOfContentJson = BaseBlockJson;
|
||||
|
||||
export class EndOfContent extends BaseBlock<LocalEndOfContentValueBlock> {
|
||||
|
||||
static {
|
||||
typeStore.EndOfContent = this;
|
||||
}
|
||||
public static override NAME = END_OF_CONTENT_NAME;
|
||||
|
||||
constructor(parameters: EndOfContentParams = {}) {
|
||||
super(parameters, LocalEndOfContentValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 0; // EndOfContent
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { IntegerParams, Integer, IntegerJson } from "./Integer";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type EnumeratedParams = IntegerParams;
|
||||
export type EnumeratedJson = IntegerJson;
|
||||
|
||||
export class Enumerated extends Integer {
|
||||
|
||||
static {
|
||||
typeStore.Enumerated = this;
|
||||
}
|
||||
|
||||
public static override NAME = "ENUMERATED";
|
||||
|
||||
constructor(parameters: EnumeratedParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 10; // Enumerated
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type GeneralStringParams = LocalSimpleStringBlockParams;
|
||||
export type GeneralStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class GeneralString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.GeneralString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "GeneralString";
|
||||
|
||||
constructor(parameters: GeneralStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 27; // GeneralString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
import * as pvutils from "pvutils";
|
||||
import { typeStore } from "./TypeStore";
|
||||
import { IUTCTime, UTCTimeParams, UTCTimeJson, UTCTime, DateStringEncoding } from "./UTCTime";
|
||||
|
||||
export interface IGeneralizedTime extends IUTCTime {
|
||||
millisecond: number;
|
||||
}
|
||||
|
||||
export type GeneralizedTimeParams = UTCTimeParams;
|
||||
|
||||
export interface GeneralizedTimeJson extends UTCTimeJson {
|
||||
millisecond: number;
|
||||
}
|
||||
|
||||
export class GeneralizedTime extends UTCTime {
|
||||
|
||||
static {
|
||||
typeStore.GeneralizedTime = this;
|
||||
}
|
||||
|
||||
public static override NAME = "GeneralizedTime";
|
||||
|
||||
public millisecond: number;
|
||||
|
||||
constructor(parameters: GeneralizedTimeParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.millisecond ??= 0;
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 24; // GeneralizedTime
|
||||
}
|
||||
|
||||
public override fromDate(inputDate: Date): void {
|
||||
super.fromDate(inputDate);
|
||||
this.millisecond = inputDate.getUTCMilliseconds();
|
||||
}
|
||||
|
||||
public override toDate(): Date {
|
||||
return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)));
|
||||
}
|
||||
|
||||
public override fromString(inputString: string): void {
|
||||
//#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.substring(0, inputString.length - 1);
|
||||
|
||||
isUTC = true;
|
||||
}
|
||||
//#endregion
|
||||
//#region Convert as local time
|
||||
else {
|
||||
const number = new Number(inputString[inputString.length - 1]);
|
||||
|
||||
if (isNaN(number.valueOf()))
|
||||
throw new Error("Wrong input string for conversion");
|
||||
|
||||
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 conversion");
|
||||
|
||||
if (timeString.indexOf("-") !== -1)
|
||||
throw new Error("Wrong input string for conversion");
|
||||
}
|
||||
//#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.substring(differencePosition + 1);
|
||||
timeString = timeString.substring(0, differencePosition);
|
||||
|
||||
if ((differenceString.length !== 2) && (differenceString.length !== 4))
|
||||
throw new Error("Wrong input string for conversion");
|
||||
|
||||
let number = parseInt(differenceString.substring(0, 2), 10);
|
||||
|
||||
if (isNaN(number.valueOf()))
|
||||
throw new Error("Wrong input string for conversion");
|
||||
|
||||
hourDifference = multiplier * number;
|
||||
|
||||
if (differenceString.length === 4) {
|
||||
number = parseInt(differenceString.substring(2, 4), 10);
|
||||
|
||||
if (isNaN(number.valueOf()))
|
||||
throw new Error("Wrong input string for conversion");
|
||||
|
||||
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) {
|
||||
const fractionPartCheck = new Number(`0${timeString.substring(fractionPointPosition)}`);
|
||||
|
||||
if (isNaN(fractionPartCheck.valueOf()))
|
||||
throw new Error("Wrong input string for conversion");
|
||||
|
||||
fractionPart = fractionPartCheck.valueOf();
|
||||
|
||||
dateTimeString = timeString.substring(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 conversion"); // 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 conversion");
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Put parsed values at right places
|
||||
const parserArray = parser.exec(dateTimeString);
|
||||
if (parserArray === null)
|
||||
throw new Error("Wrong input string for conversion");
|
||||
|
||||
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 conversion");
|
||||
}
|
||||
}
|
||||
//#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
|
||||
}
|
||||
|
||||
public override toString(encoding: DateStringEncoding = "iso"): string {
|
||||
if (encoding === "iso") {
|
||||
const outputArray = [];
|
||||
|
||||
outputArray.push(pvutils.padNumber(this.year, 4));
|
||||
outputArray.push(pvutils.padNumber(this.month, 2));
|
||||
outputArray.push(pvutils.padNumber(this.day, 2));
|
||||
outputArray.push(pvutils.padNumber(this.hour, 2));
|
||||
outputArray.push(pvutils.padNumber(this.minute, 2));
|
||||
outputArray.push(pvutils.padNumber(this.second, 2));
|
||||
if (this.millisecond !== 0) {
|
||||
outputArray.push(".");
|
||||
outputArray.push(pvutils.padNumber(this.millisecond, 3));
|
||||
}
|
||||
outputArray.push("Z");
|
||||
|
||||
return outputArray.join("");
|
||||
}
|
||||
|
||||
return super.toString(encoding);
|
||||
}
|
||||
|
||||
public override toJSON(): GeneralizedTimeJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
millisecond: this.millisecond,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type GraphicStringParams = LocalSimpleStringBlockParams;
|
||||
export type GraphicStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class GraphicString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.GraphicString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "GraphicString";
|
||||
|
||||
constructor(parameters: GraphicStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 25; // GraphicString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||
import * as pvtsutils from "pvtsutils";
|
||||
import { IBerConvertible } from "./types";
|
||||
import { EMPTY_BUFFER, EMPTY_VIEW } from "./internals/constants";
|
||||
import { LocalBaseBlockConstructor } from "./internals/LocalBaseBlock";
|
||||
import { checkBufferParams } from "./internals/utils";
|
||||
|
||||
export interface IHexBlock {
|
||||
isHexOnly: boolean;
|
||||
valueHex: pvtsutils.BufferSource;
|
||||
}
|
||||
|
||||
export interface HexBlockJson extends Omit<IHexBlock, "valueHex"> {
|
||||
valueHex: string;
|
||||
}
|
||||
|
||||
export type HexBlockParams = Partial<IHexBlock>;
|
||||
/**
|
||||
* Class used as a base block for all remaining ASN.1 classes
|
||||
*/
|
||||
export function HexBlock<T extends LocalBaseBlockConstructor>(BaseClass: T) {
|
||||
return class Some extends BaseClass implements IHexBlock, IBerConvertible {
|
||||
|
||||
public static override NAME = "hexBlock";
|
||||
|
||||
public isHexOnly: boolean;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
public get valueHex(): ArrayBuffer {
|
||||
return this.valueHexView.slice().buffer;
|
||||
}
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
public set valueHex(value: ArrayBuffer) {
|
||||
this.valueHexView = new Uint8Array(value);
|
||||
}
|
||||
/**
|
||||
* Binary data in Uint8Array representation
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public valueHexView: Uint8Array;
|
||||
|
||||
constructor(...args: any[]) {
|
||||
super(...args);
|
||||
|
||||
const params: HexBlockParams = args[0] || {};
|
||||
this.isHexOnly = params.isHexOnly ?? false;
|
||||
this.valueHexView = params.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(params.valueHex) : EMPTY_VIEW;
|
||||
}
|
||||
|
||||
public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
// Basic check for parameters
|
||||
const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer;
|
||||
if (!checkBufferParams(this, view, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const endLength = inputOffset + inputLength;
|
||||
|
||||
// Initial checks
|
||||
this.valueHexView = view.subarray(inputOffset, endLength);
|
||||
if (!this.valueHexView.length) {
|
||||
this.warnings.push("Zero buffer length");
|
||||
|
||||
return inputOffset;
|
||||
}
|
||||
|
||||
this.blockLength = inputLength;
|
||||
|
||||
return endLength;
|
||||
}
|
||||
|
||||
public toBER(sizeOnly = false): ArrayBuffer {
|
||||
if (!this.isHexOnly) {
|
||||
this.error = "Flag 'isHexOnly' is not set, abort";
|
||||
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
if (sizeOnly) {
|
||||
return new ArrayBuffer(this.valueHexView.byteLength);
|
||||
}
|
||||
|
||||
// Don't copy data if View is not offset
|
||||
return (this.valueHexView.byteLength === this.valueHexView.buffer.byteLength)
|
||||
? this.valueHexView.buffer
|
||||
: this.valueHexView.slice().buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON representation of an object
|
||||
* @returns JSON object
|
||||
*/
|
||||
public override toJSON() {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
isHexOnly: this.isHexOnly,
|
||||
valueHex: pvtsutils.Convert.ToHex(this.valueHexView),
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type IA5StringParams = LocalSimpleStringBlockParams;
|
||||
export type IA5StringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class IA5String extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.IA5String = this;
|
||||
}
|
||||
|
||||
public static override NAME = "IA5String";
|
||||
|
||||
constructor(parameters: IA5StringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 22; // IA5String
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { LocalIntegerValueBlockParams, LocalIntegerValueBlock, LocalIntegerValueBlockJson } from "./internals/LocalIntegerValueBlock";
|
||||
import { assertBigInt } from "./internals/utils";
|
||||
import { typeStore } from "./TypeStore";
|
||||
import { ViewWriter } from "./ViewWriter";
|
||||
|
||||
export interface IntegerParams extends BaseBlockParams, LocalIntegerValueBlockParams { }
|
||||
export type IntegerJson = BaseBlockJson<LocalIntegerValueBlockJson>;
|
||||
|
||||
export class Integer extends BaseBlock<LocalIntegerValueBlock, LocalIntegerValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.Integer = this;
|
||||
}
|
||||
|
||||
public static override NAME = "INTEGER";
|
||||
|
||||
constructor(parameters: IntegerParams = {}) {
|
||||
super(parameters, LocalIntegerValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 2; // Integer
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Integer into BigInt
|
||||
* @throws Throws Error if BigInt is not supported
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public toBigInt(): bigint {
|
||||
assertBigInt();
|
||||
|
||||
return BigInt(this.valueBlock.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Integer from BigInt value
|
||||
* @param value BigInt value
|
||||
* @returns ASN.1 Integer
|
||||
* @throws Throws Error if BigInt is not supported
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static fromBigInt(value: number | string | bigint | boolean): Integer {
|
||||
assertBigInt();
|
||||
|
||||
const bigIntValue = BigInt(value);
|
||||
const writer = new ViewWriter();
|
||||
|
||||
const hex = bigIntValue.toString(16).replace(/^-/, "");
|
||||
const view = new Uint8Array(pvtsutils.Convert.FromHex(hex));
|
||||
|
||||
if (bigIntValue < 0) {
|
||||
// a negative number
|
||||
const first = new Uint8Array(view.length + (view[0] & 0x80 ? 1 : 0));
|
||||
first[0] |= 0x80;
|
||||
|
||||
const firstInt = BigInt(`0x${pvtsutils.Convert.ToHex(first)}`);
|
||||
const secondInt = firstInt + bigIntValue;
|
||||
const second = pvtsutils.BufferSourceConverter.toUint8Array(pvtsutils.Convert.FromHex(secondInt.toString(16)));
|
||||
second[0] |= 0x80;
|
||||
|
||||
writer.write(second);
|
||||
} else {
|
||||
// a positive number
|
||||
if (view[0] & 0x80) {
|
||||
writer.write(new Uint8Array([0]));
|
||||
}
|
||||
writer.write(view);
|
||||
}
|
||||
|
||||
const res = new Integer({
|
||||
valueHex: writer.final(),
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public convertToDER(): Integer {
|
||||
const integer = new Integer({ valueHex: this.valueBlock.valueHexView });
|
||||
|
||||
integer.valueBlock.toDER();
|
||||
|
||||
return integer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert current Integer value from DER to BER format
|
||||
* @returns
|
||||
*/
|
||||
public convertFromDER(): Integer {
|
||||
return new Integer({
|
||||
valueHex: this.valueBlock.valueHexView[0] === 0
|
||||
? this.valueBlock.valueHexView.subarray(1)
|
||||
: this.valueBlock.valueHexView,
|
||||
});
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof Integer).NAME} : ${this.valueBlock.toString()}`;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
import { ViewWriter } from "./ViewWriter";
|
||||
import { ValueBlock, ValueBlockJson } from "./ValueBlock";
|
||||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type NullParams = BaseBlockParams;
|
||||
export type NullJson = BaseBlockJson<ValueBlockJson>;
|
||||
|
||||
export class Null extends BaseBlock<ValueBlock, ValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.Null = this;
|
||||
}
|
||||
|
||||
public static override NAME = "NULL";
|
||||
|
||||
constructor(parameters: NullParams = {}) {
|
||||
super(parameters, ValueBlock); // We will not have a call to "Null value block" because of specified FROM_BER and TO_BER functions
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 5; // Null
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
if (this.lenBlock.length > 0)
|
||||
this.warnings.push("Non-zero length of value block for Null type");
|
||||
|
||||
if (!this.idBlock.error.length)
|
||||
this.blockLength += this.idBlock.blockLength;
|
||||
|
||||
if (!this.lenBlock.error.length)
|
||||
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);
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
const retBuf = new ArrayBuffer(2);
|
||||
|
||||
if (!sizeOnly) {
|
||||
const retView = new Uint8Array(retBuf);
|
||||
retView[0] = 0x05;
|
||||
retView[1] = 0x00;
|
||||
}
|
||||
|
||||
if (writer) {
|
||||
writer.write(retBuf);
|
||||
}
|
||||
|
||||
return retBuf;
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof Null).NAME}`;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type NumericStringParams = LocalSimpleStringBlockParams;
|
||||
export type NumericStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class NumericString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.NumericString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "NumericString";
|
||||
|
||||
constructor(parameters: NumericStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 18; // NumericString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { LocalObjectIdentifierValueBlockParams, LocalObjectIdentifierValueBlock, LocalObjectIdentifierValueBlockJson } from "./internals/LocalObjectIdentifierValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface ObjectIdentifierParams extends BaseBlockParams, LocalObjectIdentifierValueBlockParams { }
|
||||
export interface ObjectIdentifierJson extends BaseBlockJson<LocalObjectIdentifierValueBlockJson> {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export class ObjectIdentifier extends BaseBlock<LocalObjectIdentifierValueBlock, LocalObjectIdentifierValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.ObjectIdentifier = this;
|
||||
}
|
||||
|
||||
public static override NAME = "OBJECT IDENTIFIER";
|
||||
|
||||
/**
|
||||
* Gets string representation of Object Identifier
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public getValue(): string {
|
||||
return this.valueBlock.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Object Identifier value from string
|
||||
* @param value String value
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public setValue(value: string): void {
|
||||
this.valueBlock.fromString(value);
|
||||
}
|
||||
|
||||
constructor(parameters: ObjectIdentifierParams = {}) {
|
||||
super(parameters, LocalObjectIdentifierValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 6; // OBJECT IDENTIFIER
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof ObjectIdentifier).NAME} : ${this.valueBlock.toString() || "empty"}`;
|
||||
}
|
||||
|
||||
public override toJSON(): ObjectIdentifierJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
value: this.getValue(),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { Constructed } from "./Constructed";
|
||||
import { LocalOctetStringValueBlockParams, LocalOctetStringValueBlock, LocalOctetStringValueBlockJson } from "./internals/LocalOctetStringValueBlock";
|
||||
import { OCTET_STRING_NAME } from "./internals/constants";
|
||||
import { localFromBER } from "./parser";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface OctetStringParams extends BaseBlockParams, LocalOctetStringValueBlockParams { }
|
||||
export type OctetStringJson = BaseBlockJson<LocalOctetStringValueBlockJson>;
|
||||
|
||||
export class OctetString extends BaseBlock<LocalOctetStringValueBlock, LocalOctetStringValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.OctetString = this;
|
||||
}
|
||||
|
||||
public static override NAME = OCTET_STRING_NAME;
|
||||
|
||||
constructor({
|
||||
idBlock = {},
|
||||
lenBlock = {},
|
||||
...parameters
|
||||
}: OctetStringParams = {}) {
|
||||
parameters.isConstructed ??= !!parameters.value?.length;
|
||||
super({
|
||||
idBlock: {
|
||||
isConstructed: parameters.isConstructed,
|
||||
...idBlock,
|
||||
},
|
||||
lenBlock: {
|
||||
...lenBlock,
|
||||
isIndefiniteForm: !!parameters.isIndefiniteForm,
|
||||
},
|
||||
...parameters,
|
||||
}, LocalOctetStringValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 4; // OctetString
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
this.valueBlock.isConstructed = this.idBlock.isConstructed;
|
||||
this.valueBlock.isIndefiniteForm = this.lenBlock.isIndefiniteForm;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (!this.valueBlock.isConstructed) {
|
||||
const view = inputBuffer instanceof ArrayBuffer ? new Uint8Array(inputBuffer) : inputBuffer;
|
||||
const buf = view.subarray(inputOffset, inputOffset + inputLength);
|
||||
try {
|
||||
if (buf.byteLength) {
|
||||
const asn = localFromBER(buf, 0, buf.byteLength);
|
||||
if (asn.offset !== -1 && asn.offset === inputLength) {
|
||||
this.valueBlock.value = [asn.result as OctetString];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
return super.fromBER(inputBuffer, inputOffset, inputLength);
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
if (this.valueBlock.isConstructed || (this.valueBlock.value && this.valueBlock.value.length)) {
|
||||
return Constructed.prototype.onAsciiEncoding.call(this);
|
||||
}
|
||||
|
||||
return `${(this.constructor as typeof OctetString).NAME} : ${pvtsutils.Convert.ToHex(this.valueBlock.valueHexView)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns OctetString value. If OctetString is constructed, returns concatenated internal OctetString values
|
||||
* @returns Array buffer
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public getValue(): ArrayBuffer {
|
||||
if (!this.idBlock.isConstructed) {
|
||||
return this.valueBlock.valueHexView.slice().buffer;
|
||||
}
|
||||
|
||||
const array: ArrayBuffer[] = [];
|
||||
for (const content of this.valueBlock.value) {
|
||||
if (content instanceof OctetString) {
|
||||
array.push(content.valueBlock.valueHexView);
|
||||
}
|
||||
}
|
||||
|
||||
return pvtsutils.BufferSourceConverter.concat(array);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { LocalPrimitiveValueBlock, LocalPrimitiveValueBlockJson, LocalPrimitiveValueBlockParams } from "./internals/LocalPrimitiveValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface PrimitiveParams extends BaseBlockParams, LocalPrimitiveValueBlockParams { }
|
||||
export type PrimitiveJson = BaseBlockJson<LocalPrimitiveValueBlockJson>;
|
||||
|
||||
export class Primitive extends BaseBlock<LocalPrimitiveValueBlock, LocalPrimitiveValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.Primitive = this;
|
||||
}
|
||||
|
||||
public static override NAME = "PRIMITIVE";
|
||||
|
||||
constructor(parameters: PrimitiveParams = {}) {
|
||||
super(parameters, LocalPrimitiveValueBlock);
|
||||
|
||||
this.idBlock.isConstructed = false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type PrintableStringParams = LocalSimpleStringBlockParams;
|
||||
export type PrintableStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class PrintableString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.PrintableString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "PrintableString";
|
||||
|
||||
constructor(parameters: PrintableStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 19; // PrintableString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { IBerConvertible } from "./types";
|
||||
import { EMPTY_VIEW } from "./internals/constants";
|
||||
|
||||
export interface IRawData {
|
||||
data: ArrayBuffer;
|
||||
}
|
||||
|
||||
export type RawDataParams = Partial<IRawData>;
|
||||
|
||||
/**
|
||||
* Special class providing ability to have "toBER/fromBER" for raw ArrayBuffer
|
||||
*/
|
||||
export class RawData implements IBerConvertible {
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Since v3.0.0
|
||||
*/
|
||||
public get data(): ArrayBuffer {
|
||||
return this.dataView.slice().buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Since v3.0.0
|
||||
*/
|
||||
public set data(value: ArrayBuffer) {
|
||||
this.dataView = pvtsutils.BufferSourceConverter.toUint8Array(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public dataView: Uint8Array;
|
||||
|
||||
constructor({ data = EMPTY_VIEW }: RawDataParams = {}) {
|
||||
this.dataView = pvtsutils.BufferSourceConverter.toUint8Array(data);
|
||||
}
|
||||
|
||||
public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const endLength = inputOffset + inputLength;
|
||||
this.dataView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer).subarray(inputOffset, endLength);
|
||||
|
||||
return endLength;
|
||||
}
|
||||
|
||||
public toBER(sizeOnly?: boolean): ArrayBuffer {
|
||||
return this.dataView.slice().buffer;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
import { BaseBlock, BaseBlockJson, BaseBlockParams } from "./BaseBlock";
|
||||
import { LocalRelativeObjectIdentifierValueBlockParams, LocalRelativeObjectIdentifierValueBlock, LocalRelativeObjectIdentifierValueBlockJson } from "./internals/LocalRelativeObjectIdentifierValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
|
||||
export interface RelativeObjectIdentifierParams extends BaseBlockParams, LocalRelativeObjectIdentifierValueBlockParams { }
|
||||
export interface RelativeObjectIdentifierJson extends BaseBlockJson<LocalRelativeObjectIdentifierValueBlockJson> {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export class RelativeObjectIdentifier extends BaseBlock<LocalRelativeObjectIdentifierValueBlock, LocalRelativeObjectIdentifierValueBlockJson> {
|
||||
|
||||
static {
|
||||
typeStore.RelativeObjectIdentifier = this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets string representation of Relative Object Identifier
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public getValue(): string {
|
||||
return this.valueBlock.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Relative Object Identifier value from string
|
||||
* @param value String value
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public setValue(value: string): void {
|
||||
this.valueBlock.fromString(value);
|
||||
}
|
||||
|
||||
public static override NAME = "RelativeObjectIdentifier";
|
||||
|
||||
constructor(parameters: RelativeObjectIdentifierParams = {}) {
|
||||
super(parameters, LocalRelativeObjectIdentifierValueBlock);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 13; // RELATIVE OBJECT IDENTIFIER
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof RelativeObjectIdentifier).NAME} : ${this.valueBlock.toString() || "empty"}`;
|
||||
}
|
||||
|
||||
public override toJSON(): RelativeObjectIdentifierJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
value: this.getValue(),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import { IAny, Any } from "./Any";
|
||||
|
||||
export interface IRepeated extends IAny {
|
||||
value: Any;
|
||||
local: boolean;
|
||||
}
|
||||
|
||||
export type RepeatedParams = Partial<IRepeated>;
|
||||
|
||||
export class Repeated extends Any {
|
||||
|
||||
public value: Any;
|
||||
public local: boolean;
|
||||
|
||||
constructor({
|
||||
value = new Any(),
|
||||
local = false,
|
||||
...parameters
|
||||
}: RepeatedParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.value = value;
|
||||
this.local = local; // Could local or global array to store elements
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { ConstructedParams, Constructed, ConstructedJson } from "./Constructed";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type SequenceParams = ConstructedParams;
|
||||
export type SequenceJson = ConstructedJson;
|
||||
|
||||
export class Sequence extends Constructed {
|
||||
|
||||
static {
|
||||
typeStore.Sequence = this;
|
||||
}
|
||||
|
||||
public static override NAME = "SEQUENCE";
|
||||
|
||||
constructor(parameters: SequenceParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 16; // Sequence
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { ConstructedParams, Constructed, ConstructedJson } from "./Constructed";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type SetParams = ConstructedParams;
|
||||
export type SetJson = ConstructedJson;
|
||||
|
||||
export class Set extends Constructed {
|
||||
|
||||
static {
|
||||
typeStore.Set = this;
|
||||
}
|
||||
|
||||
public static override NAME = "SET";
|
||||
|
||||
constructor(parameters: SetParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 17; // Set
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { typeStore } from "./TypeStore";
|
||||
import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String";
|
||||
|
||||
export type TIMEParams = Utf8StringParams;
|
||||
export type TIMEJson = Utf8StringJson;
|
||||
|
||||
export class TIME extends Utf8String {
|
||||
|
||||
static {
|
||||
typeStore.TIME = this;
|
||||
}
|
||||
|
||||
public static override NAME = "TIME";
|
||||
|
||||
constructor(parameters: TIMEParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 14; // Time
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type TeletexStringParams = LocalSimpleStringBlockParams;
|
||||
export type TeletexStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class TeletexString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.TeletexString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "TeletexString";
|
||||
|
||||
constructor(parameters: TeletexStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 20; // TeletexString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { typeStore } from "./TypeStore";
|
||||
import { Utf8StringParams, Utf8String, Utf8StringJson } from "./Utf8String";
|
||||
|
||||
export type TimeOfDayParams = Utf8StringParams;
|
||||
export type TimeOfDayJson = Utf8StringJson;
|
||||
|
||||
export class TimeOfDay extends Utf8String {
|
||||
|
||||
static {
|
||||
typeStore.TimeOfDay = this;
|
||||
}
|
||||
|
||||
public static override NAME = "TimeOfDay";
|
||||
|
||||
constructor(parameters: TimeOfDayParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 32; // TimeOfDay
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
import type { BaseBlock } from "./BaseBlock";
|
||||
import type { BitString } from "./BitString";
|
||||
import type { BmpString } from "./BmpString";
|
||||
import type { Boolean as AsnBoolean } from "./Boolean";
|
||||
import type { CharacterString } from "./CharacterString";
|
||||
import type { Constructed } from "./Constructed";
|
||||
import type { DATE } from "./DATE";
|
||||
import type { DateTime } from "./DateTime";
|
||||
import type { Duration } from "./Duration";
|
||||
import type { EndOfContent } from "./EndOfContent";
|
||||
import type { Enumerated } from "./Enumerated";
|
||||
import type { GeneralizedTime } from "./GeneralizedTime";
|
||||
import type { GeneralString } from "./GeneralString";
|
||||
import type { GraphicString } from "./GraphicString";
|
||||
import type { IA5String } from "./IA5String";
|
||||
import type { Integer } from "./Integer";
|
||||
import type { Null } from "./Null";
|
||||
import type { NumericString } from "./NumericString";
|
||||
import type { ObjectIdentifier } from "./ObjectIdentifier";
|
||||
import type { OctetString } from "./OctetString";
|
||||
import type { Primitive } from "./Primitive";
|
||||
import type { PrintableString } from "./PrintableString";
|
||||
import type { RelativeObjectIdentifier } from "./RelativeObjectIdentifier";
|
||||
import type { Sequence } from "./Sequence";
|
||||
import type { Set } from "./Set";
|
||||
import type { TeletexString } from "./TeletexString";
|
||||
import type { TIME } from "./TIME";
|
||||
import type { TimeOfDay } from "./TimeOfDay";
|
||||
import type { UniversalString } from "./UniversalString";
|
||||
import type { UTCTime } from "./UTCTime";
|
||||
import type { Utf8String } from "./Utf8String";
|
||||
import type { VideotexString } from "./VideotexString";
|
||||
import type { VisibleString } from "./VisibleString";
|
||||
|
||||
export type AsnType = BaseBlock | EndOfContent | AsnBoolean | Integer | BitString | OctetString | Null | ObjectIdentifier | Enumerated | Utf8String | RelativeObjectIdentifier | TIME | Sequence | Set | NumericString | PrintableString | TeletexString | VideotexString | IA5String | UTCTime | GeneralizedTime | GraphicString | VisibleString | GeneralString | UniversalString | CharacterString | BmpString | DATE | TimeOfDay | DateTime | Duration | Constructed | Primitive;
|
||||
|
||||
export interface TypeStore {
|
||||
BitString: typeof BitString;
|
||||
BmpString: typeof BmpString;
|
||||
Boolean: typeof AsnBoolean;
|
||||
CharacterString: typeof CharacterString;
|
||||
Constructed: typeof Constructed;
|
||||
DATE: typeof DATE;
|
||||
DateTime: typeof DateTime;
|
||||
Duration: typeof Duration;
|
||||
EndOfContent: typeof EndOfContent;
|
||||
Enumerated: typeof Enumerated;
|
||||
GeneralizedTime: typeof GeneralizedTime;
|
||||
GeneralString: typeof GeneralString;
|
||||
GraphicString: typeof GraphicString;
|
||||
IA5String: typeof IA5String;
|
||||
Integer: typeof Integer;
|
||||
Null: typeof Null;
|
||||
NumericString: typeof NumericString;
|
||||
ObjectIdentifier: typeof ObjectIdentifier;
|
||||
OctetString: typeof OctetString;
|
||||
Primitive: typeof Primitive;
|
||||
PrintableString: typeof PrintableString;
|
||||
RelativeObjectIdentifier: typeof RelativeObjectIdentifier;
|
||||
Sequence: typeof Sequence;
|
||||
Set: typeof Set;
|
||||
TeletexString: typeof TeletexString;
|
||||
TIME: typeof TIME;
|
||||
TimeOfDay: typeof TimeOfDay;
|
||||
UniversalString: typeof UniversalString;
|
||||
UTCTime: typeof UTCTime;
|
||||
Utf8String: typeof Utf8String;
|
||||
VideotexString: typeof VideotexString;
|
||||
VisibleString: typeof VisibleString;
|
||||
}
|
||||
export const typeStore = {} as TypeStore;
|
|
@ -0,0 +1,172 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { BaseBlockJson, StringEncoding } from "./BaseBlock";
|
||||
import { LocalSimpleStringValueBlockJson } from "./internals/LocalSimpleStringValueBlock";
|
||||
import { IDateConvertible } from "./types";
|
||||
import { typeStore } from "./TypeStore";
|
||||
import { VisibleStringParams, VisibleString } from "./VisibleString";
|
||||
|
||||
export interface IUTCTime {
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
}
|
||||
|
||||
export interface UTCTimeParams extends VisibleStringParams {
|
||||
value?: string;
|
||||
valueDate?: Date;
|
||||
}
|
||||
export interface UTCTimeJson extends BaseBlockJson<LocalSimpleStringValueBlockJson>, IUTCTime { }
|
||||
|
||||
export type DateStringEncoding = StringEncoding | "iso";
|
||||
|
||||
export class UTCTime extends VisibleString implements IUTCTime, IDateConvertible {
|
||||
|
||||
static {
|
||||
typeStore.UTCTime = this;
|
||||
}
|
||||
|
||||
public static override NAME = "UTCTime";
|
||||
|
||||
public year: number;
|
||||
public month: number;
|
||||
public day: number;
|
||||
public hour: number;
|
||||
public minute: number;
|
||||
public second: number;
|
||||
|
||||
constructor({
|
||||
value,
|
||||
valueDate,
|
||||
...parameters
|
||||
}: UTCTimeParams = {}) {
|
||||
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) {
|
||||
this.fromString(value);
|
||||
|
||||
this.valueBlock.valueHexView = new Uint8Array(value.length);
|
||||
|
||||
for (let i = 0; i < value.length; i++)
|
||||
this.valueBlock.valueHexView[i] = value.charCodeAt(i);
|
||||
}
|
||||
//#endregion
|
||||
//#region Create GeneralizedTime from JavaScript Date type
|
||||
if (valueDate) {
|
||||
this.fromDate(valueDate);
|
||||
this.valueBlock.valueHexView = new Uint8Array(this.toBuffer());
|
||||
}
|
||||
//#endregion
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 23; // UTCTime
|
||||
}
|
||||
|
||||
public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void {
|
||||
this.fromString(String.fromCharCode.apply(null, pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer) as unknown as number[]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Function converting ASN.1 internal string into ArrayBuffer
|
||||
* @returns
|
||||
*/
|
||||
public toBuffer(): ArrayBuffer {
|
||||
const str = this.toString(); // TODO use this.valueBlock.value and update 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
|
||||
*/
|
||||
public fromDate(inputDate: Date): void {
|
||||
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();
|
||||
}
|
||||
|
||||
public toDate(): Date {
|
||||
return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)));
|
||||
}
|
||||
|
||||
public override fromString(inputString: string): void {
|
||||
//#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 conversion";
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
public override toString(encoding: DateStringEncoding = "iso"): string {
|
||||
if (encoding === "iso") {
|
||||
const outputArray = new Array(7);
|
||||
|
||||
outputArray[0] = pvutils.padNumber(((this.year < 2000) ? (this.year - 1900) : (this.year - 2000)), 2);
|
||||
outputArray[1] = pvutils.padNumber(this.month, 2);
|
||||
outputArray[2] = pvutils.padNumber(this.day, 2);
|
||||
outputArray[3] = pvutils.padNumber(this.hour, 2);
|
||||
outputArray[4] = pvutils.padNumber(this.minute, 2);
|
||||
outputArray[5] = pvutils.padNumber(this.second, 2);
|
||||
outputArray[6] = "Z";
|
||||
|
||||
return outputArray.join("");
|
||||
}
|
||||
|
||||
return super.toString(encoding);
|
||||
}
|
||||
|
||||
protected override onAsciiEncoding(): string {
|
||||
return `${(this.constructor as typeof UTCTime).NAME} : ${this.toDate().toISOString()}`;
|
||||
}
|
||||
|
||||
public override toJSON(): UTCTimeJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
year: this.year,
|
||||
month: this.month,
|
||||
day: this.day,
|
||||
hour: this.hour,
|
||||
minute: this.minute,
|
||||
second: this.second,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { LocalUniversalStringValueBlockParams, LocalUniversalStringValueBlock, LocalUniversalStringValueBlockJson } from "./internals/LocalUniversalStringValueBlockParams";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type UniversalStringParams = LocalUniversalStringValueBlockParams;
|
||||
export type UniversalStringJson = LocalUniversalStringValueBlockJson;
|
||||
|
||||
export class UniversalString extends LocalUniversalStringValueBlock {
|
||||
|
||||
static {
|
||||
typeStore.UniversalString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "UniversalString";
|
||||
|
||||
constructor({
|
||||
...parameters
|
||||
}: UniversalStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 28; // UniversalString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { BaseBlockJson } from "./BaseBlock";
|
||||
import { BaseStringBlockParams } from "./BaseStringBlock";
|
||||
import { LocalUtf8StringValueBlockParams, LocalUtf8StringValueBlock, LocalUtf8StringValueBlockJson } from "./internals/LocalUtf8StringValueBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export interface Utf8StringParams extends BaseStringBlockParams, LocalUtf8StringValueBlockParams { }
|
||||
export type Utf8StringJson = BaseBlockJson<LocalUtf8StringValueBlockJson>;
|
||||
|
||||
export class Utf8String extends LocalUtf8StringValueBlock {
|
||||
|
||||
static {
|
||||
typeStore.Utf8String = this;
|
||||
}
|
||||
|
||||
public static override NAME = "UTF8String";
|
||||
|
||||
constructor(parameters: Utf8StringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 12; // Utf8String
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import { IBerConvertible } from "./types";
|
||||
import * as internals from "./internals/LocalBaseBlock";
|
||||
import { ViewWriter } from "./ViewWriter";
|
||||
|
||||
export type IValueBlock = internals.ILocalBaseBlock;
|
||||
export type ValueBlockParams = internals.LocalBaseBlockParams;
|
||||
export type ValueBlockJson = internals.LocalBaseBlockJson;
|
||||
|
||||
export class ValueBlock extends internals.LocalBaseBlock implements IValueBlock, IBerConvertible {
|
||||
|
||||
public static override NAME = "valueBlock";
|
||||
|
||||
public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'");
|
||||
}
|
||||
|
||||
public toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
throw TypeError("User need to make a specific function in a class which extends 'ValueBlock'");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type VideotexStringParams = LocalSimpleStringBlockParams;
|
||||
export type VideotexStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class VideotexString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.VideotexString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "VideotexString";
|
||||
|
||||
constructor(parameters: VideotexStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 21; // VideotexString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import * as utils from "./internals/utils";
|
||||
|
||||
export class ViewWriter {
|
||||
|
||||
public items: ArrayBuffer[] = [];
|
||||
|
||||
/**
|
||||
* Writes buffer
|
||||
* @param buf
|
||||
*/
|
||||
public write(buf: ArrayBuffer): void {
|
||||
this.items.push(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates all buffers
|
||||
* @returns Concatenated buffer
|
||||
*/
|
||||
public final(): ArrayBuffer {
|
||||
return utils.concat(this.items);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
import { LocalSimpleStringBlockParams, LocalSimpleStringBlock, LocalSimpleStringBlockJson } from "./internals/LocalSimpleStringBlock";
|
||||
import { typeStore } from "./TypeStore";
|
||||
|
||||
export type VisibleStringParams = LocalSimpleStringBlockParams;
|
||||
export type VisibleStringJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class VisibleString extends LocalSimpleStringBlock {
|
||||
|
||||
static {
|
||||
typeStore.VisibleString = this;
|
||||
}
|
||||
|
||||
public static override NAME = "VisibleString";
|
||||
|
||||
constructor(parameters: VisibleStringParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.idBlock.tagClass = 1; // UNIVERSAL
|
||||
this.idBlock.tagNumber = 26; // VisibleString
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
export * from "./types";
|
||||
|
||||
// basic
|
||||
export * from "./ViewWriter";
|
||||
export * from "./HexBlock";
|
||||
export * from "./ValueBlock";
|
||||
export * from "./BaseBlock";
|
||||
export * from "./BaseStringBlock";
|
||||
|
||||
export * from "./Primitive";
|
||||
export * from "./Constructed";
|
||||
export * from "./EndOfContent";
|
||||
|
||||
// common
|
||||
export * from "./Null";
|
||||
export * from "./Boolean";
|
||||
export * from "./OctetString";
|
||||
export * from "./BitString";
|
||||
export * from "./Integer";
|
||||
export * from "./Enumerated";
|
||||
export * from "./ObjectIdentifier";
|
||||
export * from "./RelativeObjectIdentifier";
|
||||
export * from "./Sequence";
|
||||
export * from "./Set";
|
||||
|
||||
// strings
|
||||
export * from "./Utf8String";
|
||||
export * from "./BmpString";
|
||||
export * from "./UniversalString";
|
||||
export * from "./NumericString";
|
||||
export * from "./PrintableString";
|
||||
export * from "./TeletexString";
|
||||
export * from "./VideotexString";
|
||||
export * from "./IA5String";
|
||||
export * from "./GraphicString";
|
||||
export * from "./VisibleString";
|
||||
export * from "./GeneralString";
|
||||
export * from "./CharacterString";
|
||||
|
||||
// date and time
|
||||
export * from "./UTCTime";
|
||||
export * from "./GeneralizedTime";
|
||||
export * from "./DATE";
|
||||
export * from "./TimeOfDay";
|
||||
export * from "./DateTime";
|
||||
export * from "./Duration";
|
||||
export * from "./TIME";
|
||||
|
||||
// schema types
|
||||
export * from "./Any";
|
||||
export * from "./Choice";
|
||||
export * from "./Repeated";
|
||||
|
||||
// special
|
||||
export * from "./RawData";
|
||||
|
||||
export { FromBerResult, fromBER } from "./parser";
|
||||
export * from "./schema";
|
||||
export { AsnType } from "./TypeStore";
|
|
@ -0,0 +1,93 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { EMPTY_STRING, EMPTY_VIEW } from "./constants";
|
||||
|
||||
export interface ILocalBaseBlock {
|
||||
blockLength: number;
|
||||
error: string;
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
export interface LocalBaseBlockJson extends ILocalBaseBlock {
|
||||
blockName: string;
|
||||
valueBeforeDecode: string;
|
||||
}
|
||||
|
||||
export interface LocalBaseBlockParams extends Partial<ILocalBaseBlock> {
|
||||
valueBeforeDecode?: pvtsutils.BufferSource;
|
||||
}
|
||||
|
||||
export interface LocalBaseBlockConstructor<T extends LocalBaseBlock = LocalBaseBlock> {
|
||||
new(...args: any[]): T;
|
||||
prototype: T;
|
||||
NAME: string;
|
||||
blockName(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used as a base block for all remaining ASN.1 classes
|
||||
*/
|
||||
export class LocalBaseBlock implements ILocalBaseBlock {
|
||||
|
||||
/**
|
||||
* Name of the block
|
||||
*/
|
||||
public static NAME = "baseBlock";
|
||||
/**
|
||||
* Aux function, need to get a block name. Need to have it here for inheritance
|
||||
* @returns Returns name of the block
|
||||
*/
|
||||
public static blockName(): string {
|
||||
return this.NAME;
|
||||
}
|
||||
|
||||
public blockLength: number;
|
||||
public error: string;
|
||||
public warnings: string[];
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
public get valueBeforeDecode(): ArrayBuffer {
|
||||
return this.valueBeforeDecodeView.slice().buffer;
|
||||
}
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
public set valueBeforeDecode(value: ArrayBuffer) {
|
||||
this.valueBeforeDecodeView = new Uint8Array(value);
|
||||
}
|
||||
/**
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public valueBeforeDecodeView: Uint8Array;
|
||||
|
||||
/**
|
||||
* Creates and initializes an object instance of that class
|
||||
* @param param0 Initialization parameters
|
||||
*/
|
||||
constructor({
|
||||
blockLength = 0,
|
||||
error = EMPTY_STRING,
|
||||
warnings = [],
|
||||
valueBeforeDecode = EMPTY_VIEW,
|
||||
}: LocalBaseBlockParams = {}) {
|
||||
this.blockLength = blockLength;
|
||||
this.error = error;
|
||||
this.warnings = warnings;
|
||||
this.valueBeforeDecodeView = pvtsutils.BufferSourceConverter.toUint8Array(valueBeforeDecode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON representation of an object
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): LocalBaseBlockJson {
|
||||
return {
|
||||
blockName: (this.constructor as typeof LocalBaseBlock).NAME,
|
||||
blockLength: this.blockLength,
|
||||
error: this.error,
|
||||
warnings: this.warnings,
|
||||
valueBeforeDecode: pvtsutils.Convert.ToHex(this.valueBeforeDecodeView),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import * as pvtsutils from "pvtsutils";
|
||||
import { ViewWriter } from "../ViewWriter";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { BIT_STRING_NAME, EMPTY_BUFFER, END_OF_CONTENT_NAME } from "./constants";
|
||||
import { LocalConstructedValueBlockParams, LocalConstructedValueBlockJson, LocalConstructedValueBlock } from "./LocalConstructedValueBlock";
|
||||
import { localFromBER } from "../parser";
|
||||
import { checkBufferParams } from "./utils";
|
||||
import type { BitString } from "../BitString";
|
||||
|
||||
export interface ILocalBitStringValueBlock {
|
||||
unusedBits: number;
|
||||
isConstructed: boolean;
|
||||
}
|
||||
|
||||
export interface LocalBitStringValueBlockParams extends HexBlockParams, LocalConstructedValueBlockParams, Partial<ILocalBitStringValueBlock> {
|
||||
value?: BitString[];
|
||||
}
|
||||
|
||||
export interface LocalBitStringValueBlockJson extends HexBlockJson, LocalConstructedValueBlockJson, ILocalBitStringValueBlock { }
|
||||
|
||||
export class LocalBitStringValueBlock extends HexBlock(LocalConstructedValueBlock) implements ILocalBitStringValueBlock {
|
||||
|
||||
public static override NAME = "BitStringValueBlock";
|
||||
|
||||
public unusedBits: number;
|
||||
public isConstructed: boolean;
|
||||
|
||||
constructor({
|
||||
unusedBits = 0,
|
||||
isConstructed = false,
|
||||
...parameters
|
||||
}: LocalBitStringValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.unusedBits = unusedBits;
|
||||
this.isConstructed = isConstructed;
|
||||
this.blockLength = this.valueHexView.byteLength;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
// Ability to decode zero-length BitString value
|
||||
if (!inputLength) {
|
||||
return inputOffset;
|
||||
}
|
||||
|
||||
let resultOffset = -1;
|
||||
|
||||
// If the BIT STRING supposed to be a constructed value
|
||||
if (this.isConstructed) {
|
||||
resultOffset = LocalConstructedValueBlock.prototype.fromBER.call(this, inputBuffer, inputOffset, inputLength);
|
||||
if (resultOffset === -1)
|
||||
return resultOffset;
|
||||
|
||||
for (const value of this.value) {
|
||||
const currentBlockName = (value.constructor as typeof LocalBitStringValueBlock).NAME;
|
||||
|
||||
if (currentBlockName === END_OF_CONTENT_NAME) {
|
||||
if (this.isIndefiniteForm)
|
||||
break;
|
||||
else {
|
||||
this.error = "EndOfContent is unexpected, BIT STRING may consists of BIT STRINGs only";
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentBlockName !== BIT_STRING_NAME) {
|
||||
this.error = "BIT STRING may consists of BIT STRINGs only";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const valueBlock = value.valueBlock as unknown as LocalBitStringValueBlock;
|
||||
if ((this.unusedBits > 0) && (valueBlock.unusedBits > 0)) {
|
||||
this.error = "Using of \"unused bits\" inside constructive BIT STRING allowed for least one only";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
this.unusedBits = valueBlock.unusedBits;
|
||||
}
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
|
||||
//If the BitString supposed to be a primitive value
|
||||
if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
this.unusedBits = intBuffer[0];
|
||||
|
||||
if (this.unusedBits > 7) {
|
||||
this.error = "Unused bits for BitString must be in range 0-7";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!this.unusedBits) {
|
||||
const buf = intBuffer.subarray(1);
|
||||
try {
|
||||
if (buf.byteLength) {
|
||||
const asn = localFromBER(buf, 0, buf.byteLength);
|
||||
if (asn.offset !== -1 && asn.offset === (inputLength - 1)) {
|
||||
this.value = [asn.result as BitString];
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
// Copy input buffer to internal buffer
|
||||
this.valueHexView = intBuffer.subarray(1);
|
||||
this.blockLength = intBuffer.length;
|
||||
|
||||
return (inputOffset + inputLength);
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
if (this.isConstructed) {
|
||||
return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer);
|
||||
}
|
||||
|
||||
if (sizeOnly) {
|
||||
return new ArrayBuffer(this.valueHexView.byteLength + 1);
|
||||
}
|
||||
|
||||
if (!this.valueHexView.byteLength) {
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
const retView = new Uint8Array(this.valueHexView.length + 1);
|
||||
|
||||
retView[0] = this.unusedBits;
|
||||
retView.set(this.valueHexView, 1);
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalBitStringValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
unusedBits: this.unusedBits,
|
||||
isConstructed: this.isConstructed,
|
||||
} as LocalBitStringValueBlockJson;
|
||||
}
|
||||
}
|
||||
|
||||
export interface LocalBitStringValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { LocalSimpleStringBlock, LocalSimpleStringBlockJson, LocalSimpleStringBlockParams } from "./LocalSimpleStringBlock";
|
||||
|
||||
export type LocalBmpStringValueBlockParams = LocalSimpleStringBlockParams;
|
||||
export type LocalBmpStringValueBlockJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class LocalBmpStringValueBlock extends LocalSimpleStringBlock {
|
||||
|
||||
public static override NAME = "BmpStringValueBlock";
|
||||
|
||||
public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void {
|
||||
this.valueBlock.value = pvtsutils.Convert.ToUtf16String(inputBuffer);
|
||||
this.valueBlock.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
}
|
||||
|
||||
public override fromString(inputString: string): void {
|
||||
this.valueBlock.value = inputString;
|
||||
this.valueBlock.valueHexView = new Uint8Array(pvtsutils.Convert.FromUtf16String(inputString));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { checkBufferParams } from "./utils";
|
||||
|
||||
export interface ILocalBooleanValueBlock {
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
export interface LocalBooleanValueBlockParams extends ValueBlockParams, HexBlockParams, Partial<ILocalBooleanValueBlock> { }
|
||||
|
||||
export interface LocalBooleanValueBlockJson extends ValueBlockJson, HexBlockJson, ILocalBooleanValueBlock { }
|
||||
|
||||
export class LocalBooleanValueBlock extends HexBlock(ValueBlock) implements ILocalBooleanValueBlock {
|
||||
|
||||
public static override NAME = "BooleanValueBlock";
|
||||
|
||||
public get value(): boolean {
|
||||
for (const octet of this.valueHexView) {
|
||||
if (octet > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public set value(value: boolean) {
|
||||
this.valueHexView[0] = value ? 0xFF : 0x00;
|
||||
}
|
||||
|
||||
constructor({
|
||||
value,
|
||||
...parameters
|
||||
}: LocalBooleanValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
if (parameters.valueHex) {
|
||||
this.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(parameters.valueHex);
|
||||
} else {
|
||||
this.valueHexView = new Uint8Array(1);
|
||||
}
|
||||
|
||||
if (value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
// Basic check for parameters
|
||||
if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Getting Uint8Array
|
||||
this.valueHexView = inputView.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
if (inputLength > 1)
|
||||
this.warnings.push("Boolean value encoded in more then 1 octet");
|
||||
|
||||
this.isHexOnly = true;
|
||||
pvutils.utilDecodeTC.call(this);
|
||||
this.blockLength = inputLength;
|
||||
|
||||
return (inputOffset + inputLength);
|
||||
}
|
||||
|
||||
public override toBER(): ArrayBuffer {
|
||||
return this.valueHexView.slice();
|
||||
}
|
||||
|
||||
public override toJSON(): LocalBooleanValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
value: this.value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface LocalBooleanValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { LocalBaseBlockJson } from "./LocalBaseBlock";
|
||||
import { EMPTY_BUFFER, END_OF_CONTENT_NAME } from "./constants";
|
||||
import type { BaseBlock } from "../BaseBlock";
|
||||
import { ValueBlock, ValueBlockParams } from "../ValueBlock";
|
||||
import { ViewWriter } from "../ViewWriter";
|
||||
import { localFromBER } from "../parser";
|
||||
import { checkBufferParams } from "./utils";
|
||||
import type { Any } from "../Any";
|
||||
|
||||
export type ConstructedItem = BaseBlock | Any;
|
||||
|
||||
export interface ILocalConstructedValueBlock {
|
||||
value: ConstructedItem[];
|
||||
isIndefiniteForm: boolean;
|
||||
}
|
||||
|
||||
export interface LocalConstructedValueBlockParams extends ValueBlockParams, Partial<ILocalConstructedValueBlock> { }
|
||||
|
||||
export interface LocalConstructedValueBlockJson extends LocalBaseBlockJson, Omit<ILocalConstructedValueBlock, "value"> {
|
||||
value: LocalBaseBlockJson[];
|
||||
}
|
||||
|
||||
function checkLen(indefiniteLength: boolean, length: number): number {
|
||||
if (indefiniteLength) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
export class LocalConstructedValueBlock extends ValueBlock implements ILocalConstructedValueBlock {
|
||||
|
||||
public static override NAME = "ConstructedValueBlock";
|
||||
|
||||
public value: BaseBlock[];
|
||||
public isIndefiniteForm: boolean;
|
||||
|
||||
constructor({
|
||||
value = [],
|
||||
isIndefiniteForm = false,
|
||||
...parameters
|
||||
}: LocalConstructedValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.value = value as BaseBlock[]; // It's possible to set Any type for Schema declaration
|
||||
this.isIndefiniteForm = isIndefiniteForm;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const view = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
|
||||
// Basic check for parameters
|
||||
if (!checkBufferParams(this, view, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
this.valueBeforeDecodeView = view.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
// Initial checks
|
||||
if (this.valueBeforeDecodeView.length === 0) {
|
||||
this.warnings.push("Zero buffer length");
|
||||
|
||||
return inputOffset;
|
||||
}
|
||||
|
||||
let currentOffset = inputOffset;
|
||||
|
||||
while (checkLen(this.isIndefiniteForm, inputLength) > 0) {
|
||||
const returnObject = localFromBER(view, 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 && (returnObject.result.constructor as typeof BaseBlock).NAME === END_OF_CONTENT_NAME) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isIndefiniteForm) {
|
||||
if ((this.value[this.value.length - 1].constructor as typeof BaseBlock).NAME === END_OF_CONTENT_NAME) {
|
||||
this.value.pop();
|
||||
} else {
|
||||
this.warnings.push("No EndOfContent block encoded");
|
||||
}
|
||||
}
|
||||
|
||||
return currentOffset;
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
const _writer = writer || new ViewWriter();
|
||||
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
this.value[i].toBER(sizeOnly, _writer);
|
||||
}
|
||||
|
||||
if (!writer) {
|
||||
return _writer.final();
|
||||
}
|
||||
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalConstructedValueBlockJson {
|
||||
const object: LocalConstructedValueBlockJson = {
|
||||
...super.toJSON(),
|
||||
isIndefiniteForm: this.isIndefiniteForm,
|
||||
value: [],
|
||||
};
|
||||
|
||||
for (const value of this.value) {
|
||||
object.value.push(value.toJSON());
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
import { ValueBlock } from "../ValueBlock";
|
||||
import { EMPTY_BUFFER } from "./constants";
|
||||
|
||||
export class LocalEndOfContentValueBlock extends ValueBlock {
|
||||
|
||||
public static override = "EndOfContentValueBlock";
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
// There is no "value block" for EndOfContent type and we need to return the same offset
|
||||
return inputOffset;
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean): ArrayBuffer {
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,280 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { EMPTY_BUFFER, EMPTY_VIEW } from "./constants";
|
||||
import { LocalBaseBlock, LocalBaseBlockJson } from "./LocalBaseBlock";
|
||||
import { checkBufferParams } from "./utils";
|
||||
|
||||
|
||||
export interface ILocalIdentificationBlock {
|
||||
tagClass: number;
|
||||
tagNumber: number;
|
||||
isConstructed: boolean;
|
||||
}
|
||||
|
||||
export interface LocalIdentificationBlockParams {
|
||||
idBlock?: Partial<ILocalIdentificationBlock> & HexBlockParams;
|
||||
}
|
||||
|
||||
export interface LocalIdentificationBlockJson extends HexBlockJson, LocalBaseBlockJson, ILocalIdentificationBlock { }
|
||||
|
||||
|
||||
export class LocalIdentificationBlock extends HexBlock(LocalBaseBlock) implements ILocalIdentificationBlock {
|
||||
|
||||
public static override NAME = "identificationBlock";
|
||||
|
||||
public tagClass: number;
|
||||
public tagNumber: number;
|
||||
public isConstructed: boolean;
|
||||
|
||||
constructor({
|
||||
idBlock = {},
|
||||
}: LocalIdentificationBlockParams = {}) {
|
||||
super();
|
||||
|
||||
if (idBlock) {
|
||||
//#region Properties from hexBlock class
|
||||
this.isHexOnly = idBlock.isHexOnly ?? false;
|
||||
this.valueHexView = idBlock.valueHex ? pvtsutils.BufferSourceConverter.toUint8Array(idBlock.valueHex) : EMPTY_VIEW;
|
||||
//#endregion
|
||||
this.tagClass = idBlock.tagClass ?? -1;
|
||||
this.tagNumber = idBlock.tagNumber ?? -1;
|
||||
this.isConstructed = idBlock.isConstructed ?? false;
|
||||
} else {
|
||||
this.tagClass = -1;
|
||||
this.tagNumber = -1;
|
||||
this.isConstructed = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly = false): ArrayBuffer {
|
||||
let firstOctet = 0;
|
||||
|
||||
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 EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
if (this.isConstructed)
|
||||
firstOctet |= 0x20;
|
||||
|
||||
if (this.tagNumber < 31 && !this.isHexOnly) {
|
||||
const retView = new Uint8Array(1);
|
||||
|
||||
if (!sizeOnly) {
|
||||
let number = this.tagNumber;
|
||||
number &= 0x1F;
|
||||
firstOctet |= number;
|
||||
|
||||
retView[0] = firstOctet;
|
||||
}
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
if (!this.isHexOnly) {
|
||||
const encodedBuf = pvutils.utilToBase(this.tagNumber, 7);
|
||||
const encodedView = new Uint8Array(encodedBuf);
|
||||
const size = encodedBuf.byteLength;
|
||||
|
||||
const retView = new Uint8Array(size + 1);
|
||||
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 retView.buffer;
|
||||
}
|
||||
|
||||
const retView = new Uint8Array(this.valueHexView.byteLength + 1);
|
||||
|
||||
retView[0] = (firstOctet | 0x1F);
|
||||
|
||||
if (!sizeOnly) {
|
||||
const curView = this.valueHexView;
|
||||
|
||||
for (let i = 0; i < (curView.length - 1); i++)
|
||||
retView[i + 1] = curView[i] | 0x80;
|
||||
|
||||
retView[this.valueHexView.byteLength] = curView[curView.length - 1];
|
||||
}
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
|
||||
// Basic check for parameters
|
||||
if (!checkBufferParams(this, inputView, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Getting Uint8Array from ArrayBuffer
|
||||
const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
// Initial checks
|
||||
if (intBuffer.length === 0) {
|
||||
this.error = "Zero buffer length";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//#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
|
||||
// Find it's constructed or not
|
||||
this.isConstructed = (intBuffer[0] & 0x20) === 0x20;
|
||||
|
||||
// Find tag number
|
||||
this.isHexOnly = false;
|
||||
const tagNumberMask = intBuffer[0] & 0x1F;
|
||||
|
||||
if (tagNumberMask !== 0x1F) {
|
||||
// Simple case (tag number < 31)
|
||||
this.tagNumber = (tagNumberMask);
|
||||
this.blockLength = 1;
|
||||
} else {
|
||||
// Tag number bigger or equal to 31
|
||||
let count = 1;
|
||||
|
||||
let intTagNumberBuffer = this.valueHexView = new Uint8Array(255);
|
||||
let tagNumberBufferMaxLength = 255;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// In case if tag number length is greater than 255 bytes (rare but possible case)
|
||||
if (count === tagNumberBufferMaxLength) {
|
||||
tagNumberBufferMaxLength += 255;
|
||||
|
||||
const tempBufferView = new Uint8Array(tagNumberBufferMaxLength);
|
||||
|
||||
for (let i = 0; i < intTagNumberBuffer.length; i++)
|
||||
tempBufferView[i] = intTagNumberBuffer[i];
|
||||
|
||||
intTagNumberBuffer = this.valueHexView = new Uint8Array(tagNumberBufferMaxLength);
|
||||
}
|
||||
}
|
||||
|
||||
this.blockLength = (count + 1);
|
||||
intTagNumberBuffer[count - 1] = intBuffer[count] & 0x7F; // Write last byte to buffer
|
||||
|
||||
|
||||
//#region Cut buffer
|
||||
const tempBufferView = new Uint8Array(count);
|
||||
|
||||
for (let i = 0; i < count; i++)
|
||||
tempBufferView[i] = intTagNumberBuffer[i];
|
||||
|
||||
intTagNumberBuffer = this.valueHexView = new Uint8Array(count);
|
||||
intTagNumberBuffer.set(tempBufferView);
|
||||
//#endregion
|
||||
//#region Try to convert long tag number to short form
|
||||
if (this.blockLength <= 9)
|
||||
this.tagNumber = 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 13: // RELATIVE OBJECT IDENTIFIER
|
||||
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
|
||||
}
|
||||
|
||||
public override toJSON(): LocalIdentificationBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
tagClass: this.tagClass,
|
||||
tagNumber: this.tagNumber,
|
||||
isConstructed: this.isConstructed,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface LocalIdentificationBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import * as pvutils from "pvutils";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { IDerConvertible } from "../types";
|
||||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { powers2, digitsString } from "./constants";
|
||||
|
||||
function viewAdd(first: Uint8Array, second: Uint8Array): Uint8Array {
|
||||
//#region Initial variables
|
||||
const c = new Uint8Array([0]);
|
||||
|
||||
const firstView = new Uint8Array(first);
|
||||
const secondView = new Uint8Array(second);
|
||||
|
||||
let firstViewCopy = firstView.slice(0);
|
||||
const firstViewCopyLength = firstViewCopy.length - 1;
|
||||
const 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 = pvutils.utilConcatView(new Uint8Array([value % 10]), firstViewCopy);
|
||||
break;
|
||||
default:
|
||||
firstViewCopy[firstViewCopyLength - counter] = value % 10;
|
||||
}
|
||||
}
|
||||
|
||||
if (c[0] > 0)
|
||||
firstViewCopy = pvutils.utilConcatView(c, firstViewCopy);
|
||||
|
||||
return firstViewCopy;
|
||||
}
|
||||
|
||||
function power2(n: number): Uint8Array {
|
||||
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 = pvutils.utilConcatView(c, digits);
|
||||
|
||||
powers2.push(digits);
|
||||
}
|
||||
}
|
||||
|
||||
return powers2[n];
|
||||
}
|
||||
|
||||
function viewSub(first: Uint8Array, second: Uint8Array): Uint8Array {
|
||||
//#region Initial variables
|
||||
let b = 0;
|
||||
|
||||
const firstView = new Uint8Array(first);
|
||||
const secondView = new Uint8Array(second);
|
||||
|
||||
const firstViewCopy = firstView.slice(0);
|
||||
const firstViewCopyLength = firstViewCopy.length - 1;
|
||||
const 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();
|
||||
}
|
||||
|
||||
export interface ILocalIntegerValueBlock {
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface LocalIntegerValueBlockParams extends HexBlockParams, ValueBlockParams, Partial<ILocalIntegerValueBlock> { }
|
||||
|
||||
export interface LocalIntegerValueBlockJson extends HexBlockJson, ValueBlockJson {
|
||||
valueDec: number;
|
||||
}
|
||||
|
||||
export class LocalIntegerValueBlock extends HexBlock(ValueBlock) implements IDerConvertible {
|
||||
protected setValueHex(): void {
|
||||
if (this.valueHexView.length >= 4) {
|
||||
this.warnings.push("Too big Integer for decoding, hex only");
|
||||
this.isHexOnly = true;
|
||||
this._valueDec = 0;
|
||||
} else {
|
||||
this.isHexOnly = false;
|
||||
|
||||
if (this.valueHexView.length > 0) {
|
||||
this._valueDec = pvutils.utilDecodeTC.call(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static override NAME = "IntegerValueBlock";
|
||||
|
||||
static {
|
||||
Object.defineProperty(this.prototype, "valueHex", {
|
||||
set: function (this: LocalIntegerValueBlock, v: ArrayBuffer) {
|
||||
this.valueHexView = new Uint8Array(v);
|
||||
|
||||
this.setValueHex();
|
||||
},
|
||||
get: function (this: LocalIntegerValueBlock) {
|
||||
return this.valueHexView.slice().buffer;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private _valueDec = 0;
|
||||
|
||||
constructor({
|
||||
value,
|
||||
...parameters
|
||||
}: LocalIntegerValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
if (parameters.valueHex) {
|
||||
this.setValueHex();
|
||||
}
|
||||
|
||||
if (value !== undefined) {
|
||||
this.valueDec = value;
|
||||
}
|
||||
}
|
||||
|
||||
public set valueDec(v: number) {
|
||||
this._valueDec = v;
|
||||
|
||||
this.isHexOnly = false;
|
||||
this.valueHexView = new Uint8Array(pvutils.utilEncodeTC(v));
|
||||
}
|
||||
|
||||
public get valueDec(): number {
|
||||
return this._valueDec;
|
||||
}
|
||||
|
||||
public fromDER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number, expectedLength = 0): number {
|
||||
const offset = this.fromBER(inputBuffer, inputOffset, inputLength);
|
||||
if (offset === -1)
|
||||
return offset;
|
||||
|
||||
const view = this.valueHexView;
|
||||
|
||||
if ((view[0] === 0x00) && ((view[1] & 0x80) !== 0)) {
|
||||
this.valueHexView = view.subarray(1);
|
||||
}
|
||||
else {
|
||||
if (expectedLength !== 0) {
|
||||
if (view.length < expectedLength) {
|
||||
if ((expectedLength - view.length) > 1)
|
||||
expectedLength = view.length + 1;
|
||||
|
||||
this.valueHexView = view.subarray(expectedLength - view.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public toDER(sizeOnly = false): ArrayBuffer {
|
||||
const view = this.valueHexView;
|
||||
|
||||
switch (true) {
|
||||
case ((view[0] & 0x80) !== 0):
|
||||
{
|
||||
const updatedView = new Uint8Array(this.valueHexView.length + 1);
|
||||
|
||||
updatedView[0] = 0x00;
|
||||
updatedView.set(view, 1);
|
||||
|
||||
this.valueHexView = updatedView;
|
||||
}
|
||||
break;
|
||||
case ((view[0] === 0x00) && ((view[1] & 0x80) === 0)):
|
||||
{
|
||||
this.valueHexView = this.valueHexView.subarray(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return this.toBER(sizeOnly);
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number): number {
|
||||
const resultOffset = super.fromBER(inputBuffer, inputOffset, inputLength);
|
||||
if (resultOffset === -1) {
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
this.setValueHex();
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean): ArrayBuffer {
|
||||
return sizeOnly
|
||||
? new ArrayBuffer(this.valueHexView.length)
|
||||
: this.valueHexView.slice().buffer;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalIntegerValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
valueDec: this.valueDec,
|
||||
};
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
//#region Initial variables
|
||||
const firstBit = (this.valueHexView.length * 8) - 1;
|
||||
|
||||
let digits = new Uint8Array((this.valueHexView.length * 8) / 3);
|
||||
let bitNumber = 0;
|
||||
let currentByte;
|
||||
|
||||
const asn1View = this.valueHexView;
|
||||
|
||||
let result = "";
|
||||
|
||||
let flag = false;
|
||||
//#endregion
|
||||
//#region Calculate number
|
||||
for (let byteNumber = (asn1View.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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface LocalIntegerValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { IBerConvertible } from "../types";
|
||||
import { EMPTY_BUFFER } from "./constants";
|
||||
import { LocalBaseBlock, LocalBaseBlockJson } from "./LocalBaseBlock";
|
||||
import { checkBufferParams } from "./utils";
|
||||
|
||||
export interface ILocalLengthBlock {
|
||||
isIndefiniteForm: boolean;
|
||||
longFormUsed: boolean;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export interface LocalLengthBlockParams {
|
||||
lenBlock?: Partial<ILocalLengthBlock>;
|
||||
}
|
||||
|
||||
export interface LocalLengthBlockJson extends LocalBaseBlockJson, ILocalLengthBlock {
|
||||
isIndefiniteForm: boolean;
|
||||
longFormUsed: boolean;
|
||||
length: number;
|
||||
}
|
||||
|
||||
export class LocalLengthBlock extends LocalBaseBlock implements ILocalLengthBlock, IBerConvertible {
|
||||
|
||||
public static override NAME = "lengthBlock";
|
||||
|
||||
public isIndefiniteForm: boolean;
|
||||
public longFormUsed: boolean;
|
||||
public length: number;
|
||||
|
||||
constructor({
|
||||
lenBlock = {},
|
||||
}: LocalLengthBlockParams = {}) {
|
||||
super();
|
||||
|
||||
this.isIndefiniteForm = lenBlock.isIndefiniteForm ?? false;
|
||||
this.longFormUsed = lenBlock.longFormUsed ?? false;
|
||||
this.length = lenBlock.length ?? 0;
|
||||
}
|
||||
|
||||
|
||||
public fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
const view = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
// Basic check for parameters
|
||||
if (!checkBufferParams(this, view, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
//#region Getting Uint8Array from ArrayBuffer
|
||||
const intBuffer = view.subarray(inputOffset, 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) {
|
||||
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 lenOffset = inputOffset + 1;
|
||||
const lengthBufferView = view.subarray(lenOffset, lenOffset + count);
|
||||
|
||||
if (lengthBufferView[count - 1] === 0x00)
|
||||
this.warnings.push("Needlessly long encoded length");
|
||||
|
||||
this.length = pvutils.utilFromBase(lengthBufferView, 8);
|
||||
|
||||
if (this.longFormUsed && (this.length <= 127))
|
||||
this.warnings.push("Unnecessary usage of long length form");
|
||||
|
||||
this.blockLength = count + 1;
|
||||
//#endregion
|
||||
|
||||
return (inputOffset + this.blockLength); // Return current offset in input buffer
|
||||
}
|
||||
|
||||
public toBER(sizeOnly = false): ArrayBuffer {
|
||||
//#region Initial variables
|
||||
let retBuf: ArrayBuffer;
|
||||
let retView: Uint8Array;
|
||||
//#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) {
|
||||
const encodedBuf = pvutils.utilToBase(this.length, 8);
|
||||
|
||||
if (encodedBuf.byteLength > 127) {
|
||||
this.error = "Too big length";
|
||||
|
||||
return (EMPTY_BUFFER);
|
||||
}
|
||||
|
||||
retBuf = new ArrayBuffer(encodedBuf.byteLength + 1);
|
||||
|
||||
if (sizeOnly)
|
||||
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;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalLengthBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
isIndefiniteForm: this.isIndefiniteForm,
|
||||
longFormUsed: this.longFormUsed,
|
||||
length: this.length,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { EMPTY_BUFFER, EMPTY_STRING } from "./constants";
|
||||
import * as utils from "./utils";
|
||||
import { LocalSidValueBlockJson, LocalSidValueBlock } from "./LocalSidValueBlock";
|
||||
import { IStringConvertible } from "../types";
|
||||
|
||||
|
||||
export interface ILocalObjectIdentifierValueBlock {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface LocalObjectIdentifierValueBlockParams extends ValueBlockParams, Partial<ILocalObjectIdentifierValueBlock> { }
|
||||
|
||||
export interface LocalObjectIdentifierValueBlockJson extends ValueBlockJson, ILocalObjectIdentifierValueBlock {
|
||||
sidArray: LocalSidValueBlockJson[];
|
||||
}
|
||||
|
||||
export class LocalObjectIdentifierValueBlock extends ValueBlock implements IStringConvertible {
|
||||
|
||||
public static override NAME = "ObjectIdentifierValueBlock";
|
||||
|
||||
public value: LocalSidValueBlock[] = [];
|
||||
|
||||
constructor({
|
||||
value = EMPTY_STRING,
|
||||
...parameters
|
||||
}: LocalObjectIdentifierValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
if (value) {
|
||||
this.fromString(value);
|
||||
}
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
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;
|
||||
}
|
||||
public override toBER(sizeOnly?: boolean): ArrayBuffer {
|
||||
const retBuffers: ArrayBuffer[] = [];
|
||||
|
||||
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 EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
retBuffers.push(valueBuf);
|
||||
}
|
||||
|
||||
return utils.concat(retBuffers);
|
||||
}
|
||||
|
||||
public fromString(string: string): void {
|
||||
this.value = []; // Clear existing SID values
|
||||
|
||||
let pos1 = 0;
|
||||
let pos2 = 0;
|
||||
|
||||
let sid = "";
|
||||
|
||||
let flag = false;
|
||||
|
||||
// const sids = string.split(".");
|
||||
// for (const sid of sids) {
|
||||
|
||||
// }
|
||||
do {
|
||||
pos2 = string.indexOf(".", pos1);
|
||||
if (pos2 === -1)
|
||||
sid = string.substring(pos1);
|
||||
|
||||
else
|
||||
sid = string.substring(pos1, pos2);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const parsedSID = parseInt(sid, 10);
|
||||
if (isNaN(parsedSID))
|
||||
return;
|
||||
|
||||
sidBlock.valueDec = parsedSID + plus;
|
||||
|
||||
flag = false;
|
||||
} else {
|
||||
const sidBlock = new LocalSidValueBlock();
|
||||
if ((sid as any) > Number.MAX_SAFE_INTEGER) { // TODO remove as any
|
||||
utils.assertBigInt();
|
||||
const sidValue = BigInt(sid);
|
||||
sidBlock.valueBigInt = sidValue;
|
||||
} else {
|
||||
sidBlock.valueDec = parseInt(sid, 10);
|
||||
if (isNaN(sidBlock.valueDec))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.value.length) {
|
||||
sidBlock.isFirstSid = true;
|
||||
flag = true;
|
||||
}
|
||||
|
||||
this.value.push(sidBlock);
|
||||
}
|
||||
} while (pos2 !== -1);
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
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;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalObjectIdentifierValueBlockJson {
|
||||
const object: LocalObjectIdentifierValueBlockJson = {
|
||||
...super.toJSON(),
|
||||
value: this.toString(),
|
||||
sidArray: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < this.value.length; i++) {
|
||||
object.sidArray.push(this.value[i].toJSON());
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { ViewWriter } from "../ViewWriter";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { END_OF_CONTENT_NAME, OCTET_STRING_NAME } from "./constants";
|
||||
import { LocalConstructedValueBlockParams, LocalConstructedValueBlockJson, LocalConstructedValueBlock } from "./LocalConstructedValueBlock";
|
||||
import type { OctetString } from "../OctetString";
|
||||
|
||||
export interface ILocalOctetStringValueBlock {
|
||||
isConstructed: boolean;
|
||||
}
|
||||
|
||||
export interface LocalOctetStringValueBlockParams extends HexBlockParams, LocalConstructedValueBlockParams, Partial<ILocalOctetStringValueBlock> {
|
||||
value?: OctetString[];
|
||||
}
|
||||
|
||||
export interface LocalOctetStringValueBlockJson extends HexBlockJson, LocalConstructedValueBlockJson, ILocalOctetStringValueBlock { }
|
||||
|
||||
export class LocalOctetStringValueBlock extends HexBlock(LocalConstructedValueBlock) {
|
||||
|
||||
public static override NAME = "OctetStringValueBlock";
|
||||
|
||||
public isConstructed: boolean;
|
||||
|
||||
constructor({
|
||||
isConstructed = false,
|
||||
...parameters
|
||||
}: LocalOctetStringValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.isConstructed = isConstructed;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number): number {
|
||||
let resultOffset = 0;
|
||||
|
||||
if (this.isConstructed) {
|
||||
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 as typeof LocalOctetStringValueBlock).NAME;
|
||||
|
||||
if (currentBlockName === END_OF_CONTENT_NAME) {
|
||||
if (this.isIndefiniteForm)
|
||||
break;
|
||||
else {
|
||||
this.error = "EndOfContent is unexpected, OCTET STRING may consists of OCTET STRINGs only";
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentBlockName !== OCTET_STRING_NAME) {
|
||||
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;
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
if (this.isConstructed)
|
||||
return LocalConstructedValueBlock.prototype.toBER.call(this, sizeOnly, writer);
|
||||
|
||||
return sizeOnly
|
||||
? new ArrayBuffer(this.valueHexView.byteLength)
|
||||
: this.valueHexView.slice().buffer;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalOctetStringValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
isConstructed: this.isConstructed,
|
||||
} as LocalOctetStringValueBlockJson;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface LocalOctetStringValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { HexBlock, HexBlockJson, HexBlockParams } from "../HexBlock";
|
||||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
|
||||
export interface LocalPrimitiveValueBlockParams extends HexBlockParams, ValueBlockParams { }
|
||||
export interface LocalPrimitiveValueBlockJson extends HexBlockJson, ValueBlockJson { }
|
||||
|
||||
export class LocalPrimitiveValueBlock extends HexBlock(ValueBlock) {
|
||||
|
||||
public static override NAME = "PrimitiveValueBlock";
|
||||
|
||||
constructor({
|
||||
isHexOnly = true,
|
||||
...parameters
|
||||
}: LocalPrimitiveValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.isHexOnly = isHexOnly;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface LocalPrimitiveValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
140
third_party/asn1js/src/internals/LocalRelativeObjectIdentifierValueBlock.ts
поставляемый
Normal file
140
third_party/asn1js/src/internals/LocalRelativeObjectIdentifierValueBlock.ts
поставляемый
Normal file
|
@ -0,0 +1,140 @@
|
|||
import { ViewWriter } from "../ViewWriter";
|
||||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { EMPTY_BUFFER, EMPTY_STRING } from "./constants";
|
||||
import * as utils from "./utils";
|
||||
import { LocalRelativeSidValueBlockJson, LocalRelativeSidValueBlock } from "./LocalRelativeSidValueBlock";
|
||||
import { IStringConvertible } from "../types";
|
||||
|
||||
export interface ILocalRelativeObjectIdentifierValueBlock {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface LocalRelativeObjectIdentifierValueBlockParams extends ValueBlockParams, Partial<ILocalRelativeObjectIdentifierValueBlock> { }
|
||||
|
||||
export interface LocalRelativeObjectIdentifierValueBlockJson extends ValueBlockJson, ILocalRelativeObjectIdentifierValueBlock {
|
||||
sidArray: LocalRelativeSidValueBlockJson[];
|
||||
}
|
||||
|
||||
export class LocalRelativeObjectIdentifierValueBlock extends ValueBlock implements IStringConvertible {
|
||||
|
||||
public static override NAME = "RelativeObjectIdentifierValueBlock";
|
||||
|
||||
public value: LocalRelativeSidValueBlock[] = [];
|
||||
|
||||
constructor({
|
||||
value = EMPTY_STRING,
|
||||
...parameters
|
||||
}: LocalRelativeObjectIdentifierValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
if (value) {
|
||||
this.fromString(value);
|
||||
}
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
let resultOffset = inputOffset;
|
||||
|
||||
while (inputLength > 0) {
|
||||
const sidBlock = new LocalRelativeSidValueBlock();
|
||||
resultOffset = sidBlock.fromBER(inputBuffer, resultOffset, inputLength);
|
||||
if (resultOffset === -1) {
|
||||
this.blockLength = 0;
|
||||
this.error = sidBlock.error;
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
this.blockLength += sidBlock.blockLength;
|
||||
inputLength -= sidBlock.blockLength;
|
||||
|
||||
this.value.push(sidBlock);
|
||||
}
|
||||
|
||||
return resultOffset;
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean, writer?: ViewWriter): ArrayBuffer {
|
||||
const retBuffers: ArrayBuffer[] = [];
|
||||
|
||||
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 EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
retBuffers.push(valueBuf);
|
||||
}
|
||||
|
||||
return utils.concat(retBuffers);
|
||||
}
|
||||
|
||||
public fromString(string: string): boolean {
|
||||
this.value = []; // Clear existing SID values
|
||||
|
||||
let pos1 = 0;
|
||||
let pos2 = 0;
|
||||
|
||||
let sid = "";
|
||||
|
||||
do {
|
||||
pos2 = string.indexOf(".", pos1);
|
||||
if (pos2 === -1)
|
||||
sid = string.substring(pos1);
|
||||
|
||||
else
|
||||
sid = string.substring(pos1, pos2);
|
||||
|
||||
pos1 = pos2 + 1;
|
||||
|
||||
const sidBlock = new LocalRelativeSidValueBlock();
|
||||
sidBlock.valueDec = parseInt(sid, 10);
|
||||
if (isNaN(sidBlock.valueDec))
|
||||
return true;
|
||||
|
||||
this.value.push(sidBlock);
|
||||
|
||||
} while (pos2 !== -1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
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}}`;
|
||||
result += sidStr;
|
||||
}
|
||||
else
|
||||
result += sidStr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalRelativeObjectIdentifierValueBlockJson {
|
||||
const object: LocalRelativeObjectIdentifierValueBlockJson = {
|
||||
...super.toJSON(),
|
||||
value: this.toString(),
|
||||
sidArray: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < this.value.length; i++)
|
||||
object.sidArray.push(this.value[i].toJSON());
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { LocalBaseBlock } from "./LocalBaseBlock";
|
||||
import { EMPTY_BUFFER } from "./constants";
|
||||
import { checkBufferParams } from "./utils";
|
||||
|
||||
export interface ILocalRelativeSidValueBlock {
|
||||
valueDec: number;
|
||||
}
|
||||
|
||||
export interface LocalRelativeSidValueBlockParams extends HexBlockParams, ValueBlockParams, Partial<ILocalRelativeSidValueBlock> { }
|
||||
|
||||
export interface LocalRelativeSidValueBlockJson extends HexBlockJson, ValueBlockJson, ILocalRelativeSidValueBlock { }
|
||||
|
||||
export class LocalRelativeSidValueBlock extends HexBlock(LocalBaseBlock) implements ILocalRelativeSidValueBlock {
|
||||
|
||||
public static override NAME = "relativeSidBlock";
|
||||
|
||||
public valueDec: number;
|
||||
|
||||
constructor({
|
||||
valueDec = 0,
|
||||
...parameters
|
||||
}: LocalRelativeSidValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.valueDec = valueDec;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
if (inputLength === 0)
|
||||
return inputOffset;
|
||||
|
||||
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
|
||||
// Basic check for parameters
|
||||
if (!checkBufferParams(this, inputView, inputOffset, inputLength))
|
||||
return -1;
|
||||
|
||||
const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
this.valueHexView = new Uint8Array(inputLength);
|
||||
|
||||
for (let i = 0; i < inputLength; i++) {
|
||||
this.valueHexView[i] = intBuffer[i] & 0x7F;
|
||||
|
||||
this.blockLength++;
|
||||
|
||||
if ((intBuffer[i] & 0x80) === 0x00)
|
||||
break;
|
||||
}
|
||||
|
||||
//#region Adjust size of valueHex buffer
|
||||
const tempView = new Uint8Array(this.blockLength);
|
||||
|
||||
for (let i = 0; i < this.blockLength; i++)
|
||||
tempView[i] = this.valueHexView[i];
|
||||
|
||||
this.valueHexView = tempView;
|
||||
//#endregion
|
||||
if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) {
|
||||
this.error = "End of input reached before message was fully decoded";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this.valueHexView[0] === 0x00)
|
||||
this.warnings.push("Needlessly long format of SID encoding");
|
||||
|
||||
if (this.blockLength <= 8)
|
||||
this.valueDec = pvutils.utilFromBase(this.valueHexView, 7);
|
||||
else {
|
||||
this.isHexOnly = true;
|
||||
this.warnings.push("Too big SID for decoding, hex only");
|
||||
}
|
||||
|
||||
return (inputOffset + this.blockLength);
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean): ArrayBuffer {
|
||||
if (this.isHexOnly) {
|
||||
if (sizeOnly)
|
||||
return (new ArrayBuffer(this.valueHexView.byteLength));
|
||||
|
||||
const curView = this.valueHexView;
|
||||
|
||||
const retView = new Uint8Array(this.blockLength);
|
||||
|
||||
for (let i = 0; i < (this.blockLength - 1); i++)
|
||||
retView[i] = curView[i] | 0x80;
|
||||
|
||||
retView[this.blockLength - 1] = curView[this.blockLength - 1];
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
const encodedBuf = pvutils.utilToBase(this.valueDec, 7);
|
||||
if (encodedBuf.byteLength === 0) {
|
||||
this.error = "Error during encoding SID value";
|
||||
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
const retView = new Uint8Array(encodedBuf.byteLength);
|
||||
|
||||
if (!sizeOnly) {
|
||||
const encodedView = new Uint8Array(encodedBuf);
|
||||
const len = encodedBuf.byteLength - 1;
|
||||
|
||||
for (let i = 0; i < len; i++)
|
||||
retView[i] = encodedView[i] | 0x80;
|
||||
|
||||
retView[len] = encodedView[len];
|
||||
}
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
let result = "";
|
||||
|
||||
if (this.isHexOnly)
|
||||
result = pvtsutils.Convert.ToHex(this.valueHexView);
|
||||
else {
|
||||
result = this.valueDec.toString();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalRelativeSidValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
valueDec: this.valueDec,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import * as pvtsutils from "pvtsutils";
|
||||
import * as pvutils from "pvutils";
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { EMPTY_BUFFER } from "./constants";
|
||||
import * as utils from "./utils";
|
||||
|
||||
export interface ILocalSidValueBlock {
|
||||
valueDec: number;
|
||||
isFirstSid: boolean;
|
||||
}
|
||||
|
||||
export interface LocalSidValueBlockParams extends HexBlockParams, ValueBlockParams, Partial<ILocalSidValueBlock> { }
|
||||
|
||||
export interface LocalSidValueBlockJson extends HexBlockJson, ValueBlockJson, ILocalSidValueBlock { }
|
||||
|
||||
export class LocalSidValueBlock extends HexBlock(ValueBlock) implements ILocalSidValueBlock {
|
||||
|
||||
public static override NAME = "sidBlock";
|
||||
|
||||
public valueDec: number;
|
||||
public isFirstSid: boolean;
|
||||
|
||||
constructor({
|
||||
valueDec = -1,
|
||||
isFirstSid = false,
|
||||
...parameters
|
||||
}: LocalSidValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.valueDec = valueDec;
|
||||
this.isFirstSid = isFirstSid;
|
||||
}
|
||||
|
||||
public override fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number {
|
||||
if (!inputLength) {
|
||||
return inputOffset;
|
||||
}
|
||||
const inputView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
|
||||
// Basic check for parameters
|
||||
if (!utils.checkBufferParams(this, inputView, inputOffset, inputLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
const intBuffer = inputView.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
this.valueHexView = new Uint8Array(inputLength);
|
||||
|
||||
for (let i = 0; i < inputLength; i++) {
|
||||
this.valueHexView[i] = intBuffer[i] & 0x7F;
|
||||
|
||||
this.blockLength++;
|
||||
|
||||
if ((intBuffer[i] & 0x80) === 0x00)
|
||||
break;
|
||||
}
|
||||
|
||||
//#region Adjust size of valueHex buffer
|
||||
const tempView = new Uint8Array(this.blockLength);
|
||||
|
||||
for (let i = 0; i < this.blockLength; i++) {
|
||||
tempView[i] = this.valueHexView[i];
|
||||
}
|
||||
|
||||
this.valueHexView = tempView;
|
||||
//#endregion
|
||||
|
||||
if ((intBuffer[this.blockLength - 1] & 0x80) !== 0x00) {
|
||||
this.error = "End of input reached before message was fully decoded";
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this.valueHexView[0] === 0x00)
|
||||
this.warnings.push("Needlessly long format of SID encoding");
|
||||
|
||||
if (this.blockLength <= 8)
|
||||
this.valueDec = pvutils.utilFromBase(this.valueHexView, 7);
|
||||
else {
|
||||
this.isHexOnly = true;
|
||||
this.warnings.push("Too big SID for decoding, hex only");
|
||||
}
|
||||
|
||||
return (inputOffset + this.blockLength);
|
||||
}
|
||||
|
||||
public set valueBigInt(value: bigint) {
|
||||
|
||||
utils.assertBigInt();
|
||||
|
||||
let bits = BigInt(value).toString(2);
|
||||
while (bits.length % 7) {
|
||||
bits = "0" + bits;
|
||||
}
|
||||
const bytes = new Uint8Array(bits.length / 7);
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
bytes[i] = parseInt(bits.slice(i * 7, i * 7 + 7), 2) + (i + 1 < bytes.length ? 0x80 : 0);
|
||||
}
|
||||
this.fromBER(bytes.buffer, 0, bytes.length);
|
||||
}
|
||||
|
||||
public override toBER(sizeOnly?: boolean): ArrayBuffer {
|
||||
if (this.isHexOnly) {
|
||||
if (sizeOnly)
|
||||
return (new ArrayBuffer(this.valueHexView.byteLength));
|
||||
|
||||
const curView = this.valueHexView;
|
||||
const retView = new Uint8Array(this.blockLength);
|
||||
|
||||
for (let i = 0; i < (this.blockLength - 1); i++)
|
||||
retView[i] = curView[i] | 0x80;
|
||||
|
||||
retView[this.blockLength - 1] = curView[this.blockLength - 1];
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
const encodedBuf = pvutils.utilToBase(this.valueDec, 7);
|
||||
if (encodedBuf.byteLength === 0) {
|
||||
this.error = "Error during encoding SID value";
|
||||
|
||||
return EMPTY_BUFFER;
|
||||
}
|
||||
|
||||
const retView = new Uint8Array(encodedBuf.byteLength);
|
||||
|
||||
if (!sizeOnly) {
|
||||
const encodedView = new Uint8Array(encodedBuf);
|
||||
const len = encodedBuf.byteLength - 1;
|
||||
|
||||
for (let i = 0; i < len; i++)
|
||||
retView[i] = encodedView[i] | 0x80;
|
||||
|
||||
retView[len] = encodedView[len];
|
||||
}
|
||||
|
||||
return retView;
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
let result = "";
|
||||
|
||||
if (this.isHexOnly)
|
||||
result = pvtsutils.Convert.ToHex(this.valueHexView);
|
||||
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;
|
||||
}
|
||||
|
||||
public override toJSON(): LocalSidValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
valueDec: this.valueDec,
|
||||
isFirstSid: this.isFirstSid,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface LocalSidValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { BaseBlockParams } from "../BaseBlock";
|
||||
import { BaseStringBlock } from "../BaseStringBlock";
|
||||
import { LocalSimpleStringValueBlock, LocalSimpleStringValueBlockJson, LocalSimpleStringValueBlockParams } from "./LocalSimpleStringValueBlock";
|
||||
|
||||
export interface LocalSimpleStringBlockParams extends BaseBlockParams, LocalSimpleStringValueBlockParams { }
|
||||
export type LocalSimpleStringBlockJson = LocalSimpleStringValueBlockJson;
|
||||
|
||||
export class LocalSimpleStringBlock extends BaseStringBlock<LocalSimpleStringValueBlock, LocalSimpleStringValueBlockJson> {
|
||||
|
||||
public static override NAME = "SIMPLE STRING";
|
||||
|
||||
constructor({
|
||||
...parameters
|
||||
}: LocalSimpleStringBlockParams = {}) {
|
||||
super(parameters, LocalSimpleStringValueBlock);
|
||||
}
|
||||
|
||||
public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void {
|
||||
this.valueBlock.value = String.fromCharCode.apply(null, pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer) as unknown as number[]);
|
||||
}
|
||||
|
||||
public fromString(inputString: string): void {
|
||||
const strLen = inputString.length;
|
||||
|
||||
const view = this.valueBlock.valueHexView = new Uint8Array(strLen);
|
||||
|
||||
for (let i = 0; i < strLen; i++)
|
||||
view[i] = inputString.charCodeAt(i);
|
||||
|
||||
this.valueBlock.value = inputString;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { ILocalStringValueBlock, LocalStringValueBlockParams, LocalStringValueBlockJson, LocalStringValueBlock } from "./LocalStringValueBlock";
|
||||
|
||||
export type ILocalSimpleStringValueBlock = ILocalStringValueBlock;
|
||||
export type LocalSimpleStringValueBlockParams = LocalStringValueBlockParams;
|
||||
export type LocalSimpleStringValueBlockJson = LocalStringValueBlockJson;
|
||||
|
||||
export class LocalSimpleStringValueBlock extends LocalStringValueBlock {
|
||||
|
||||
public static override NAME = "SimpleStringValueBlock";
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { HexBlockJson, HexBlockParams, HexBlock } from "../HexBlock";
|
||||
import { ValueBlock, ValueBlockJson, ValueBlockParams } from "../ValueBlock";
|
||||
import { EMPTY_STRING } from "./constants";
|
||||
import { LocalUtf8StringValueBlockParams, LocalUtf8StringValueBlockJson } from "./LocalUtf8StringValueBlock";
|
||||
|
||||
export interface ILocalStringValueBlock {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface LocalStringValueBlockParams extends Omit<HexBlockParams, "isHexOnly">, ValueBlockParams, Partial<ILocalStringValueBlock> { }
|
||||
|
||||
export interface LocalStringValueBlockJson extends HexBlockJson, ValueBlockJson, ILocalStringValueBlock { }
|
||||
|
||||
export abstract class LocalStringValueBlock extends HexBlock(ValueBlock) implements ILocalStringValueBlock {
|
||||
|
||||
public static override NAME = "StringValueBlock";
|
||||
|
||||
public value: string;
|
||||
|
||||
constructor({
|
||||
...parameters
|
||||
}: LocalUtf8StringValueBlockParams = {}) {
|
||||
super(parameters);
|
||||
|
||||
this.isHexOnly = true;
|
||||
this.value = EMPTY_STRING; // String representation of decoded ArrayBuffer
|
||||
}
|
||||
|
||||
public override toJSON(): LocalUtf8StringValueBlockJson {
|
||||
return {
|
||||
...super.toJSON(),
|
||||
value: this.value,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface LocalStringValueBlock {
|
||||
/**
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueBeforeDecode: ArrayBuffer;
|
||||
/**
|
||||
* Binary data in ArrayBuffer representation
|
||||
*
|
||||
* @deprecated since version 3.0.0
|
||||
*/
|
||||
// @ts-ignore
|
||||
valueHex: ArrayBuffer;
|
||||
}
|
45
third_party/asn1js/src/internals/LocalUniversalStringValueBlockParams.ts
поставляемый
Normal file
45
third_party/asn1js/src/internals/LocalUniversalStringValueBlockParams.ts
поставляемый
Normal file
|
@ -0,0 +1,45 @@
|
|||
import * as pvutils from "pvutils";
|
||||
import { LocalSimpleStringBlock, LocalSimpleStringBlockJson, LocalSimpleStringBlockParams } from "./LocalSimpleStringBlock";
|
||||
|
||||
export type LocalUniversalStringValueBlockParams = LocalSimpleStringBlockParams;
|
||||
export type LocalUniversalStringValueBlockJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class LocalUniversalStringValueBlock extends LocalSimpleStringBlock {
|
||||
|
||||
public static override NAME = "UniversalStringValueBlock";
|
||||
|
||||
public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void {
|
||||
const copyBuffer = ArrayBuffer.isView(inputBuffer) ? inputBuffer.slice().buffer : 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) as unknown as number[]);
|
||||
}
|
||||
|
||||
public override fromString(inputString: string): void {
|
||||
const strLength = inputString.length;
|
||||
|
||||
const valueHexView = this.valueBlock.valueHexView = new Uint8Array(strLength * 4);
|
||||
|
||||
for (let i = 0; i < strLength; i++) {
|
||||
const codeBuf = 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { LocalSimpleStringBlock, LocalSimpleStringBlockJson, LocalSimpleStringBlockParams } from "./LocalSimpleStringBlock";
|
||||
|
||||
export type LocalUtf8StringValueBlockParams = LocalSimpleStringBlockParams;
|
||||
export type LocalUtf8StringValueBlockJson = LocalSimpleStringBlockJson;
|
||||
|
||||
export class LocalUtf8StringValueBlock extends LocalSimpleStringBlock {
|
||||
|
||||
public static override NAME = "Utf8StringValueBlock";
|
||||
|
||||
public override fromBuffer(inputBuffer: ArrayBuffer | Uint8Array): void {
|
||||
this.valueBlock.valueHexView = pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer);
|
||||
try {
|
||||
this.valueBlock.value = pvtsutils.Convert.ToUtf8String(inputBuffer);
|
||||
}
|
||||
catch (ex) {
|
||||
this.warnings.push(`Error during "decodeURIComponent": ${ex}, using raw string`);
|
||||
this.valueBlock.value = pvtsutils.Convert.ToBinary(inputBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public override fromString(inputString: string): void {
|
||||
this.valueBlock.valueHexView = new Uint8Array(pvtsutils.Convert.FromUtf8String(inputString));
|
||||
this.valueBlock.value = inputString;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// Declaration of global variables
|
||||
|
||||
export const powers2 = [new Uint8Array([1])];
|
||||
export const digitsString = "0123456789";
|
||||
export const NAME = "name";
|
||||
export const VALUE_HEX_VIEW = "valueHexView";
|
||||
export const IS_HEX_ONLY = "isHexOnly";
|
||||
export const ID_BLOCK = "idBlock";
|
||||
export const TAG_CLASS = "tagClass";
|
||||
export const TAG_NUMBER = "tagNumber";
|
||||
export const IS_CONSTRUCTED = "isConstructed";
|
||||
export const FROM_BER = "fromBER";
|
||||
export const TO_BER = "toBER";
|
||||
export const LOCAL = "local";
|
||||
export const EMPTY_STRING = "";
|
||||
export const EMPTY_BUFFER = new ArrayBuffer(0);
|
||||
export const EMPTY_VIEW = new Uint8Array(0);
|
||||
export const END_OF_CONTENT_NAME = "EndOfContent";
|
||||
export const OCTET_STRING_NAME = "OCTET STRING";
|
||||
export const BIT_STRING_NAME = "BIT STRING";
|
|
@ -0,0 +1,81 @@
|
|||
// Utility functions
|
||||
|
||||
import type { LocalBaseBlock } from "./LocalBaseBlock";
|
||||
|
||||
/**
|
||||
* Throws an exception if BigInt is not supported
|
||||
* @throws Throws Error if BigInt is not supported
|
||||
*/
|
||||
export function assertBigInt(): void {
|
||||
if (typeof BigInt === "undefined") {
|
||||
throw new Error("BigInt is not defined. Your environment doesn't implement BigInt.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates buffers from the list
|
||||
* @param buffers List of buffers
|
||||
* @returns Concatenated buffer
|
||||
*/
|
||||
export function concat(buffers: ArrayBuffer[]): ArrayBuffer {
|
||||
let outputLength = 0;
|
||||
let prevLength = 0;
|
||||
|
||||
// Calculate output length
|
||||
for (let i = 0; i < buffers.length; i++) {
|
||||
const buffer = buffers[i];
|
||||
outputLength += buffer.byteLength;
|
||||
}
|
||||
|
||||
const retView = new Uint8Array(outputLength);
|
||||
|
||||
for (let i = 0; i < buffers.length; i++) {
|
||||
const buffer = buffers[i];
|
||||
retView.set(new Uint8Array(buffer), prevLength);
|
||||
prevLength += buffer.byteLength;
|
||||
}
|
||||
|
||||
return retView.buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check input "Uint8Array" for common functions
|
||||
* @param baseBlock
|
||||
* @param inputBuffer
|
||||
* @param inputOffset
|
||||
* @param inputLength
|
||||
* @returns
|
||||
*/
|
||||
export function checkBufferParams(baseBlock: LocalBaseBlock, inputBuffer: Uint8Array, inputOffset: number, inputLength: number): boolean {
|
||||
if (!(inputBuffer instanceof Uint8Array)) {
|
||||
baseBlock.error = "Wrong parameter: inputBuffer must be 'Uint8Array'";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!inputBuffer.byteLength) {
|
||||
baseBlock.error = "Wrong parameter: inputBuffer has zero length";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inputOffset < 0) {
|
||||
baseBlock.error = "Wrong parameter: inputOffset less than zero";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inputLength < 0) {
|
||||
baseBlock.error = "Wrong parameter: inputLength less than zero";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((inputBuffer.byteLength - inputOffset - inputLength) < 0) {
|
||||
baseBlock.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
import * as pvtsutils from "pvtsutils";
|
||||
import { ValueBlock } from "./ValueBlock";
|
||||
import { BaseBlock } from "./BaseBlock";
|
||||
import { LocalBaseBlock } from "./internals/LocalBaseBlock";
|
||||
import { AsnType, typeStore } from "./TypeStore";
|
||||
import { checkBufferParams } from "./internals/utils";
|
||||
|
||||
export interface FromBerResult {
|
||||
offset: number;
|
||||
result: AsnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Local function changing a type for ASN.1 classes
|
||||
* @param inputObject Incoming object
|
||||
* @param newType Target type to convert
|
||||
* @returns Converted object
|
||||
*/
|
||||
function localChangeType<T extends BaseBlock>(inputObject: BaseBlock, newType: new () => T): T {
|
||||
if (inputObject instanceof newType) {
|
||||
return inputObject;
|
||||
}
|
||||
|
||||
const newObject = new newType();
|
||||
newObject.idBlock = inputObject.idBlock;
|
||||
newObject.lenBlock = inputObject.lenBlock;
|
||||
newObject.warnings = inputObject.warnings;
|
||||
newObject.valueBeforeDecodeView = inputObject.valueBeforeDecodeView;
|
||||
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal library function for decoding ASN.1 BER
|
||||
* @param inputBuffer ASN.1 BER encoded array
|
||||
* @param inputOffset Offset in ASN.1 BER encoded array where decoding should be started
|
||||
* @param inputLength Maximum length of array of bytes which can be using in this function
|
||||
* @returns
|
||||
*/
|
||||
export function localFromBER(inputBuffer: Uint8Array, inputOffset = 0, inputLength = inputBuffer.length): FromBerResult {
|
||||
const incomingOffset = inputOffset; // Need to store initial offset since "inputOffset" is changing in the function
|
||||
|
||||
// Create a basic ASN.1 type since we need to return errors and warnings from the function
|
||||
let returnObject = new BaseBlock({}, ValueBlock);
|
||||
|
||||
// Basic check for parameters
|
||||
const baseBlock = new LocalBaseBlock();
|
||||
if (!checkBufferParams(baseBlock, inputBuffer, inputOffset, inputLength)) {
|
||||
returnObject.error = baseBlock.error;
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
|
||||
// Getting Uint8Array subarray
|
||||
const intBuffer = inputBuffer.subarray(inputOffset, inputOffset + inputLength);
|
||||
|
||||
// Initial checks
|
||||
if (!intBuffer.length) {
|
||||
returnObject.error = "Zero buffer length";
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
|
||||
// Decode identification block of ASN.1 BER structure
|
||||
// console.time("idBlock");
|
||||
let resultOffset = returnObject.idBlock.fromBER(inputBuffer, inputOffset, inputLength);
|
||||
if (returnObject.idBlock.warnings.length) {
|
||||
returnObject.warnings.concat(returnObject.idBlock.warnings);
|
||||
}
|
||||
if (resultOffset === -1) {
|
||||
returnObject.error = returnObject.idBlock.error;
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
// console.timeEnd("idBlock");
|
||||
|
||||
inputOffset = resultOffset;
|
||||
inputLength -= returnObject.idBlock.blockLength;
|
||||
|
||||
// Decode length block of ASN.1 BER structure
|
||||
// console.time("lengthBlock");
|
||||
resultOffset = returnObject.lenBlock.fromBER(inputBuffer, inputOffset, inputLength);
|
||||
if (returnObject.lenBlock.warnings.length) {
|
||||
returnObject.warnings.concat(returnObject.lenBlock.warnings);
|
||||
}
|
||||
if (resultOffset === -1) {
|
||||
returnObject.error = returnObject.lenBlock.error;
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
// console.timeEnd("lengthBlock");
|
||||
|
||||
inputOffset = resultOffset;
|
||||
inputLength -= returnObject.lenBlock.blockLength;
|
||||
|
||||
// Check for using indefinite length form in encoding for primitive types
|
||||
if (!returnObject.idBlock.isConstructed &&
|
||||
returnObject.lenBlock.isIndefiniteForm) {
|
||||
returnObject.error = "Indefinite length form used for primitive encoding form";
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
|
||||
// Switch ASN.1 block type
|
||||
let newASN1Type: new () => AsnType = BaseBlock as any;
|
||||
|
||||
switch (returnObject.idBlock.tagClass) {
|
||||
// UNIVERSAL
|
||||
case 1:
|
||||
// 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
|
||||
};
|
||||
}
|
||||
switch (returnObject.idBlock.tagNumber) {
|
||||
case 0: // EndOfContent
|
||||
// Check for EndOfContent type
|
||||
if ((returnObject.idBlock.isConstructed) &&
|
||||
(returnObject.lenBlock.length > 0)) {
|
||||
returnObject.error = "Type [UNIVERSAL 0] is reserved";
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
|
||||
newASN1Type = typeStore.EndOfContent;
|
||||
|
||||
break;
|
||||
case 1: // Boolean
|
||||
newASN1Type = typeStore.Boolean;
|
||||
break;
|
||||
case 2: // Integer
|
||||
newASN1Type = typeStore.Integer;
|
||||
break;
|
||||
case 3: // BitString
|
||||
newASN1Type = typeStore.BitString;
|
||||
break;
|
||||
case 4: // OctetString
|
||||
newASN1Type = typeStore.OctetString;
|
||||
break;
|
||||
case 5: // Null
|
||||
newASN1Type = typeStore.Null;
|
||||
break;
|
||||
case 6: // ObjectIdentifier
|
||||
newASN1Type = typeStore.ObjectIdentifier;
|
||||
break;
|
||||
case 10: // Enumerated
|
||||
newASN1Type = typeStore.Enumerated;
|
||||
break;
|
||||
case 12: // Utf8String
|
||||
newASN1Type = typeStore.Utf8String;
|
||||
break;
|
||||
case 13: // RelativeObjectIdentifier
|
||||
newASN1Type = typeStore.RelativeObjectIdentifier;
|
||||
break;
|
||||
case 14: // TIME
|
||||
newASN1Type = typeStore.TIME;
|
||||
break;
|
||||
case 15:
|
||||
returnObject.error = "[UNIVERSAL 15] is reserved by ASN.1 standard";
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result: returnObject
|
||||
};
|
||||
case 16: // Sequence
|
||||
newASN1Type = typeStore.Sequence;
|
||||
break;
|
||||
case 17: // Set
|
||||
newASN1Type = typeStore.Set;
|
||||
break;
|
||||
case 18: // NumericString
|
||||
newASN1Type = typeStore.NumericString;
|
||||
break;
|
||||
case 19: // PrintableString
|
||||
newASN1Type = typeStore.PrintableString;
|
||||
break;
|
||||
case 20: // TeletexString
|
||||
newASN1Type = typeStore.TeletexString;
|
||||
break;
|
||||
case 21: // VideotexString
|
||||
newASN1Type = typeStore.VideotexString;
|
||||
break;
|
||||
case 22: // IA5String
|
||||
newASN1Type = typeStore.IA5String;
|
||||
break;
|
||||
case 23: // UTCTime
|
||||
newASN1Type = typeStore.UTCTime;
|
||||
break;
|
||||
case 24: // GeneralizedTime
|
||||
newASN1Type = typeStore.GeneralizedTime;
|
||||
break;
|
||||
case 25: // GraphicString
|
||||
newASN1Type = typeStore.GraphicString;
|
||||
break;
|
||||
case 26: // VisibleString
|
||||
newASN1Type = typeStore.VisibleString;
|
||||
break;
|
||||
case 27: // GeneralString
|
||||
newASN1Type = typeStore.GeneralString;
|
||||
break;
|
||||
case 28: // UniversalString
|
||||
newASN1Type = typeStore.UniversalString;
|
||||
break;
|
||||
case 29: // CharacterString
|
||||
newASN1Type = typeStore.CharacterString;
|
||||
break;
|
||||
case 30: // BmpString
|
||||
newASN1Type = typeStore.BmpString;
|
||||
break;
|
||||
case 31: // DATE
|
||||
newASN1Type = typeStore.DATE;
|
||||
break;
|
||||
case 32: // TimeOfDay
|
||||
newASN1Type = typeStore.TimeOfDay;
|
||||
break;
|
||||
case 33: // DateTime
|
||||
newASN1Type = typeStore.DateTime;
|
||||
break;
|
||||
case 34: // Duration
|
||||
newASN1Type = typeStore.Duration;
|
||||
break;
|
||||
default: {
|
||||
const newObject = returnObject.idBlock.isConstructed
|
||||
? new typeStore.Constructed()
|
||||
: new typeStore.Primitive();
|
||||
|
||||
newObject.idBlock = returnObject.idBlock;
|
||||
newObject.lenBlock = returnObject.lenBlock;
|
||||
newObject.warnings = returnObject.warnings;
|
||||
|
||||
returnObject = newObject;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// All other tag classes
|
||||
case 2: // APPLICATION
|
||||
case 3: // CONTEXT-SPECIFIC
|
||||
case 4: // PRIVATE
|
||||
default: {
|
||||
newASN1Type = returnObject.idBlock.isConstructed
|
||||
? typeStore.Constructed
|
||||
: typeStore.Primitive;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Change type and perform BER decoding
|
||||
returnObject = localChangeType(returnObject, newASN1Type);
|
||||
// console.time("valueBlock");
|
||||
resultOffset = returnObject.fromBER(inputBuffer, inputOffset, returnObject.lenBlock.isIndefiniteForm ? inputLength : returnObject.lenBlock.length);
|
||||
|
||||
// Coping incoming buffer for entire ASN.1 block
|
||||
returnObject.valueBeforeDecodeView = inputBuffer.subarray(incomingOffset, incomingOffset + returnObject.blockLength);
|
||||
// console.timeEnd("valueBlock");
|
||||
|
||||
return {
|
||||
offset: resultOffset,
|
||||
result: returnObject
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Major function for decoding ASN.1 BER array into internal library structures
|
||||
* @param inputBuffer ASN.1 BER encoded array of bytes
|
||||
*/
|
||||
export function fromBER(inputBuffer: pvtsutils.BufferSource): FromBerResult {
|
||||
if (!inputBuffer.byteLength) {
|
||||
const result = new BaseBlock({}, ValueBlock);
|
||||
result.error = "Input buffer has zero length";
|
||||
|
||||
return {
|
||||
offset: -1,
|
||||
result
|
||||
};
|
||||
}
|
||||
|
||||
return localFromBER(pvtsutils.BufferSourceConverter.toUint8Array(inputBuffer).slice(), 0, inputBuffer.byteLength);
|
||||
}
|
|
@ -0,0 +1,475 @@
|
|||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import * as pvtsutils from "pvtsutils";
|
||||
import { IS_CONSTRUCTED, EMPTY_STRING, NAME, ID_BLOCK, FROM_BER, TO_BER, TAG_CLASS, TAG_NUMBER, IS_HEX_ONLY, LOCAL, VALUE_HEX_VIEW } from "./internals/constants";
|
||||
import { Any } from "./Any";
|
||||
import { Choice } from "./Choice";
|
||||
import { Repeated } from "./Repeated";
|
||||
import { localFromBER } from "./parser";
|
||||
import { AsnType, typeStore } from "./TypeStore";
|
||||
|
||||
export type AsnSchemaType = AsnType | Any | Choice | Repeated;
|
||||
|
||||
export interface CompareSchemaSuccess {
|
||||
verified: true;
|
||||
result: AsnType & { [key: string]: any; };
|
||||
}
|
||||
|
||||
export interface CompareSchemaFail {
|
||||
verified: false;
|
||||
name?: string;
|
||||
result: AsnType | { error: string; };
|
||||
}
|
||||
|
||||
export type CompareSchemaResult = CompareSchemaSuccess | CompareSchemaFail;
|
||||
|
||||
/**
|
||||
* Compare of two ASN.1 object trees
|
||||
* @param root Root of input ASN.1 object tree
|
||||
* @param inputData Input ASN.1 object tree
|
||||
* @param inputSchema Input ASN.1 schema to compare with
|
||||
* @return Returns result of comparison
|
||||
*/
|
||||
export function compareSchema(root: AsnType, inputData: AsnType, inputSchema: AsnSchemaType): CompareSchemaResult {
|
||||
//#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) {
|
||||
return {
|
||||
verified: true,
|
||||
result: root
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (choiceResult === false) {
|
||||
const _result: CompareSchemaResult = {
|
||||
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 as any)[inputSchema.name] = inputData; // TODO Such call may replace original field of the object (eg idBlock)
|
||||
|
||||
|
||||
//#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 ((ID_BLOCK 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 necessary because could be an errors in schema definition</remarks>
|
||||
if ((FROM_BER in inputSchema.idBlock) === false) {
|
||||
return {
|
||||
verified: false,
|
||||
result: { error: "Wrong ASN.1 schema" }
|
||||
};
|
||||
}
|
||||
|
||||
if ((TO_BER 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(TAG_CLASS) === 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(TAG_NUMBER) === 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(IS_CONSTRUCTED) === 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 (!(IS_HEX_ONLY in inputSchema.idBlock)) // Since 'isHexOnly' is an inherited 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) {
|
||||
if ((VALUE_HEX_VIEW in inputSchema.idBlock) === false) // Since 'valueHex' is an inherited property
|
||||
{
|
||||
return {
|
||||
verified: false,
|
||||
result: { error: "Wrong ASN.1 schema" }
|
||||
};
|
||||
}
|
||||
|
||||
const schemaView = inputSchema.idBlock.valueHexView;
|
||||
const asn1View = inputData.idBlock.valueHexView;
|
||||
|
||||
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.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name)
|
||||
(root as any)[inputSchema.name] = inputData; // TODO check field existence. If exists throw an error
|
||||
}
|
||||
//#endregion
|
||||
//#region Getting next ASN.1 block for comparison
|
||||
if (inputSchema instanceof typeStore.Constructed) {
|
||||
// TODO not clear how it works for OctetString and BitString
|
||||
//* if (inputSchema.idBlock.isConstructed) {
|
||||
let admission = 0;
|
||||
let result: CompareSchemaResult = {
|
||||
verified: false,
|
||||
result: {
|
||||
error: "Unknown error",
|
||||
}
|
||||
};
|
||||
|
||||
let maxLength = inputSchema.valueBlock.value.length;
|
||||
|
||||
if (maxLength > 0) {
|
||||
if (inputSchema.valueBlock.value[0] instanceof Repeated) {
|
||||
// @ts-ignore
|
||||
maxLength = inputData.valueBlock.value.length; // TODO debug it
|
||||
}
|
||||
}
|
||||
|
||||
//#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
|
||||
// @ts-ignore
|
||||
// TODO debug it
|
||||
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) {
|
||||
return {
|
||||
verified: true,
|
||||
result: root
|
||||
};
|
||||
}
|
||||
|
||||
//#region Delete early added name of block
|
||||
if (inputSchema.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name)
|
||||
delete (root as any)[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
|
||||
// @ts-ignore
|
||||
if ((i - admission) >= inputData.valueBlock.value.length) {
|
||||
if (inputSchema.valueBlock.value[i].optional === false) {
|
||||
const _result: CompareSchemaResult = {
|
||||
verified: false,
|
||||
result: root
|
||||
};
|
||||
|
||||
root.error = "Inconsistent length between ASN.1 data and schema";
|
||||
|
||||
//#region Delete early added name of block
|
||||
if (inputSchema.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name) {
|
||||
delete (root as any)[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) {
|
||||
// @ts-ignore
|
||||
result = compareSchema(root, inputData.valueBlock.value[i], inputSchema.valueBlock.value[0].value);
|
||||
if (result.verified === false) {
|
||||
if (inputSchema.valueBlock.value[0].optional)
|
||||
admission++;
|
||||
else {
|
||||
//#region Delete early added name of block
|
||||
if (inputSchema.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name)
|
||||
delete (root as any)[inputSchema.name];
|
||||
}
|
||||
//#endregion
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if ((NAME in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].name.length > 0)) {
|
||||
let arrayRoot: Record<string, any> = {};
|
||||
|
||||
if ((LOCAL in inputSchema.valueBlock.value[0]) && (inputSchema.valueBlock.value[0].local))
|
||||
arrayRoot = inputData;
|
||||
|
||||
else
|
||||
arrayRoot = root;
|
||||
|
||||
if (typeof arrayRoot[inputSchema.valueBlock.value[0].name] === "undefined")
|
||||
arrayRoot[inputSchema.valueBlock.value[0].name] = [];
|
||||
|
||||
// @ts-ignore
|
||||
arrayRoot[inputSchema.valueBlock.value[0].name].push(inputData.valueBlock.value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//#endregion
|
||||
else {
|
||||
// @ts-ignore
|
||||
result = compareSchema(root, inputData.valueBlock.value[i - admission], inputSchema.valueBlock.value[i]);
|
||||
if (result.verified === false) {
|
||||
if (inputSchema.valueBlock.value[i].optional)
|
||||
admission++;
|
||||
else {
|
||||
//#region Delete early added name of block
|
||||
if (inputSchema.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name)
|
||||
delete (root as any)[inputSchema.name];
|
||||
}
|
||||
//#endregion
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.verified === false) // The situation may take place if last element is OPTIONAL and verification failed
|
||||
{
|
||||
const _result: CompareSchemaResult = {
|
||||
verified: false,
|
||||
result: root
|
||||
};
|
||||
|
||||
//#region Delete early added name of block
|
||||
if (inputSchema.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name) {
|
||||
delete (root as any)[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 (inputSchema.primitiveSchema &&
|
||||
(VALUE_HEX_VIEW in inputData.valueBlock)) {
|
||||
//#region Decoding of raw ASN.1 data
|
||||
const asn1 = localFromBER(inputData.valueBlock.valueHexView);
|
||||
if (asn1.offset === -1) {
|
||||
const _result: CompareSchemaResult = {
|
||||
verified: false,
|
||||
result: asn1.result
|
||||
};
|
||||
|
||||
//#region Delete early added name of block
|
||||
if (inputSchema.name) {
|
||||
inputSchema.name = inputSchema.name.replace(/^\s+|\s+$/g, EMPTY_STRING);
|
||||
if (inputSchema.name) {
|
||||
delete (root as any)[inputSchema.name];
|
||||
_result.name = inputSchema.name;
|
||||
}
|
||||
}
|
||||
//#endregion
|
||||
|
||||
return _result;
|
||||
}
|
||||
//#endregion
|
||||
|
||||
return compareSchema(root, asn1.result, inputSchema.primitiveSchema);
|
||||
}
|
||||
|
||||
return {
|
||||
verified: true,
|
||||
result: root
|
||||
};
|
||||
//#endregion
|
||||
}
|
||||
/**
|
||||
* ASN.1 schema verification for ArrayBuffer data
|
||||
* @param inputBuffer Input BER-encoded ASN.1 data
|
||||
* @param inputSchema Input ASN.1 schema to verify against to
|
||||
* @return
|
||||
*/
|
||||
|
||||
export function verifySchema(inputBuffer: pvtsutils.BufferSource, inputSchema: AsnSchemaType): CompareSchemaResult {
|
||||
//#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 = localFromBER(pvtsutils.BufferSourceConverter.toUint8Array(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
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
export interface IBerConvertible {
|
||||
|
||||
/**
|
||||
* Base function for converting block from BER encoded array of bytes
|
||||
* @param inputBuffer ASN.1 BER encoded array
|
||||
* @param inputOffset Offset in ASN.1 BER encoded array where decoding should be started
|
||||
* @param inputLength Maximum length of array of bytes which can be using in this function
|
||||
* @returns Offset after least decoded byte
|
||||
*/
|
||||
fromBER(inputBuffer: ArrayBuffer | Uint8Array, inputOffset: number, inputLength: number): number;
|
||||
/**
|
||||
* Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
|
||||
* @param sizeOnly Flag that we need only a size of encoding, not a real array of bytes
|
||||
* @returns ASN.1 BER encoded array
|
||||
*/
|
||||
toBER(sizeOnly?: boolean): ArrayBuffer;
|
||||
}
|
||||
|
||||
export interface IDerConvertible {
|
||||
/**
|
||||
* Base function for converting block from DER encoded array of bytes
|
||||
* @param inputBuffer ASN.1 DER encoded array
|
||||
* @param inputOffset Offset in ASN.1 DER encoded array where decoding should be started
|
||||
* @param inputLength Maximum length of array of bytes which can be using in this function
|
||||
* @param expectedLength Expected length of converted VALUE_HEX buffer
|
||||
* @returns Offset after least decoded byte
|
||||
*/
|
||||
fromDER(inputBuffer: ArrayBuffer, inputOffset: number, inputLength: number, expectedLength?: number): number;
|
||||
/**
|
||||
* Encoding of current ASN.1 block into ASN.1 encoded array (DER rules)
|
||||
* @param sizeOnly Flag that we need only a size of encoding, not a real array of bytes
|
||||
* @returns ASN.1 DER encoded array
|
||||
*/
|
||||
toDER(sizeOnly?: boolean): ArrayBuffer;
|
||||
}
|
||||
|
||||
export interface IStringConvertible {
|
||||
/**
|
||||
* Returns a string representation of an object
|
||||
* @returns String representation of the class object
|
||||
*/
|
||||
toString(): string;
|
||||
/**
|
||||
* Creates a class object from the string
|
||||
* @param data Input string to convert from
|
||||
*/
|
||||
fromString(data: string): void;
|
||||
}
|
||||
|
||||
export interface IDateConvertible {
|
||||
/**
|
||||
* Converts a class object into the JavaScrip Date Object
|
||||
* @returns Date object
|
||||
*/
|
||||
toDate(): Date;
|
||||
/**
|
||||
* Creates a class object from the JavaScript Date object
|
||||
* @param date Date object
|
||||
*/
|
||||
fromDate(date: Date): void;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2019",
|
||||
"module": "CommonJS",
|
||||
"lib": [
|
||||
"ES2019"
|
||||
],
|
||||
"strict": true,
|
||||
"importHelpers": true,
|
||||
"noImplicitOverride": true,
|
||||
"skipLibCheck": true,
|
||||
"noErrorTruncation": true,
|
||||
"experimentalDecorators": true
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче