Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * This file implements converting a Base38 String into an array of bytes.
21 : *
22 : */
23 :
24 : #include "Base38Decode.h"
25 :
26 : namespace {
27 :
28 592 : static inline CHIP_ERROR decodeChar(char c, uint8_t & value)
29 : {
30 : static const int kBogus = 255;
31 : // map of base38 charater to numeric value
32 : // subtract 45 from the charater, then index into this array, if possible
33 592 : const uint8_t decodes[] = {
34 : 36, // '-', =45
35 : 37, // '.', =46
36 : kBogus, // '/', =47
37 : 0, // '0', =48
38 : 1, // '1', =49
39 : 2, // '2', =50
40 : 3, // '3', =51
41 : 4, // '4', =52
42 : 5, // '5', =53
43 : 6, // '6', =54
44 : 7, // '7', =55
45 : 8, // '8', =56
46 : 9, // '9', =57
47 : kBogus, // ':', =58
48 : kBogus, // ';', =59
49 : kBogus, // '<', =50
50 : kBogus, // '=', =61
51 : kBogus, // '>', =62
52 : kBogus, // '?', =63
53 : kBogus, // '@', =64
54 : 10, // 'A', =65
55 : 11, // 'B', =66
56 : 12, // 'C', =67
57 : 13, // 'D', =68
58 : 14, // 'E', =69
59 : 15, // 'F', =70
60 : 16, // 'G', =71
61 : 17, // 'H', =72
62 : 18, // 'I', =73
63 : 19, // 'J', =74
64 : 20, // 'K', =75
65 : 21, // 'L', =76
66 : 22, // 'M', =77
67 : 23, // 'N', =78
68 : 24, // 'O', =79
69 : 25, // 'P', =80
70 : 26, // 'Q', =81
71 : 27, // 'R', =82
72 : 28, // 'S', =83
73 : 29, // 'T', =84
74 : 30, // 'U', =85
75 : 31, // 'V', =86
76 : 32, // 'W', =87
77 : 33, // 'X', =88
78 : 34, // 'Y', =89
79 : 35, // 'Z', =90
80 : };
81 592 : if (c < '-' || c > 'Z')
82 : {
83 18 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
84 : }
85 574 : uint8_t v = decodes[c - '-'];
86 574 : if (v == kBogus)
87 : {
88 5 : return CHIP_ERROR_INVALID_INTEGER_VALUE;
89 : }
90 569 : value = v;
91 569 : return CHIP_NO_ERROR;
92 : }
93 :
94 : } // unnamed namespace
95 :
96 : namespace chip {
97 :
98 54 : CHIP_ERROR base38Decode(std::string base38, std::vector<uint8_t> & result)
99 : {
100 54 : result.clear();
101 :
102 54 : size_t base38CharactersNumber = base38.length();
103 54 : size_t decodedBase38Characters = 0;
104 169 : while (base38CharactersNumber > 0)
105 : {
106 : uint8_t base38CharactersInChunk;
107 : uint8_t bytesInDecodedChunk;
108 :
109 142 : if (base38CharactersNumber >= kBase38CharactersNeededInNBytesChunk[2])
110 : {
111 93 : base38CharactersInChunk = kBase38CharactersNeededInNBytesChunk[2];
112 93 : bytesInDecodedChunk = 3;
113 : }
114 49 : else if (base38CharactersNumber == kBase38CharactersNeededInNBytesChunk[1])
115 : {
116 18 : base38CharactersInChunk = kBase38CharactersNeededInNBytesChunk[1];
117 18 : bytesInDecodedChunk = 2;
118 : }
119 31 : else if (base38CharactersNumber == kBase38CharactersNeededInNBytesChunk[0])
120 : {
121 30 : base38CharactersInChunk = kBase38CharactersNeededInNBytesChunk[0];
122 30 : bytesInDecodedChunk = 1;
123 : }
124 : else
125 : {
126 1 : return CHIP_ERROR_INVALID_STRING_LENGTH;
127 : }
128 :
129 141 : uint32_t value = 0;
130 :
131 710 : for (size_t i = base38CharactersInChunk; i > 0; i--)
132 : {
133 592 : uint8_t v = 0;
134 592 : CHIP_ERROR err = decodeChar(base38[decodedBase38Characters + i - 1], v);
135 :
136 592 : if (err != CHIP_NO_ERROR)
137 : {
138 23 : return err;
139 : }
140 :
141 569 : value = value * kRadix + v;
142 : }
143 118 : decodedBase38Characters += base38CharactersInChunk;
144 118 : base38CharactersNumber -= base38CharactersInChunk;
145 :
146 439 : for (size_t i = 0; i < bytesInDecodedChunk; i++)
147 : {
148 321 : result.push_back(static_cast<uint8_t>(value));
149 321 : value >>= 8;
150 : }
151 :
152 118 : if (value > 0)
153 : {
154 : // encoded value is too big to represent a correct chunk of size 1, 2 or 3 bytes
155 3 : return CHIP_ERROR_INVALID_ARGUMENT;
156 : }
157 : }
158 27 : return CHIP_NO_ERROR;
159 : }
160 :
161 : } // namespace chip
|