summaryrefslogtreecommitdiffstats
path: root/comm/third_party/asn1js/src/internals/LocalBitStringValueBlock.ts
blob: 1720b55d823624f6344d4720589f15de2b6108d3 (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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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;
}