1
// Copyright © 2017-2020 Trust Wallet.
2
//
3
// This file is part of Trust. The full Trust copyright notice, including
4
// terms governing use, modification, and redistribution, is contained in the
5
// file LICENSE at the root of the source code distribution tree.
6

7
#include "BinaryCoding.h"
8

9
#include <cassert>
10

11
namespace TW {
12

13
using namespace std;
14

15 1
void encode64LE(uint64_t val, vector<uint8_t>& data) {
16 1
    data.push_back(static_cast<uint8_t>(val));
17 1
    data.push_back(static_cast<uint8_t>((val >> 8)));
18 1
    data.push_back(static_cast<uint8_t>((val >> 16)));
19 1
    data.push_back(static_cast<uint8_t>((val >> 24)));
20 1
    data.push_back(static_cast<uint8_t>((val >> 32)));
21 1
    data.push_back(static_cast<uint8_t>((val >> 40)));
22 1
    data.push_back(static_cast<uint8_t>((val >> 48)));
23 1
    data.push_back(static_cast<uint8_t>((val >> 56)));
24
}
25

26 1
uint64_t decode64LE(const uint8_t* _Nonnull src) {
27
    // clang-format off
28 1
    return static_cast<uint64_t>(src[0])
29 1
        | (static_cast<uint64_t>(src[1]) << 8)
30 1
        | (static_cast<uint64_t>(src[2]) << 16)
31 1
        | (static_cast<uint64_t>(src[3]) << 24)
32 1
        | (static_cast<uint64_t>(src[4]) << 32)
33 1
        | (static_cast<uint64_t>(src[5]) << 40)
34 1
        | (static_cast<uint64_t>(src[6]) << 48)
35 1
        | (static_cast<uint64_t>(src[7]) << 56);
36
    // clang-format on
37
}
38

39 1
uint8_t varIntSize(uint64_t value) {
40
    // The value is small enough to be represented by itself.
41 1
    if (value < 0xfd) {
42 1
        return 1;
43
    }
44

45
    // Discriminant 1 byte plus 2 bytes for the uint16.
46 1
    if (value <= UINT16_MAX) {
47 1
        return 1 + 2;
48
    }
49

50
    // Discriminant 1 byte plus 4 bytes for the uint32.
51 1
    if (value <= UINT32_MAX) {
52 1
        return 1 + 4;
53
    }
54

55
    // Discriminant 1 byte plus 8 bytes for the uint64.
56 1
    return 1 + 8;
57
}
58

59 1
uint8_t encodeVarInt(uint64_t size, vector<uint8_t>& data) {
60 1
    if (size < 0xfd) {
61 1
        data.push_back(static_cast<uint8_t>(size));
62 1
        return 1;
63
    }
64

65 1
    if (size <= UINT16_MAX) {
66 1
        data.push_back(0xfd);
67 1
        encode16LE((uint16_t)size, data);
68 1
        return 3;
69
    }
70

71 1
    if (size <= UINT32_MAX) {
72 1
        data.push_back(0xfe);
73 1
        encode32LE((uint32_t)size, data);
74 1
        return 5;
75
    }
76

77 1
    data.push_back(0xff);
78 1
    encode64LE((uint64_t)size, data);
79 1
    return 9;
80
}
81

82 1
tuple<bool, uint64_t> decodeVarInt(const Data& in, size_t& indexInOut) {
83 1
    if (in.size() < indexInOut + 1) {
84
        // too short
85 0
        return make_tuple(false, 0);
86
    }
87
    // extra bytes except first
88 1
    uint8_t size = 0;
89 1
    const auto firstByte = in[indexInOut];
90 1
    switch (firstByte) {
91 1
        case 0xfd: size = 2; break;
92 1
        case 0xfe: size = 4; break;
93 1
        case 0xff: size = 8; break;
94 1
        default: size = 0; break; // one-byte case is one byte, with not discriminator
95
    }
96 1
    ++indexInOut;
97 1
    assert(size == 0 || size == 2 || size == 4 || size == 8);
98 1
    if (in.size() < indexInOut + size) {
99
        // too short
100 1
        return make_tuple(false, 0);
101
    }
102

103 1
    uint64_t number = 0;
104 1
    switch (size) {
105
        default:
106 1
        case 0: number = firstByte; break;
107 1
        case 2: number = decode16LE(in.data() + indexInOut); break;
108 1
        case 4: number = decode32LE(in.data() + indexInOut); break;
109 1
        case 8: number = decode64LE(in.data() + indexInOut); break;
110
    }
111 1
    indexInOut += size;
112 1
    return make_tuple(true, number);
113
}
114

115 1
void encode64BE(uint64_t val, vector<uint8_t>& data) {
116 1
    data.push_back(static_cast<uint8_t>((val >> 56)));
117 1
    data.push_back(static_cast<uint8_t>((val >> 48)));
118 1
    data.push_back(static_cast<uint8_t>((val >> 40)));
119 1
    data.push_back(static_cast<uint8_t>((val >> 32)));
120 1
    data.push_back(static_cast<uint8_t>((val >> 24)));
121 1
    data.push_back(static_cast<uint8_t>((val >> 16)));
122 1
    data.push_back(static_cast<uint8_t>((val >> 8)));
123 1
    data.push_back(static_cast<uint8_t>(val));
124
}
125

126 0
uint64_t decode64BE(const uint8_t* _Nonnull src) {
127
    // clang-format off
128 0
    return static_cast<uint64_t>(src[7])
129 0
        | (static_cast<uint64_t>(src[6]) << 8)
130 0
        | (static_cast<uint64_t>(src[5]) << 16)
131 0
        | (static_cast<uint64_t>(src[4]) << 24)
132 0
        | (static_cast<uint64_t>(src[3]) << 32)
133 0
        | (static_cast<uint64_t>(src[2]) << 40)
134 0
        | (static_cast<uint64_t>(src[1]) << 48)
135 0
        | (static_cast<uint64_t>(src[0]) << 56);
136
    // clang-format on
137
}
138

139 1
void encodeString(const string& str, vector<uint8_t>& data) {
140 1
    size_t size = str.size();
141 1
    encodeVarInt(size, data);
142 1
    data.insert(data.end(), str.data(), str.data() + size);
143
}
144

145
/// Decodes an ASCII string prefixed by its length (varInt) 
146 1
tuple<bool, string>  decodeString(const Data& in, size_t& indexInOut) {
147 1
    const auto lenTup = decodeVarInt(in, indexInOut);
148 1
    if (!get<0>(lenTup)) { return make_tuple(false, ""); }
149 1
    const auto len = get<1>(lenTup);
150
    // read bytes into string
151 1
    if (in.size() < indexInOut + len) { return make_tuple(false, ""); }
152 1
    string result(in.data() + indexInOut, in.data() + indexInOut + len);
153 1
    indexInOut += len;
154 1
    return make_tuple(true, result);
155
}
156

157
} // namespace TW

Read our documentation on viewing source code .

Loading