UNPKG

4.18 kBJavaScriptView Raw
1import { BN } from '../bn/index.js';
2import { 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 */
17export 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 */
57export 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}