diff options
Diffstat (limited to 'comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts')
-rw-r--r-- | comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts b/comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts new file mode 100644 index 0000000000..d97c874b7a --- /dev/null +++ b/comm/third_party/asn1js/src/internals/LocalIdentificationBlock.ts @@ -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; +}
\ No newline at end of file |