goscript 0.2.4 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/README.md +8 -8
  2. package/cmd/go_js_wasm_exec/main.go +1 -1
  3. package/cmd/go_js_wasm_exec/main_test.go +1 -1
  4. package/cmd/goscript/cmd-compile.go +9 -1
  5. package/cmd/goscript/cmd-test.go +1 -1
  6. package/cmd/goscript/cmd_compile_test.go +44 -0
  7. package/cmd/goscript/deps.go +1 -1
  8. package/cmd/goscript-wasm/main.go +2 -2
  9. package/compiler/compile-request.go +19 -0
  10. package/compiler/compile_bench_test.go +121 -0
  11. package/compiler/compliance_test.go +17 -1
  12. package/compiler/config.go +2 -0
  13. package/compiler/gotest/result.go +1 -1
  14. package/compiler/gotest/runner.go +2 -2
  15. package/compiler/gotest/runner_test.go +4 -7
  16. package/compiler/index.test.ts +28 -0
  17. package/compiler/index.ts +32 -16
  18. package/compiler/lowering.go +1238 -194
  19. package/compiler/lowering_bench_test.go +4 -0
  20. package/compiler/override-facts.go +1 -1
  21. package/compiler/package-graph.go +92 -0
  22. package/compiler/package-graph_test.go +113 -0
  23. package/compiler/runtime-contract.go +1 -1
  24. package/compiler/semantic-model.go +32 -0
  25. package/compiler/skeleton_test.go +241 -15
  26. package/compiler/wasm/compile.go +1 -1
  27. package/compiler/wasm/compile_test.go +1 -1
  28. package/dist/compiler/index.d.ts +4 -0
  29. package/dist/compiler/index.js +26 -15
  30. package/dist/compiler/index.js.map +1 -1
  31. package/dist/gs/database/sql/driver/index.d.ts +165 -0
  32. package/dist/gs/database/sql/driver/index.js +432 -0
  33. package/dist/gs/database/sql/driver/index.js.map +1 -0
  34. package/dist/gs/encoding/binary/index.d.ts +71 -0
  35. package/dist/gs/encoding/binary/index.js +778 -0
  36. package/dist/gs/encoding/binary/index.js.map +1 -0
  37. package/dist/gs/fmt/fmt.js +156 -57
  38. package/dist/gs/fmt/fmt.js.map +1 -1
  39. package/dist/gs/github.com/klauspost/cpuid/v2/index.d.ts +11 -0
  40. package/dist/gs/github.com/klauspost/cpuid/v2/index.js +28 -0
  41. package/dist/gs/github.com/klauspost/cpuid/v2/index.js.map +1 -0
  42. package/dist/gs/github.com/pkg/errors/errors.d.ts +0 -2
  43. package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
  44. package/dist/gs/github.com/pkg/errors/index.d.ts +2 -1
  45. package/dist/gs/github.com/pkg/errors/index.js +1 -1
  46. package/dist/gs/github.com/pkg/errors/index.js.map +1 -1
  47. package/dist/gs/github.com/pkg/errors/stack.d.ts +8 -19
  48. package/dist/gs/github.com/pkg/errors/stack.js +26 -61
  49. package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
  50. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.d.ts +19 -0
  51. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js +25 -0
  52. package/dist/gs/golang.org/x/crypto/cryptobyte/asn1/index.js.map +1 -0
  53. package/dist/gs/golang.org/x/crypto/cryptobyte/index.d.ts +104 -0
  54. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1107 -0
  55. package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -0
  56. package/dist/gs/golang.org/x/crypto/internal/alias/index.d.ts +3 -0
  57. package/dist/gs/golang.org/x/crypto/internal/alias/index.js +39 -0
  58. package/dist/gs/golang.org/x/crypto/internal/alias/index.js.map +1 -0
  59. package/dist/gs/runtime/runtime.d.ts +6 -1
  60. package/dist/gs/runtime/runtime.js +15 -8
  61. package/dist/gs/runtime/runtime.js.map +1 -1
  62. package/dist/gs/runtime/trace/index.d.ts +8 -5
  63. package/dist/gs/runtime/trace/index.js +324 -23
  64. package/dist/gs/runtime/trace/index.js.map +1 -1
  65. package/dist/gs/slices/slices.d.ts +2 -1
  66. package/dist/gs/slices/slices.js +9 -3
  67. package/dist/gs/slices/slices.js.map +1 -1
  68. package/dist/gs/sort/search.gs.d.ts +3 -1
  69. package/dist/gs/sort/search.gs.js +18 -53
  70. package/dist/gs/sort/search.gs.js.map +1 -1
  71. package/dist/gs/sync/sync.d.ts +1 -1
  72. package/dist/gs/sync/sync.js +3 -0
  73. package/dist/gs/sync/sync.js.map +1 -1
  74. package/dist/gs/time/time.d.ts +22 -29
  75. package/dist/gs/time/time.js +111 -32
  76. package/dist/gs/time/time.js.map +1 -1
  77. package/dist/gs/unsafe/unsafe.d.ts +3 -2
  78. package/dist/gs/unsafe/unsafe.js.map +1 -1
  79. package/go.mod +7 -5
  80. package/go.sum +12 -26
  81. package/gs/database/sql/driver/index.test.ts +88 -0
  82. package/gs/database/sql/driver/index.ts +675 -0
  83. package/gs/database/sql/driver/meta.json +3 -0
  84. package/gs/database/sql/driver/parity.json +144 -0
  85. package/gs/encoding/binary/index.test.ts +239 -0
  86. package/gs/encoding/binary/index.ts +999 -0
  87. package/gs/encoding/binary/meta.json +9 -0
  88. package/gs/encoding/binary/parity.json +72 -0
  89. package/gs/fmt/fmt.test.ts +28 -0
  90. package/gs/fmt/fmt.ts +198 -61
  91. package/gs/fmt/meta.json +2 -1
  92. package/gs/github.com/klauspost/cpuid/v2/index.ts +38 -0
  93. package/gs/github.com/klauspost/cpuid/v2/meta.json +3 -0
  94. package/gs/github.com/pkg/errors/errors.ts +1 -2
  95. package/gs/github.com/pkg/errors/index.ts +2 -1
  96. package/gs/github.com/pkg/errors/stack.ts +34 -62
  97. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.test.ts +19 -0
  98. package/gs/golang.org/x/crypto/cryptobyte/asn1/index.ts +29 -0
  99. package/gs/golang.org/x/crypto/cryptobyte/index.test.ts +255 -0
  100. package/gs/golang.org/x/crypto/cryptobyte/index.ts +1441 -0
  101. package/gs/golang.org/x/crypto/cryptobyte/meta.json +3 -0
  102. package/gs/golang.org/x/crypto/internal/alias/index.test.ts +40 -0
  103. package/gs/golang.org/x/crypto/internal/alias/index.ts +40 -0
  104. package/gs/runtime/runtime.test.ts +16 -0
  105. package/gs/runtime/runtime.ts +17 -9
  106. package/gs/runtime/trace/index.test.ts +113 -14
  107. package/gs/runtime/trace/index.ts +384 -34
  108. package/gs/runtime/trace/meta.json +1 -0
  109. package/gs/slices/slices.test.ts +24 -1
  110. package/gs/slices/slices.ts +14 -4
  111. package/gs/sort/meta.json +1 -0
  112. package/gs/sort/search.gs.ts +20 -5
  113. package/gs/sync/sync.ts +4 -1
  114. package/gs/time/time.test.ts +79 -2
  115. package/gs/time/time.ts +133 -33
  116. package/gs/unsafe/unsafe.ts +4 -2
  117. package/package.json +2 -2
@@ -0,0 +1,1441 @@
1
+ import * as $ from '@goscript/builtin/index.js'
2
+ import * as asn1 from '@goscript/golang.org/x/crypto/cryptobyte/asn1/index.js'
3
+ import * as time from '@goscript/time/index.js'
4
+
5
+ export type String = $.Bytes
6
+
7
+ export type BuilderContinuation = ((child: Builder | null) => void) | null
8
+
9
+ export type MarshalingValue = {
10
+ Marshal(builder: Builder | $.VarRef<Builder> | null): $.GoError
11
+ }
12
+
13
+ const maxUint64 = (1n << 64n) - 1n
14
+ const maxInt64 = (1n << 63n) - 1n
15
+ const minInt64 = -(1n << 63n)
16
+
17
+ function byte(value: number | bigint): number {
18
+ if (typeof value === 'bigint') {
19
+ return Number(BigInt.asUintN(8, value))
20
+ }
21
+ return Number(value) & 0xff
22
+ }
23
+
24
+ function bytesArray(bytes: $.Bytes | string | null | undefined): number[] {
25
+ if (bytes == null) {
26
+ return []
27
+ }
28
+ if (typeof bytes === 'string') {
29
+ return Array.from(bytes, (ch) => ch.charCodeAt(0) & 0xff)
30
+ }
31
+ return Array.from($.bytesToUint8Array(bytes))
32
+ }
33
+
34
+ function bytesFromArray(bytes: number[]): $.Bytes {
35
+ return new Uint8Array(bytes.map(byte))
36
+ }
37
+
38
+ function bytesFromString(value: string): $.Bytes {
39
+ return new Uint8Array(Array.from(value, (ch) => ch.charCodeAt(0) & 0xff))
40
+ }
41
+
42
+ function bytesToAscii(bytes: $.Bytes): string {
43
+ return globalThis.String.fromCharCode(...bytesArray(bytes))
44
+ }
45
+
46
+ function stringValue(s: $.VarRef<String> | null): String {
47
+ if (s == null) {
48
+ throw new Error(
49
+ 'runtime error: invalid memory address or nil pointer dereference',
50
+ )
51
+ }
52
+ return s.value
53
+ }
54
+
55
+ function read(s: $.VarRef<String> | null, n: number): $.Bytes | null {
56
+ const data = stringValue(s)
57
+ if ($.len(data) < n) {
58
+ return null
59
+ }
60
+ const out = $.goSlice(data, 0, n)
61
+ s!.value = $.goSlice(data, n)
62
+ return out
63
+ }
64
+
65
+ function readUint(bytes: $.Bytes): number {
66
+ let out = 0
67
+ for (const b of bytesArray(bytes)) {
68
+ out = out * 256 + b
69
+ }
70
+ return out
71
+ }
72
+
73
+ function readUint64Value(bytes: $.Bytes): number {
74
+ let out = 0n
75
+ for (const b of bytesArray(bytes)) {
76
+ out = (out << 8n) | BigInt(b)
77
+ }
78
+ return $.uint(out, 64)
79
+ }
80
+
81
+ function writeRef<T>(out: $.VarRef<T> | null, value: T): void {
82
+ if (out == null) {
83
+ throw new Error(
84
+ 'runtime error: invalid memory address or nil pointer dereference',
85
+ )
86
+ }
87
+ out.value = value
88
+ }
89
+
90
+ export function String_Skip(s: $.VarRef<String> | null, n: number): boolean {
91
+ return read(s, n) !== null
92
+ }
93
+
94
+ export function String_ReadUint8(
95
+ s: $.VarRef<String> | null,
96
+ out: $.VarRef<number> | null,
97
+ ): boolean {
98
+ const v = read(s, 1)
99
+ if (v == null) {
100
+ return false
101
+ }
102
+ writeRef(out, bytesArray(v)[0])
103
+ return true
104
+ }
105
+
106
+ export function String_ReadUint16(
107
+ s: $.VarRef<String> | null,
108
+ out: $.VarRef<number> | null,
109
+ ): boolean {
110
+ const v = read(s, 2)
111
+ if (v == null) {
112
+ return false
113
+ }
114
+ writeRef(out, readUint(v))
115
+ return true
116
+ }
117
+
118
+ export function String_ReadUint24(
119
+ s: $.VarRef<String> | null,
120
+ out: $.VarRef<number> | null,
121
+ ): boolean {
122
+ const v = read(s, 3)
123
+ if (v == null) {
124
+ return false
125
+ }
126
+ writeRef(out, readUint(v))
127
+ return true
128
+ }
129
+
130
+ export function String_ReadUint32(
131
+ s: $.VarRef<String> | null,
132
+ out: $.VarRef<number> | null,
133
+ ): boolean {
134
+ const v = read(s, 4)
135
+ if (v == null) {
136
+ return false
137
+ }
138
+ writeRef(out, $.uint(readUint(v), 32))
139
+ return true
140
+ }
141
+
142
+ export function String_ReadUint48(
143
+ s: $.VarRef<String> | null,
144
+ out: $.VarRef<number> | null,
145
+ ): boolean {
146
+ const v = read(s, 6)
147
+ if (v == null) {
148
+ return false
149
+ }
150
+ writeRef(out, readUint(v))
151
+ return true
152
+ }
153
+
154
+ export function String_ReadUint64(
155
+ s: $.VarRef<String> | null,
156
+ out: $.VarRef<number> | null,
157
+ ): boolean {
158
+ const v = read(s, 8)
159
+ if (v == null) {
160
+ return false
161
+ }
162
+ writeRef(out, readUint64Value(v))
163
+ return true
164
+ }
165
+
166
+ function readLengthPrefixed(
167
+ s: $.VarRef<String> | null,
168
+ lenLen: number,
169
+ out: $.VarRef<String> | null,
170
+ ): boolean {
171
+ const data = stringValue(s)
172
+ if ($.len(data) < lenLen) {
173
+ return false
174
+ }
175
+ const length = readUint($.goSlice(data, 0, lenLen))
176
+ if ($.len(data) < lenLen + length) {
177
+ return false
178
+ }
179
+ writeRef(out, $.goSlice(data, lenLen, lenLen + length))
180
+ s!.value = $.goSlice(data, lenLen + length)
181
+ return true
182
+ }
183
+
184
+ export function String_ReadUint8LengthPrefixed(
185
+ s: $.VarRef<String> | null,
186
+ out: $.VarRef<String> | null,
187
+ ): boolean {
188
+ return readLengthPrefixed(s, 1, out)
189
+ }
190
+
191
+ export function String_ReadUint16LengthPrefixed(
192
+ s: $.VarRef<String> | null,
193
+ out: $.VarRef<String> | null,
194
+ ): boolean {
195
+ return readLengthPrefixed(s, 2, out)
196
+ }
197
+
198
+ export function String_ReadUint24LengthPrefixed(
199
+ s: $.VarRef<String> | null,
200
+ out: $.VarRef<String> | null,
201
+ ): boolean {
202
+ return readLengthPrefixed(s, 3, out)
203
+ }
204
+
205
+ export function String_ReadBytes(
206
+ s: $.VarRef<String> | null,
207
+ out: $.VarRef<$.Bytes> | null,
208
+ n: number,
209
+ ): boolean {
210
+ const v = read(s, n)
211
+ if (v == null) {
212
+ return false
213
+ }
214
+ writeRef(out, v)
215
+ return true
216
+ }
217
+
218
+ export function String_CopyBytes(
219
+ s: $.VarRef<String> | null,
220
+ out: $.Bytes,
221
+ ): boolean {
222
+ if ($.len(out) > $.len(stringValue(s))) {
223
+ return false
224
+ }
225
+ const v = read(s, $.len(out))
226
+ if (v == null) {
227
+ return false
228
+ }
229
+ $.copy(out, v)
230
+ return true
231
+ }
232
+
233
+ export function String_Empty(s: String): boolean {
234
+ return $.len(s) === 0
235
+ }
236
+
237
+ export class BuildError {
238
+ public Err: $.GoError
239
+
240
+ constructor(init?: Partial<{ Err: $.GoError }>) {
241
+ this.Err = init?.Err ?? null
242
+ }
243
+
244
+ public Error(): string {
245
+ return this.Err == null ? '' : this.Err.Error()
246
+ }
247
+ }
248
+
249
+ export class Builder {
250
+ private err: $.GoError
251
+ private result: number[]
252
+ private fixedSize: boolean
253
+ private capacityLimit: number
254
+ private child: Builder | null
255
+ private offset: number
256
+ private pendingLenLen: number
257
+ private pendingIsASN1: boolean
258
+
259
+ constructor(
260
+ init?: Partial<{
261
+ err: $.GoError
262
+ result: $.Bytes
263
+ resultArray: number[]
264
+ fixedSize: boolean
265
+ capacityLimit: number
266
+ }>,
267
+ ) {
268
+ this.err = init?.err ?? null
269
+ this.result = init?.resultArray ?? bytesArray(init?.result)
270
+ this.fixedSize = init?.fixedSize ?? false
271
+ this.capacityLimit =
272
+ init?.capacityLimit ?? (init?.result == null ? this.result.length : $.cap(init.result))
273
+ this.child = null
274
+ this.offset = 0
275
+ this.pendingLenLen = 0
276
+ this.pendingIsASN1 = false
277
+ }
278
+
279
+ public SetError(err: $.GoError): void {
280
+ if (this.err == null) {
281
+ this.err = err
282
+ }
283
+ }
284
+
285
+ public Bytes(): [$.Bytes, $.GoError] {
286
+ this.flushChild()
287
+ if (this.err != null) {
288
+ return [null as unknown as $.Bytes, this.err]
289
+ }
290
+ if (this.fixedSize && this.result.length !== this.capacityLimit) {
291
+ return [null as unknown as $.Bytes, $.newError('cryptobyte: Builder is not full')]
292
+ }
293
+ return [bytesFromArray(this.result), null]
294
+ }
295
+
296
+ public BytesOrPanic(): $.Bytes {
297
+ const [bytes, err] = this.Bytes()
298
+ if (err != null) {
299
+ $.panic(new BuildError({ Err: err }))
300
+ }
301
+ return bytes
302
+ }
303
+
304
+ public AddUint8(v: number): void {
305
+ this.add(byte(v))
306
+ }
307
+
308
+ public AddUint16(v: number): void {
309
+ this.add(byte(v >> 8), byte(v))
310
+ }
311
+
312
+ public AddUint24(v: number): void {
313
+ this.add(byte(v >> 16), byte(v >> 8), byte(v))
314
+ }
315
+
316
+ public AddUint32(v: number): void {
317
+ this.add(byte(v / 0x1000000), byte(v >> 16), byte(v >> 8), byte(v))
318
+ }
319
+
320
+ public AddUint48(v: number): void {
321
+ this.add(
322
+ byte(Math.floor(v / 0x10000000000)),
323
+ byte(Math.floor(v / 0x100000000)),
324
+ byte(v >> 24),
325
+ byte(v >> 16),
326
+ byte(v >> 8),
327
+ byte(v),
328
+ )
329
+ }
330
+
331
+ public AddUint64(v: number): void {
332
+ let value = toUint64BigInt(v)
333
+ const out = new Array<number>(8)
334
+ for (let i = 7; i >= 0; i--) {
335
+ out[i] = byte(value)
336
+ value >>= 8n
337
+ }
338
+ this.add(...out)
339
+ }
340
+
341
+ public AddBytes(v: $.Bytes): void {
342
+ this.add(...bytesArray(v))
343
+ }
344
+
345
+ public AddUint8LengthPrefixed(f: BuilderContinuation): void {
346
+ this.addLengthPrefixed(1, false, f)
347
+ }
348
+
349
+ public AddUint16LengthPrefixed(f: BuilderContinuation): void {
350
+ this.addLengthPrefixed(2, false, f)
351
+ }
352
+
353
+ public AddUint24LengthPrefixed(f: BuilderContinuation): void {
354
+ this.addLengthPrefixed(3, false, f)
355
+ }
356
+
357
+ public AddUint32LengthPrefixed(f: BuilderContinuation): void {
358
+ this.addLengthPrefixed(4, false, f)
359
+ }
360
+
361
+ public AddValue(v: MarshalingValue | null): void {
362
+ if (v == null) {
363
+ this.SetError($.newError('cryptobyte: nil MarshalingValue'))
364
+ return
365
+ }
366
+ this.SetError(v.Marshal(this))
367
+ }
368
+
369
+ public Unwrite(n: number): void {
370
+ this.flushChild()
371
+ if (this.err != null) {
372
+ return
373
+ }
374
+ if (n < 0 || n > this.result.length) {
375
+ this.SetError($.newError('cryptobyte: invalid Unwrite'))
376
+ return
377
+ }
378
+ this.result.length -= n
379
+ }
380
+
381
+ public AddASN1Int64(v: number): void {
382
+ this.AddASN1Int64WithTag(v, asn1.INTEGER)
383
+ }
384
+
385
+ public AddASN1Int64WithTag(v: number, tag: asn1.Tag): void {
386
+ this.addASN1Signed(BigInt(Math.trunc(v)), tag)
387
+ }
388
+
389
+ public AddASN1Enum(v: number): void {
390
+ this.addASN1Signed(BigInt(Math.trunc(v)), asn1.ENUM)
391
+ }
392
+
393
+ public AddASN1Uint64(v: number): void {
394
+ this.AddASN1(asn1.INTEGER, (child) => {
395
+ child!.add(...encodeASN1Unsigned(toUint64BigInt(v)))
396
+ })
397
+ }
398
+
399
+ public AddASN1BigInt(n: unknown): void {
400
+ const value = bigIntValue(n)
401
+ this.AddASN1(asn1.INTEGER, (child) => {
402
+ child!.add(...encodeASN1Signed(value))
403
+ })
404
+ }
405
+
406
+ public AddASN1OctetString(bytes: $.Bytes): void {
407
+ this.AddASN1(asn1.OCTET_STRING, (child) => {
408
+ child!.AddBytes(bytes)
409
+ })
410
+ }
411
+
412
+ public AddASN1GeneralizedTime(t: time.Time | $.VarRef<time.Time> | null): void {
413
+ const value = $.pointerValue(t)
414
+ this.AddASN1(asn1.GeneralizedTime, (child) => {
415
+ child!.AddBytes(bytesFromString(value.Format('20060102150405Z0700')))
416
+ })
417
+ }
418
+
419
+ public AddASN1UTCTime(t: time.Time | $.VarRef<time.Time> | null): void {
420
+ const value = $.pointerValue(t)
421
+ this.AddASN1(asn1.UTCTime, (child) => {
422
+ child!.AddBytes(bytesFromString(value.Format('060102150405Z0700')))
423
+ })
424
+ }
425
+
426
+ public AddASN1BitString(bitString: unknown): void {
427
+ const value = pointerValueOrBox(bitString) as {
428
+ Bytes?: $.Bytes
429
+ BitLength?: number
430
+ } | null
431
+ if (value == null) {
432
+ this.SetError($.newError('cryptobyte: nil BitString'))
433
+ return
434
+ }
435
+ const bytes = value.Bytes ?? null
436
+ const bitLength = Math.trunc(value.BitLength ?? 0)
437
+ const paddingBits = (8 - (bitLength % 8)) % 8
438
+ if (
439
+ (bytes == null && bitLength !== 0) ||
440
+ $.len(bytes) * 8 - paddingBits !== bitLength
441
+ ) {
442
+ this.SetError($.newError('cryptobyte: invalid BitString'))
443
+ return
444
+ }
445
+ this.AddASN1(asn1.BIT_STRING, (child) => {
446
+ child!.AddUint8(paddingBits)
447
+ child!.AddBytes(bytes ?? new Uint8Array(0))
448
+ })
449
+ }
450
+
451
+ public AddASN1ObjectIdentifier(oid: $.Slice<number> | null): void {
452
+ if (oid == null || $.len(oid) < 2) {
453
+ this.SetError($.newError('cryptobyte: invalid OID'))
454
+ return
455
+ }
456
+ const first = Number((oid as any)[0])
457
+ const second = Number((oid as any)[1])
458
+ if (first > 2 || second >= 40 && first < 2) {
459
+ this.SetError($.newError('cryptobyte: invalid OID'))
460
+ return
461
+ }
462
+ this.AddASN1(asn1.OBJECT_IDENTIFIER, (child) => {
463
+ child!.addBase128Int(first * 40 + second)
464
+ for (let i = 2; i < $.len(oid); i++) {
465
+ child!.addBase128Int(Number((oid as any)[i]))
466
+ }
467
+ })
468
+ }
469
+
470
+ public AddASN1Boolean(v: boolean): void {
471
+ this.AddASN1(asn1.BOOLEAN, (child) => {
472
+ child!.AddUint8(v ? 0xff : 0)
473
+ })
474
+ }
475
+
476
+ public AddASN1NULL(): void {
477
+ this.add(asn1.NULL, 0)
478
+ }
479
+
480
+ public MarshalASN1(_v: unknown): void {
481
+ this.SetError(
482
+ $.newError('cryptobyte: MarshalASN1 is not supported in the js build'),
483
+ )
484
+ }
485
+
486
+ public AddASN1(tag: asn1.Tag, f: BuilderContinuation): void {
487
+ this.add(byte(tag))
488
+ this.addLengthPrefixed(1, true, f)
489
+ }
490
+
491
+ private addASN1Signed(v: bigint, tag: asn1.Tag): void {
492
+ this.AddASN1(tag, (child) => {
493
+ child!.add(...encodeASN1Signed(v))
494
+ })
495
+ }
496
+
497
+ private addBase128Int(v: number): void {
498
+ if (v < 0) {
499
+ this.SetError($.newError('cryptobyte: negative OID component'))
500
+ return
501
+ }
502
+ const out = [byte(v)]
503
+ v = Math.floor(v / 128)
504
+ while (v > 0) {
505
+ out.unshift(byte(v) | 0x80)
506
+ v = Math.floor(v / 128)
507
+ }
508
+ this.add(...out)
509
+ }
510
+
511
+ private addLengthPrefixed(
512
+ lenLen: number,
513
+ isASN1: boolean,
514
+ f: BuilderContinuation,
515
+ ): void {
516
+ this.flushChild()
517
+ if (this.err != null) {
518
+ return
519
+ }
520
+ this.offset = this.result.length
521
+ this.pendingLenLen = lenLen
522
+ this.pendingIsASN1 = isASN1
523
+ this.add(...new Array<number>(lenLen).fill(0))
524
+ const child = new Builder({
525
+ err: this.err,
526
+ resultArray: this.result,
527
+ fixedSize: this.fixedSize,
528
+ capacityLimit: this.capacityLimit,
529
+ })
530
+ this.child = child
531
+ try {
532
+ f?.(child)
533
+ } catch (err) {
534
+ const value = $.panicValue(err)
535
+ if (value instanceof BuildError) {
536
+ this.SetError(value.Err)
537
+ } else {
538
+ throw err
539
+ }
540
+ }
541
+ if (this.child === child) {
542
+ this.flushChild()
543
+ }
544
+ }
545
+
546
+ private flushChild(): void {
547
+ if (this.child == null) {
548
+ return
549
+ }
550
+ if (this.err == null && this.child.err != null) {
551
+ this.err = this.child.err
552
+ }
553
+ const offset = this.offset
554
+ const lenLen = this.pendingLenLen
555
+ const childStart = offset + lenLen
556
+ const length = this.result.length - childStart
557
+ if (this.err == null) {
558
+ if (this.pendingIsASN1) {
559
+ this.flushASN1Length(offset, length)
560
+ } else {
561
+ const max = 1n << BigInt(lenLen * 8)
562
+ if (BigInt(length) >= max) {
563
+ this.SetError($.newError('cryptobyte: length prefix overflow'))
564
+ } else {
565
+ for (let i = lenLen - 1, value = length; i >= 0; i--) {
566
+ this.result[offset + i] = byte(value)
567
+ value = Math.floor(value / 256)
568
+ }
569
+ }
570
+ }
571
+ }
572
+ this.child = null
573
+ }
574
+
575
+ private flushASN1Length(offset: number, length: number): void {
576
+ if (length <= 127) {
577
+ this.result[offset] = length
578
+ return
579
+ }
580
+ const encoded = encodeASN1Length(length)
581
+ const extra = encoded.length - 1
582
+ this.result.push(...new Array<number>(extra).fill(0))
583
+ for (let i = this.result.length - extra - 1; i > offset; i--) {
584
+ this.result[i + extra] = this.result[i]
585
+ }
586
+ for (let i = 0; i < encoded.length; i++) {
587
+ this.result[offset + i] = encoded[i]
588
+ }
589
+ }
590
+
591
+ private add(...bytes: number[]): void {
592
+ this.flushChild()
593
+ if (this.err != null) {
594
+ return
595
+ }
596
+ if (this.fixedSize && this.result.length + bytes.length > this.capacityLimit) {
597
+ this.SetError($.newError('cryptobyte: Builder is exceeding its fixed-size buffer'))
598
+ return
599
+ }
600
+ this.result.push(...bytes.map(byte))
601
+ }
602
+ }
603
+
604
+ export function NewBuilder(buffer?: $.Bytes | null): Builder {
605
+ return new Builder({ result: buffer ?? new Uint8Array(0), fixedSize: false })
606
+ }
607
+
608
+ export function NewFixedBuilder(buffer: $.Bytes): Builder {
609
+ return new Builder({
610
+ result: new Uint8Array(0),
611
+ fixedSize: true,
612
+ capacityLimit: $.cap(buffer),
613
+ })
614
+ }
615
+
616
+ function encodeASN1Length(length: number): number[] {
617
+ if (length <= 127) {
618
+ return [length]
619
+ }
620
+ const out: number[] = []
621
+ let value = length
622
+ while (value > 0) {
623
+ out.unshift(byte(value))
624
+ value = Math.floor(value / 256)
625
+ }
626
+ return [0x80 | out.length, ...out]
627
+ }
628
+
629
+ function encodeASN1Unsigned(value: bigint): number[] {
630
+ if (value < 0n || value > maxUint64) {
631
+ return []
632
+ }
633
+ const out = unsignedBytes(value)
634
+ if (out.length === 0) {
635
+ return [0]
636
+ }
637
+ if ((out[0] & 0x80) !== 0) {
638
+ out.unshift(0)
639
+ }
640
+ return out
641
+ }
642
+
643
+ function encodeASN1Signed(value: bigint): number[] {
644
+ if (value >= 0n) {
645
+ const out = unsignedBytes(value)
646
+ if (out.length === 0) {
647
+ return [0]
648
+ }
649
+ if ((out[0] & 0x80) !== 0) {
650
+ out.unshift(0)
651
+ }
652
+ return out
653
+ }
654
+ let byteLen = 1
655
+ while (value < -(1n << BigInt(byteLen * 8 - 1))) {
656
+ byteLen++
657
+ }
658
+ const mod = 1n << BigInt(byteLen * 8)
659
+ return fixedUnsignedBytes(mod + value, byteLen)
660
+ }
661
+
662
+ function unsignedBytes(value: bigint): number[] {
663
+ if (value === 0n) {
664
+ return []
665
+ }
666
+ const out: number[] = []
667
+ while (value > 0n) {
668
+ out.unshift(byte(value))
669
+ value >>= 8n
670
+ }
671
+ return out
672
+ }
673
+
674
+ function fixedUnsignedBytes(value: bigint, byteLen: number): number[] {
675
+ const out = new Array<number>(byteLen)
676
+ for (let i = byteLen - 1; i >= 0; i--) {
677
+ out[i] = byte(value)
678
+ value >>= 8n
679
+ }
680
+ return out
681
+ }
682
+
683
+ function toUint64BigInt(value: number | bigint): bigint {
684
+ if (typeof value === 'bigint') {
685
+ return BigInt.asUintN(64, value)
686
+ }
687
+ if (Number.isSafeInteger(value) && value >= 0) {
688
+ return BigInt(value)
689
+ }
690
+ return BigInt.asUintN(64, BigInt(Math.trunc(value)))
691
+ }
692
+
693
+ function signedBigInt(bytes: $.Bytes): bigint {
694
+ const arr = bytesArray(bytes)
695
+ let value = 0n
696
+ for (const b of arr) {
697
+ value = (value << 8n) | BigInt(b)
698
+ }
699
+ if (arr.length > 0 && (arr[0] & 0x80) !== 0) {
700
+ value -= 1n << BigInt(arr.length * 8)
701
+ }
702
+ return value
703
+ }
704
+
705
+ function unsignedBigInt(bytes: $.Bytes): bigint {
706
+ let value = 0n
707
+ for (const b of bytesArray(bytes)) {
708
+ value = (value << 8n) | BigInt(b)
709
+ }
710
+ return value
711
+ }
712
+
713
+ function checkASN1Integer(bytes: $.Bytes): boolean {
714
+ const arr = bytesArray(bytes)
715
+ if (arr.length === 0) {
716
+ return false
717
+ }
718
+ if (arr.length === 1) {
719
+ return true
720
+ }
721
+ if (arr[0] === 0 && (arr[1] & 0x80) === 0) {
722
+ return false
723
+ }
724
+ if (arr[0] === 0xff && (arr[1] & 0x80) === 0x80) {
725
+ return false
726
+ }
727
+ return true
728
+ }
729
+
730
+ type WriteTarget = {
731
+ typeName: string
732
+ ref: $.VarRef<unknown> | null
733
+ value: unknown
734
+ }
735
+
736
+ function boxedTypeName(value: unknown): string {
737
+ if (value !== null && typeof value === 'object' && '__goType' in value) {
738
+ return globalThis.String((value as { __goType?: unknown }).__goType ?? '')
739
+ }
740
+ return ''
741
+ }
742
+
743
+ function boxedValue(value: unknown): unknown {
744
+ if (value !== null && typeof value === 'object' && '__goValue' in value) {
745
+ return (value as { __goValue: unknown }).__goValue
746
+ }
747
+ return value
748
+ }
749
+
750
+ function writeTarget(out: unknown): WriteTarget {
751
+ const typeName = boxedTypeName(out)
752
+ const value = boxedValue(out)
753
+ if ($.isVarRef(value)) {
754
+ return { typeName, ref: value as $.VarRef<unknown>, value: value.value }
755
+ }
756
+ if ($.isVarRef(out)) {
757
+ return { typeName, ref: out as $.VarRef<unknown>, value: out.value }
758
+ }
759
+ return { typeName, ref: null, value }
760
+ }
761
+
762
+ function pointerValueOrBox(value: unknown): unknown {
763
+ const raw = boxedValue(value)
764
+ if ($.isVarRef(raw)) {
765
+ return raw.value
766
+ }
767
+ return raw
768
+ }
769
+
770
+ function isBigIntType(target: WriteTarget): boolean {
771
+ const typeName = target.typeName.replace(/^\*/, '')
772
+ const value = pointerValueOrBox(target.value)
773
+ return (
774
+ typeName === 'big.Int' ||
775
+ typeName === 'math/big.Int' ||
776
+ (value !== null &&
777
+ typeof value === 'object' &&
778
+ typeof (value as { SetBytes?: unknown }).SetBytes === 'function' &&
779
+ typeof (value as { Sign?: unknown }).Sign === 'function')
780
+ )
781
+ }
782
+
783
+ function integerKind(typeName: string): string {
784
+ return typeName.replace(/^\*/, '')
785
+ }
786
+
787
+ function writeInteger(target: WriteTarget, value: bigint): void {
788
+ const kind = integerKind(target.typeName)
789
+ if (isBigIntType(target)) {
790
+ setBigIntObject(pointerValueOrBox(target.value), value)
791
+ return
792
+ }
793
+ if (target.ref == null) {
794
+ $.panic('out does not point to an integer type')
795
+ }
796
+ switch (kind) {
797
+ case '':
798
+ case 'int':
799
+ case 'int64':
800
+ if (value < minInt64 || value > maxInt64) {
801
+ throw $.newError('cryptobyte: integer overflow')
802
+ }
803
+ target.ref!.value = $.int(value, 64)
804
+ return
805
+ case 'int8':
806
+ if (value < -128n || value > 127n) {
807
+ throw $.newError('cryptobyte: integer overflow')
808
+ }
809
+ target.ref!.value = $.int(value, 8)
810
+ return
811
+ case 'int16':
812
+ if (value < -32768n || value > 32767n) {
813
+ throw $.newError('cryptobyte: integer overflow')
814
+ }
815
+ target.ref!.value = $.int(value, 16)
816
+ return
817
+ case 'int32':
818
+ if (value < -2147483648n || value > 2147483647n) {
819
+ throw $.newError('cryptobyte: integer overflow')
820
+ }
821
+ target.ref!.value = $.int(value, 32)
822
+ return
823
+ case 'uint':
824
+ case 'uint64':
825
+ case 'uintptr':
826
+ if (value < 0n || value > maxUint64) {
827
+ throw $.newError('cryptobyte: integer overflow')
828
+ }
829
+ target.ref!.value = $.uint(value, 64)
830
+ return
831
+ case 'uint8':
832
+ case 'byte':
833
+ if (value < 0n || value > 255n) {
834
+ throw $.newError('cryptobyte: integer overflow')
835
+ }
836
+ target.ref!.value = $.uint(value, 8)
837
+ return
838
+ case 'uint16':
839
+ if (value < 0n || value > 65535n) {
840
+ throw $.newError('cryptobyte: integer overflow')
841
+ }
842
+ target.ref!.value = $.uint(value, 16)
843
+ return
844
+ case 'uint32':
845
+ if (value < 0n || value > 4294967295n) {
846
+ throw $.newError('cryptobyte: integer overflow')
847
+ }
848
+ target.ref!.value = $.uint(value, 32)
849
+ return
850
+ default:
851
+ throw $.newError(
852
+ 'cryptobyte: ReadASN1Integer of a named integer type is not supported in the js build',
853
+ )
854
+ }
855
+ }
856
+
857
+ function integerDefaultValue(defaultValue: unknown): bigint {
858
+ const raw = boxedValue(defaultValue)
859
+ if (typeof raw === 'bigint') {
860
+ return raw
861
+ }
862
+ if (typeof raw === 'number' && Number.isFinite(raw)) {
863
+ return BigInt(Math.trunc(raw))
864
+ }
865
+ if (raw !== null && typeof raw === 'object') {
866
+ return bigIntValue(raw)
867
+ }
868
+ throw $.newError(
869
+ 'cryptobyte: ReadOptionalASN1Integer default of a named integer type is not supported in the js build',
870
+ )
871
+ }
872
+
873
+ function setBigIntObject(target: unknown, value: bigint): void {
874
+ if (target == null || typeof target !== 'object') {
875
+ $.panic('out does not point to an integer type')
876
+ }
877
+ const big = target as {
878
+ SetBytes?: (bytes: $.Bytes) => unknown
879
+ SetInt64?: (value: number) => unknown
880
+ Neg?: (value: unknown) => unknown
881
+ value?: bigint
882
+ }
883
+ if ('value' in big) {
884
+ big.value = value
885
+ return
886
+ }
887
+ const magnitude = bytesFromArray(unsignedBytes(value < 0n ? -value : value))
888
+ if (typeof big.SetBytes === 'function') {
889
+ big.SetBytes(magnitude)
890
+ if (value < 0n) {
891
+ if (typeof big.Neg !== 'function') {
892
+ throw $.newError(
893
+ 'cryptobyte: big.Int negative assignment is not supported in the js build',
894
+ )
895
+ }
896
+ big.Neg(big)
897
+ }
898
+ return
899
+ }
900
+ if (typeof big.SetInt64 === 'function') {
901
+ big.SetInt64(Number(value))
902
+ return
903
+ }
904
+ throw $.newError('cryptobyte: unsupported big.Int representation')
905
+ }
906
+
907
+ function bigIntValue(value: unknown): bigint {
908
+ const raw = pointerValueOrBox(value)
909
+ if (typeof raw === 'bigint') {
910
+ return raw
911
+ }
912
+ if (typeof raw === 'number') {
913
+ return BigInt(Math.trunc(raw))
914
+ }
915
+ if (raw !== null && typeof raw === 'object') {
916
+ const big = raw as {
917
+ value?: bigint | number
918
+ Sign?: () => number
919
+ Bytes?: () => $.Bytes
920
+ String?: () => string
921
+ }
922
+ if (typeof big.value === 'bigint') {
923
+ return big.value
924
+ }
925
+ if (typeof big.value === 'number') {
926
+ return BigInt(Math.trunc(big.value))
927
+ }
928
+ if (typeof big.Sign === 'function' && typeof big.Bytes === 'function') {
929
+ const sign = big.Sign()
930
+ const mag = unsignedBigInt(big.Bytes())
931
+ return sign < 0 ? -mag : mag
932
+ }
933
+ if (typeof big.String === 'function') {
934
+ return BigInt(big.String())
935
+ }
936
+ }
937
+ throw $.newError('cryptobyte: unsupported big.Int representation')
938
+ }
939
+
940
+ function readASN1Bytes(
941
+ s: $.VarRef<String> | null,
942
+ tag: asn1.Tag,
943
+ ): $.Bytes | null {
944
+ const bytes = $.varRef<String>(new Uint8Array(0))
945
+ if (!String_ReadASN1(s, bytes, tag)) {
946
+ return null
947
+ }
948
+ return bytes.value
949
+ }
950
+
951
+ function readASN1SignedInteger(
952
+ s: $.VarRef<String> | null,
953
+ tag: asn1.Tag,
954
+ ): bigint | null {
955
+ const bytes = readASN1Bytes(s, tag)
956
+ if (bytes == null || !checkASN1Integer(bytes)) {
957
+ return null
958
+ }
959
+ return signedBigInt(bytes)
960
+ }
961
+
962
+ export function String_ReadASN1Boolean(
963
+ s: $.VarRef<String> | null,
964
+ out: $.VarRef<boolean> | null,
965
+ ): boolean {
966
+ const bytes = readASN1Bytes(s, asn1.BOOLEAN)
967
+ const arr = bytesArray(bytes)
968
+ if (bytes == null || arr.length !== 1 || (arr[0] !== 0 && arr[0] !== 0xff)) {
969
+ return false
970
+ }
971
+ writeRef(out, arr[0] === 0xff)
972
+ return true
973
+ }
974
+
975
+ export function String_ReadASN1Integer(
976
+ s: $.VarRef<String> | null,
977
+ out: unknown,
978
+ ): boolean {
979
+ const target = writeTarget(out)
980
+ const bytes = readASN1Bytes(s, asn1.INTEGER)
981
+ if (bytes == null || !checkASN1Integer(bytes)) {
982
+ return false
983
+ }
984
+ const value = signedBigInt(bytes)
985
+ writeInteger(target, value)
986
+ return true
987
+ }
988
+
989
+ export function String_ReadASN1Int64WithTag(
990
+ s: $.VarRef<String> | null,
991
+ out: $.VarRef<number> | null,
992
+ tag: asn1.Tag,
993
+ ): boolean {
994
+ const value = readASN1SignedInteger(s, tag)
995
+ if (value == null || value < minInt64 || value > maxInt64) {
996
+ return false
997
+ }
998
+ writeRef(out, $.int(value, 64))
999
+ return true
1000
+ }
1001
+
1002
+ export function String_ReadASN1Enum(
1003
+ s: $.VarRef<String> | null,
1004
+ out: $.VarRef<number> | null,
1005
+ ): boolean {
1006
+ const value = readASN1SignedInteger(s, asn1.ENUM)
1007
+ if (value == null || value < minInt64 || value > maxInt64) {
1008
+ return false
1009
+ }
1010
+ writeRef(out, $.int(value, 64))
1011
+ return true
1012
+ }
1013
+
1014
+ export function String_ReadASN1ObjectIdentifier(
1015
+ s: $.VarRef<String> | null,
1016
+ out: $.VarRef<$.Slice<number> | null> | null,
1017
+ ): boolean {
1018
+ const bytes = readASN1Bytes(s, asn1.OBJECT_IDENTIFIER)
1019
+ const arr = bytesArray(bytes)
1020
+ if (bytes == null || arr.length === 0) {
1021
+ return false
1022
+ }
1023
+ const oid: number[] = []
1024
+ let offset = 0
1025
+ const firstRead = readBase128Int(arr, offset)
1026
+ if (firstRead == null) {
1027
+ return false
1028
+ }
1029
+ offset = firstRead.next
1030
+ if (firstRead.value < 80) {
1031
+ oid.push(Math.floor(firstRead.value / 40), firstRead.value % 40)
1032
+ } else {
1033
+ oid.push(2, firstRead.value - 80)
1034
+ }
1035
+ while (offset < arr.length) {
1036
+ const part = readBase128Int(arr, offset)
1037
+ if (part == null) {
1038
+ return false
1039
+ }
1040
+ offset = part.next
1041
+ oid.push(part.value)
1042
+ }
1043
+ writeRef(out, $.arrayToSlice(oid))
1044
+ return true
1045
+ }
1046
+
1047
+ export function String_ReadASN1GeneralizedTime(
1048
+ s: $.VarRef<String> | null,
1049
+ out: $.VarRef<time.Time> | null,
1050
+ ): boolean {
1051
+ const bytes = readASN1Bytes(s, asn1.GeneralizedTime)
1052
+ if (bytes == null) {
1053
+ return false
1054
+ }
1055
+ const parsed = parseGeneralizedTime(bytesToAscii(bytes))
1056
+ if (parsed == null) {
1057
+ return false
1058
+ }
1059
+ writeRef(out, parsed)
1060
+ return true
1061
+ }
1062
+
1063
+ export function String_ReadASN1UTCTime(
1064
+ s: $.VarRef<String> | null,
1065
+ out: $.VarRef<time.Time> | null,
1066
+ ): boolean {
1067
+ const bytes = readASN1Bytes(s, asn1.UTCTime)
1068
+ if (bytes == null) {
1069
+ return false
1070
+ }
1071
+ const parsed = parseUTCTime(bytesToAscii(bytes))
1072
+ if (parsed == null) {
1073
+ return false
1074
+ }
1075
+ writeRef(out, parsed)
1076
+ return true
1077
+ }
1078
+
1079
+ export function String_ReadASN1BitString(
1080
+ s: $.VarRef<String> | null,
1081
+ out: unknown,
1082
+ ): boolean {
1083
+ const bytes = readASN1Bytes(s, asn1.BIT_STRING)
1084
+ const parsed = parseBitString(bytes)
1085
+ if (parsed == null) {
1086
+ return false
1087
+ }
1088
+ const target = pointerValueOrBox(out) as {
1089
+ Bytes?: $.Bytes
1090
+ BitLength?: number
1091
+ } | null
1092
+ if (target == null) {
1093
+ throw new Error(
1094
+ 'runtime error: invalid memory address or nil pointer dereference',
1095
+ )
1096
+ }
1097
+ target.Bytes = parsed.bytes
1098
+ target.BitLength = parsed.bitLength
1099
+ return true
1100
+ }
1101
+
1102
+ export function String_ReadASN1BitStringAsBytes(
1103
+ s: $.VarRef<String> | null,
1104
+ out: $.VarRef<$.Bytes> | null,
1105
+ paddingBits: $.VarRef<number> | null,
1106
+ ): boolean {
1107
+ const bytes = readASN1Bytes(s, asn1.BIT_STRING)
1108
+ const parsed = parseBitString(bytes)
1109
+ if (parsed == null) {
1110
+ return false
1111
+ }
1112
+ writeRef(out, parsed.bytes)
1113
+ writeRef(paddingBits, parsed.paddingBits)
1114
+ return true
1115
+ }
1116
+
1117
+ export function String_ReadASN1Bytes(
1118
+ s: $.VarRef<String> | null,
1119
+ out: $.VarRef<$.Bytes> | null,
1120
+ tag: asn1.Tag,
1121
+ ): boolean {
1122
+ return String_ReadASN1(s, out as $.VarRef<String> | null, tag)
1123
+ }
1124
+
1125
+ export function String_ReadASN1(
1126
+ s: $.VarRef<String> | null,
1127
+ out: $.VarRef<String> | null,
1128
+ tag: asn1.Tag,
1129
+ ): boolean {
1130
+ return readASN1(s, out, null, tag, true)
1131
+ }
1132
+
1133
+ export function String_ReadASN1Element(
1134
+ s: $.VarRef<String> | null,
1135
+ out: $.VarRef<String> | null,
1136
+ tag: asn1.Tag,
1137
+ ): boolean {
1138
+ return readASN1(s, out, null, tag, false)
1139
+ }
1140
+
1141
+ export function String_ReadAnyASN1(
1142
+ s: $.VarRef<String> | null,
1143
+ out: $.VarRef<String> | null,
1144
+ outTag: $.VarRef<asn1.Tag> | null,
1145
+ ): boolean {
1146
+ return readASN1(s, out, outTag, null, true)
1147
+ }
1148
+
1149
+ export function String_ReadAnyASN1Element(
1150
+ s: $.VarRef<String> | null,
1151
+ out: $.VarRef<String> | null,
1152
+ outTag: $.VarRef<asn1.Tag> | null,
1153
+ ): boolean {
1154
+ return readASN1(s, out, outTag, null, false)
1155
+ }
1156
+
1157
+ export function String_PeekASN1Tag(s: String, tag: asn1.Tag): boolean {
1158
+ const parsed = parseASN1(s)
1159
+ return parsed !== null && parsed.tag === tag
1160
+ }
1161
+
1162
+ export function String_SkipASN1(
1163
+ s: $.VarRef<String> | null,
1164
+ tag: asn1.Tag,
1165
+ ): boolean {
1166
+ const out = $.varRef<String>(new Uint8Array(0))
1167
+ return String_ReadASN1Element(s, out, tag)
1168
+ }
1169
+
1170
+ export function String_ReadOptionalASN1(
1171
+ s: $.VarRef<String> | null,
1172
+ out: $.VarRef<String> | null,
1173
+ tag: asn1.Tag,
1174
+ defaultValue: String,
1175
+ ): boolean {
1176
+ if (!String_PeekASN1Tag(stringValue(s), tag)) {
1177
+ writeRef(out, defaultValue)
1178
+ return true
1179
+ }
1180
+ return String_ReadASN1(s, out, tag)
1181
+ }
1182
+
1183
+ export function String_SkipOptionalASN1(
1184
+ s: $.VarRef<String> | null,
1185
+ tag: asn1.Tag,
1186
+ ): boolean {
1187
+ if (!String_PeekASN1Tag(stringValue(s), tag)) {
1188
+ return true
1189
+ }
1190
+ return String_SkipASN1(s, tag)
1191
+ }
1192
+
1193
+ export function String_ReadOptionalASN1Integer(
1194
+ s: $.VarRef<String> | null,
1195
+ out: unknown,
1196
+ tag: asn1.Tag,
1197
+ defaultValue: unknown,
1198
+ ): boolean {
1199
+ if (!String_PeekASN1Tag(stringValue(s), tag)) {
1200
+ writeInteger(writeTarget(out), integerDefaultValue(defaultValue))
1201
+ return true
1202
+ }
1203
+ return String_ReadASN1Integer(s, out)
1204
+ }
1205
+
1206
+ export function String_ReadOptionalASN1OctetString(
1207
+ s: $.VarRef<String> | null,
1208
+ out: $.VarRef<$.Bytes> | null,
1209
+ tag: asn1.Tag,
1210
+ defaultValue: $.Bytes,
1211
+ ): boolean {
1212
+ if (!String_PeekASN1Tag(stringValue(s), tag)) {
1213
+ writeRef(out, defaultValue)
1214
+ return true
1215
+ }
1216
+ return String_ReadASN1Bytes(s, out, tag)
1217
+ }
1218
+
1219
+ export function String_ReadOptionalASN1Boolean(
1220
+ s: $.VarRef<String> | null,
1221
+ out: $.VarRef<boolean> | null,
1222
+ tag: asn1.Tag,
1223
+ defaultValue: boolean,
1224
+ ): boolean {
1225
+ if (!String_PeekASN1Tag(stringValue(s), tag)) {
1226
+ writeRef(out, defaultValue)
1227
+ return true
1228
+ }
1229
+ return String_ReadASN1Boolean(s, out)
1230
+ }
1231
+
1232
+ type ParsedASN1 = {
1233
+ tag: asn1.Tag
1234
+ headerLen: number
1235
+ length: number
1236
+ totalLen: number
1237
+ }
1238
+
1239
+ function parseASN1(data: $.Bytes): ParsedASN1 | null {
1240
+ const arr = bytesArray(data)
1241
+ if (arr.length < 2 || (arr[0] & 0x1f) === 0x1f) {
1242
+ return null
1243
+ }
1244
+ const tag = arr[0]
1245
+ let headerLen = 2
1246
+ let length = arr[1]
1247
+ if ((length & 0x80) !== 0) {
1248
+ const lenLen = length & 0x7f
1249
+ if (lenLen === 0 || lenLen > 4 || arr.length < 2 + lenLen) {
1250
+ return null
1251
+ }
1252
+ if (arr[2] === 0) {
1253
+ return null
1254
+ }
1255
+ length = 0
1256
+ for (let i = 0; i < lenLen; i++) {
1257
+ length = length * 256 + arr[2 + i]
1258
+ }
1259
+ if (length < 128) {
1260
+ return null
1261
+ }
1262
+ headerLen += lenLen
1263
+ }
1264
+ const totalLen = headerLen + length
1265
+ if (arr.length < totalLen) {
1266
+ return null
1267
+ }
1268
+ return { tag, headerLen, length, totalLen }
1269
+ }
1270
+
1271
+ function readASN1(
1272
+ s: $.VarRef<String> | null,
1273
+ out: $.VarRef<String> | null,
1274
+ outTag: $.VarRef<asn1.Tag> | null,
1275
+ expectedTag: asn1.Tag | null,
1276
+ skipHeader: boolean,
1277
+ ): boolean {
1278
+ const data = stringValue(s)
1279
+ const parsed = parseASN1(data)
1280
+ if (parsed == null || (expectedTag !== null && parsed.tag !== expectedTag)) {
1281
+ return false
1282
+ }
1283
+ if (outTag != null) {
1284
+ outTag.value = parsed.tag
1285
+ }
1286
+ if (out != null) {
1287
+ out.value = skipHeader
1288
+ ? $.goSlice(data, parsed.headerLen, parsed.totalLen)
1289
+ : $.goSlice(data, 0, parsed.totalLen)
1290
+ }
1291
+ s!.value = $.goSlice(data, parsed.totalLen)
1292
+ return true
1293
+ }
1294
+
1295
+ function parseBitString(bytes: $.Bytes | null): {
1296
+ bytes: $.Bytes
1297
+ paddingBits: number
1298
+ bitLength: number
1299
+ } | null {
1300
+ const arr = bytesArray(bytes)
1301
+ if (bytes == null || arr.length === 0) {
1302
+ return null
1303
+ }
1304
+ const paddingBits = arr[0]
1305
+ if (paddingBits > 7 || (arr.length === 1 && paddingBits !== 0)) {
1306
+ return null
1307
+ }
1308
+ if (
1309
+ arr.length > 1 &&
1310
+ paddingBits > 0 &&
1311
+ (arr[arr.length - 1] & ((1 << paddingBits) - 1)) !== 0
1312
+ ) {
1313
+ return null
1314
+ }
1315
+ const content = bytesFromArray(arr.slice(1))
1316
+ return {
1317
+ bytes: content,
1318
+ paddingBits,
1319
+ bitLength: $.len(content) * 8 - paddingBits,
1320
+ }
1321
+ }
1322
+
1323
+ function readBase128Int(
1324
+ bytes: number[],
1325
+ offset: number,
1326
+ ): { value: number; next: number } | null {
1327
+ let ret = 0
1328
+ for (let i = offset; i < bytes.length; i++) {
1329
+ const b = bytes[i]
1330
+ if (ret === 0 && b === 0x80) {
1331
+ return null
1332
+ }
1333
+ ret = ret * 128 + (b & 0x7f)
1334
+ if (ret > Number.MAX_SAFE_INTEGER) {
1335
+ return null
1336
+ }
1337
+ if ((b & 0x80) === 0) {
1338
+ return { value: ret, next: i + 1 }
1339
+ }
1340
+ }
1341
+ return null
1342
+ }
1343
+
1344
+ function parseFixedDigits(value: string, offset: number, width: number): number | null {
1345
+ const text = value.slice(offset, offset + width)
1346
+ if (!new RegExp(`^[0-9]{${width}}$`).test(text)) {
1347
+ return null
1348
+ }
1349
+ return Number(text)
1350
+ }
1351
+
1352
+ function parseZone(value: string, offset: number): { offsetMinutes: number } | null {
1353
+ if (value[offset] === 'Z' && offset + 1 === value.length) {
1354
+ return { offsetMinutes: 0 }
1355
+ }
1356
+ const sign = value[offset]
1357
+ if ((sign !== '+' && sign !== '-') || offset + 5 !== value.length) {
1358
+ return null
1359
+ }
1360
+ const hour = parseFixedDigits(value, offset + 1, 2)
1361
+ const minute = parseFixedDigits(value, offset + 3, 2)
1362
+ if (hour == null || minute == null || hour > 23 || minute > 59) {
1363
+ return null
1364
+ }
1365
+ const offsetMinutes = hour * 60 + minute
1366
+ return { offsetMinutes: sign === '+' ? offsetMinutes : -offsetMinutes }
1367
+ }
1368
+
1369
+ function makeTime(
1370
+ year: number,
1371
+ month: number,
1372
+ day: number,
1373
+ hour: number,
1374
+ minute: number,
1375
+ second: number,
1376
+ offsetMinutes: number,
1377
+ ): time.Time {
1378
+ const millis =
1379
+ globalThis.Date.UTC(year, month - 1, day, hour, minute, second) -
1380
+ offsetMinutes * 60 * 1000
1381
+ return time.Unix(Math.floor(millis / 1000), 0)
1382
+ }
1383
+
1384
+ function parseGeneralizedTime(value: string): time.Time | null {
1385
+ if (value.length < 15) {
1386
+ return null
1387
+ }
1388
+ const year = parseFixedDigits(value, 0, 4)
1389
+ const month = parseFixedDigits(value, 4, 2)
1390
+ const day = parseFixedDigits(value, 6, 2)
1391
+ const hour = parseFixedDigits(value, 8, 2)
1392
+ const minute = parseFixedDigits(value, 10, 2)
1393
+ const second = parseFixedDigits(value, 12, 2)
1394
+ const zone = parseZone(value, 14)
1395
+ if (
1396
+ year == null ||
1397
+ month == null ||
1398
+ day == null ||
1399
+ hour == null ||
1400
+ minute == null ||
1401
+ second == null ||
1402
+ zone == null
1403
+ ) {
1404
+ return null
1405
+ }
1406
+ return makeTime(year, month, day, hour, minute, second, zone.offsetMinutes)
1407
+ }
1408
+
1409
+ function parseUTCTime(value: string): time.Time | null {
1410
+ if (value.length !== 11 && value.length !== 13 && value.length !== 15 && value.length !== 17) {
1411
+ return null
1412
+ }
1413
+ const yearPart = parseFixedDigits(value, 0, 2)
1414
+ const month = parseFixedDigits(value, 2, 2)
1415
+ const day = parseFixedDigits(value, 4, 2)
1416
+ const hour = parseFixedDigits(value, 6, 2)
1417
+ const minute = parseFixedDigits(value, 8, 2)
1418
+ let second = 0
1419
+ let zoneOffset = 10
1420
+ if (value.length === 13 || value.length === 17) {
1421
+ const parsedSecond = parseFixedDigits(value, 10, 2)
1422
+ if (parsedSecond == null) {
1423
+ return null
1424
+ }
1425
+ second = parsedSecond
1426
+ zoneOffset = 12
1427
+ }
1428
+ const zone = parseZone(value, zoneOffset)
1429
+ if (
1430
+ yearPart == null ||
1431
+ month == null ||
1432
+ day == null ||
1433
+ hour == null ||
1434
+ minute == null ||
1435
+ zone == null
1436
+ ) {
1437
+ return null
1438
+ }
1439
+ const year = yearPart >= 50 ? 1900 + yearPart : 2000 + yearPart
1440
+ return makeTime(year, month, day, hour, minute, second, zone.offsetMinutes)
1441
+ }