1 | const JSBI = require('jsbi');
|
2 | const { assert, format } = require('../util');
|
3 | const BaseCoder = require('./BaseCoder');
|
4 | const { UINT_BOUND, padBuffer } = require('./util');
|
5 |
|
6 | class IntegerCoder extends BaseCoder {
|
7 | static from({ type, name }) {
|
8 | const match = type.match(/^(int|uint)([0-9]*)$/);
|
9 | if (!match) {
|
10 | return undefined;
|
11 | }
|
12 |
|
13 | const [, label, bits] = match;
|
14 | return new this({
|
15 | name,
|
16 | type: label,
|
17 | signed: !label.startsWith('u'),
|
18 | bits: bits ? parseInt(bits, 10) : undefined,
|
19 | });
|
20 | }
|
21 |
|
22 | constructor({ name, type, signed = false, bits = 256 }) {
|
23 | assert(Number.isInteger(bits) && 0 < bits && bits <= 256 && (bits % 8 === 0), {
|
24 | message: 'invalid bits',
|
25 | expect: 'integer && 0<bits<=256 && bits%8==0',
|
26 | got: bits,
|
27 | coder: { name, type, signed },
|
28 | });
|
29 |
|
30 | super({ name });
|
31 | this.type = `${type}${bits}`;
|
32 | this.signed = signed;
|
33 | this.size = bits / 8;
|
34 | this.bound = JSBI.leftShift(JSBI.BigInt(1), JSBI.BigInt(bits - (this.signed ? 1 : 0)));
|
35 | }
|
36 |
|
37 | |
38 |
|
39 |
|
40 |
|
41 | encode(value) {
|
42 | let number = format.bigInt(value);
|
43 | let twosComplement = number;
|
44 |
|
45 | if (this.signed && JSBI.LT(number, JSBI.BigInt(0))) {
|
46 | twosComplement = JSBI.add(number, this.bound);
|
47 | number = JSBI.add(number, UINT_BOUND);
|
48 | }
|
49 |
|
50 | assert(JSBI.LE(JSBI.BigInt(0), twosComplement) && JSBI.LT(twosComplement, this.bound), {
|
51 | message: 'bound error',
|
52 | expect: `0<= && <${this.bound}`,
|
53 | got: twosComplement.toString(),
|
54 | coder: this,
|
55 | value,
|
56 | });
|
57 |
|
58 | return padBuffer(format.hex(number));
|
59 | }
|
60 |
|
61 | |
62 |
|
63 |
|
64 |
|
65 | decode(stream) {
|
66 | let value = format.bigInt(`0x${stream.read(this.size * 2)}`);
|
67 |
|
68 | if (this.signed && JSBI.GE(value, this.bound)) {
|
69 | const mask = JSBI.leftShift(JSBI.BigInt(1), JSBI.BigInt(this.size * 8));
|
70 | value = JSBI.subtract(value, mask);
|
71 | }
|
72 |
|
73 | return value;
|
74 | }
|
75 | }
|
76 |
|
77 | module.exports = IntegerCoder;
|