summaryrefslogtreecommitdiffstats
path: root/comm/third_party/asn1js/src/internals/LocalConstructedValueBlock.ts
blob: db3ba9f35ebcf38c92efb1dbc438db4d53b1bbc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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;
  }
}