1 | import { BN } from '../bn/index.js';
|
2 | import { u8aToBn, u8aToU8a } from '../u8a/index.js';
|
3 | /**
|
4 | * @name compactFromU8a
|
5 | * @description Retrives the offset and encoded length from a compact-prefixed value
|
6 | * @example
|
7 | * <BR>
|
8 | *
|
9 | * ```javascript
|
10 | * import { compactFromU8a } from '@polkadot/util';
|
11 | *
|
12 | * const [offset, length] = compactFromU8a(new Uint8Array([254, 255, 3, 0]));
|
13 | *
|
14 | * console.log('value offset=', offset, 'length=', length); // 4, 0xffff
|
15 | * ```
|
16 | */
|
17 | export function compactFromU8a(input) {
|
18 | const u8a = u8aToU8a(input);
|
19 | // The u8a is manually converted here for 1, 2 & 4 lengths, it is 2x faster
|
20 | // than doing an additional call to u8aToBn (as with variable length)
|
21 | switch (u8a[0] & 0b11) {
|
22 | case 0b00:
|
23 | return [1, new BN(u8a[0] >>> 2)];
|
24 | case 0b01:
|
25 | return [2, new BN((u8a[0] + (u8a[1] << 8)) >>> 2)];
|
26 | case 0b10:
|
27 | // for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
28 | // 32-bit, in the case where the top-most bit is set this yields a negative value
|
29 | return [4, new BN((u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 16777216)) >>> 2)];
|
30 | // 0b11
|
31 | default: {
|
32 | // add 5 to shifted (4 for base length, 1 for this byte)
|
33 | const offset = (u8a[0] >>> 2) + 5;
|
34 | // we unroll the loop
|
35 | switch (offset) {
|
36 | // there still could be 4 bytes data, similar to 0b10 above (with offsets)
|
37 | case 5:
|
38 | // for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
39 | // 32-bit, in the case where the top-most bit is set this yields a negative value
|
40 | return [5, new BN(u8a[1] + (u8a[2] << 8) + (u8a[3] << 16) + (u8a[4] * 16777216))];
|
41 | case 6:
|
42 | return [6, new BN(u8a[1] + (u8a[2] << 8) + (u8a[3] << 16) + ((u8a[4] + (u8a[5] << 8)) * 16777216))];
|
43 | // 6 bytes data is the maximum, 48 bits (56 would overflow)
|
44 | case 7:
|
45 | return [7, new BN(u8a[1] + (u8a[2] << 8) + (u8a[3] << 16) + ((u8a[4] + (u8a[5] << 8) + (u8a[6] << 16)) * 16777216))];
|
46 | // for anything else, use the non-unrolled version
|
47 | default:
|
48 | return [offset, u8aToBn(u8a.subarray(1, offset))];
|
49 | }
|
50 | }
|
51 | }
|
52 | }
|
53 | /**
|
54 | * @name compactFromU8aLim
|
55 | * @description A limited version of [[compactFromU8a]], accepting only Uint8Array inputs for values <= 48 bits
|
56 | */
|
57 | export function compactFromU8aLim(u8a) {
|
58 | // The u8a is manually converted here for 1, 2 & 4 lengths, it is 2x faster
|
59 | // than doing an additional call to u8aToBn (as with variable length)
|
60 | switch (u8a[0] & 0b11) {
|
61 | case 0b00:
|
62 | return [1, u8a[0] >>> 2];
|
63 | case 0b01:
|
64 | return [2, (u8a[0] + (u8a[1] << 8)) >>> 2];
|
65 | case 0b10:
|
66 | // for the 3rd byte, we don't << 24 - since JS converts all bitwise operators to
|
67 | // 32-bit, in the case where the top-most bit is set this yields a negative value
|
68 | return [4, (u8a[0] + (u8a[1] << 8) + (u8a[2] << 16) + (u8a[3] * 16777216)) >>> 2];
|
69 | // 0b11
|
70 | default: {
|
71 | // add 5 to shifted (4 for base length, 1 for this byte)
|
72 | // we unroll the loop
|
73 | switch ((u8a[0] >>> 2) + 5) {
|
74 | // there still could be 4 bytes data, similar to 0b10 above (with offsets)
|
75 | case 5:
|
76 | return [5, u8a[1] + (u8a[2] << 8) + (u8a[3] << 16) + (u8a[4] * 16777216)];
|
77 | case 6:
|
78 | return [6, u8a[1] + (u8a[2] << 8) + (u8a[3] << 16) + ((u8a[4] + (u8a[5] << 8)) * 16777216)];
|
79 | // 6 bytes data is the maximum, 48 bits (56 would overflow)
|
80 | case 7:
|
81 | return [7, u8a[1] + (u8a[2] << 8) + (u8a[3] << 16) + ((u8a[4] + (u8a[5] << 8) + (u8a[6] << 16)) * 16777216)];
|
82 | // for anything else, we are above the actual MAX_SAFE_INTEGER - bail out
|
83 | default:
|
84 | throw new Error('Compact input is > Number.MAX_SAFE_INTEGER');
|
85 | }
|
86 | }
|
87 | }
|
88 | }
|