blob: 357b9ee60d5a11f2e1c899a58bc9e8eeb7304426 [file] [log] [blame]
Max Bires44c78812020-04-10 09:38:23 -07001/*
2 * Copyright 2019 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "cppbor_parse.h"
18
Max Bires44c78812020-04-10 09:38:23 -070019#include <stack>
20
Bram Bonnéf04333a2020-10-20 16:40:52 +020021#ifndef __TRUSTY__
Shawn Willden6ad57322020-11-20 00:31:53 -070022#include <android-base/logging.h>
23#define LOG_TAG "CppBor"
Bram Bonnéf04333a2020-10-20 16:40:52 +020024#else
Shawn Willden6ad57322020-11-20 00:31:53 -070025#define CHECK(x) (void)(x)
Bram Bonnéf04333a2020-10-20 16:40:52 +020026#endif
Max Bires44c78812020-04-10 09:38:23 -070027
28namespace cppbor {
29
30namespace {
31
32std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
33 const std::string& type) {
Bram Bonnéf04333a2020-10-20 16:40:52 +020034 char buf[1024];
Shawn Willden0f9cd2d2020-11-20 00:35:10 -070035 snprintf(buf, sizeof(buf), "Need %zu byte(s) for %s, have %zu.", bytesNeeded, type.c_str(),
Shawn Willden6ad57322020-11-20 00:31:53 -070036 bytesAvail);
Bram Bonnéf04333a2020-10-20 16:40:52 +020037 return std::string(buf);
Max Bires44c78812020-04-10 09:38:23 -070038}
39
40template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
41std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
42 ParseClient* parseClient) {
43 if (pos + sizeof(T) > end) {
44 parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
45 return {false, 0, pos};
46 }
47
48 const uint8_t* intEnd = pos + sizeof(T);
49 T result = 0;
50 do {
51 result = static_cast<T>((result << 8) | *pos++);
52 } while (pos < intEnd);
53 return {true, result, pos};
54}
55
56std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
57 ParseClient* parseClient);
58
59std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
60 const uint8_t* hdrEnd,
61 ParseClient* parseClient) {
62 std::unique_ptr<Item> item = std::make_unique<Uint>(value);
63 return {hdrEnd,
64 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
65}
66
67std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
68 const uint8_t* hdrEnd,
69 ParseClient* parseClient) {
70 if (value > std::numeric_limits<int64_t>::max()) {
71 parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
72 return {hdrBegin, nullptr /* end parsing */};
73 }
74 std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<uint64_t>(value));
75 return {hdrEnd,
76 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
77}
78
79std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
80 const uint8_t* hdrEnd,
81 ParseClient* parseClient) {
82 std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
83 return {hdrEnd,
84 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
85}
86
87std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
88 ParseClient* parseClient) {
89 std::unique_ptr<Item> item = std::make_unique<Null>();
90 return {hdrEnd,
91 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
92}
93
94template <typename T>
95std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
96 const uint8_t* valueBegin, const uint8_t* end,
97 const std::string& errLabel,
98 ParseClient* parseClient) {
99 if (end - valueBegin < static_cast<ssize_t>(length)) {
100 parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
101 return {hdrBegin, nullptr /* end parsing */};
102 }
103
104 std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
105 return {valueBegin + length,
106 parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
107}
108
109class IncompleteItem {
110 public:
111 virtual ~IncompleteItem() {}
112 virtual void add(std::unique_ptr<Item> item) = 0;
113};
114
115class IncompleteArray : public Array, public IncompleteItem {
116 public:
117 IncompleteArray(size_t size) : mSize(size) {}
118
119 // We return the "complete" size, rather than the actual size.
120 size_t size() const override { return mSize; }
121
122 void add(std::unique_ptr<Item> item) override {
123 mEntries.reserve(mSize);
124 mEntries.push_back(std::move(item));
125 }
126
127 private:
128 size_t mSize;
129};
130
131class IncompleteMap : public Map, public IncompleteItem {
132 public:
133 IncompleteMap(size_t size) : mSize(size) {}
134
135 // We return the "complete" size, rather than the actual size.
136 size_t size() const override { return mSize; }
137
138 void add(std::unique_ptr<Item> item) override {
139 mEntries.reserve(mSize * 2);
140 mEntries.push_back(std::move(item));
141 }
142
143 private:
144 size_t mSize;
145};
146
147class IncompleteSemantic : public Semantic, public IncompleteItem {
148 public:
149 IncompleteSemantic(uint64_t value) : Semantic(value) {}
150
151 // We return the "complete" size, rather than the actual size.
152 size_t size() const override { return 1; }
153
154 void add(std::unique_ptr<Item> item) override {
155 mEntries.reserve(1);
156 mEntries.push_back(std::move(item));
157 }
158};
159
160std::tuple<const uint8_t*, ParseClient*> handleEntries(size_t entryCount, const uint8_t* hdrBegin,
161 const uint8_t* pos, const uint8_t* end,
162 const std::string& typeName,
163 ParseClient* parseClient) {
164 while (entryCount > 0) {
165 --entryCount;
166 if (pos == end) {
167 parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
168 return {hdrBegin, nullptr /* end parsing */};
169 }
170 std::tie(pos, parseClient) = parseRecursively(pos, end, parseClient);
171 if (!parseClient) return {hdrBegin, nullptr};
172 }
173 return {pos, parseClient};
174}
175
176std::tuple<const uint8_t*, ParseClient*> handleCompound(
177 std::unique_ptr<Item> item, uint64_t entryCount, const uint8_t* hdrBegin,
178 const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName,
179 ParseClient* parseClient) {
180 parseClient =
181 parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
182 if (!parseClient) return {hdrBegin, nullptr};
183
184 const uint8_t* pos;
185 std::tie(pos, parseClient) =
186 handleEntries(entryCount, hdrBegin, valueBegin, end, typeName, parseClient);
187 if (!parseClient) return {hdrBegin, nullptr};
188
189 return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
190}
191
192std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
193 ParseClient* parseClient) {
194 const uint8_t* pos = begin;
195
196 MajorType type = static_cast<MajorType>(*pos & 0xE0);
197 uint8_t tagInt = *pos & 0x1F;
198 ++pos;
199
200 bool success = true;
201 uint64_t addlData;
202 if (tagInt < ONE_BYTE_LENGTH || tagInt > EIGHT_BYTE_LENGTH) {
203 addlData = tagInt;
204 } else {
205 switch (tagInt) {
206 case ONE_BYTE_LENGTH:
207 std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
208 break;
209
210 case TWO_BYTE_LENGTH:
211 std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
212 break;
213
214 case FOUR_BYTE_LENGTH:
215 std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
216 break;
217
218 case EIGHT_BYTE_LENGTH:
219 std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
220 break;
221
222 default:
223 CHECK(false); // It's impossible to get here
224 break;
225 }
226 }
227
228 if (!success) return {begin, nullptr};
229
230 switch (type) {
231 case UINT:
232 return handleUint(addlData, begin, pos, parseClient);
233
234 case NINT:
235 return handleNint(addlData, begin, pos, parseClient);
236
237 case BSTR:
238 return handleString<Bstr>(addlData, begin, pos, end, "byte string", parseClient);
239
240 case TSTR:
241 return handleString<Tstr>(addlData, begin, pos, end, "text string", parseClient);
242
243 case ARRAY:
244 return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
245 end, "array", parseClient);
246
247 case MAP:
248 return handleCompound(std::make_unique<IncompleteMap>(addlData), addlData * 2, begin,
249 pos, end, "map", parseClient);
250
251 case SEMANTIC:
252 return handleCompound(std::make_unique<IncompleteSemantic>(addlData), 1, begin, pos,
253 end, "semantic", parseClient);
254
255 case SIMPLE:
256 switch (addlData) {
257 case TRUE:
258 case FALSE:
259 return handleBool(addlData, begin, pos, parseClient);
260 case NULL_V:
261 return handleNull(begin, pos, parseClient);
262 }
263 }
264 CHECK(false); // Impossible to get here.
265 return {};
266}
267
268class FullParseClient : public ParseClient {
269 public:
270 virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
271 const uint8_t* end) override {
272 if (mParentStack.empty() && !item->isCompound()) {
273 // This is the first and only item.
274 mTheItem = std::move(item);
275 mPosition = end;
276 return nullptr; // We're done.
277 }
278
279 if (item->isCompound()) {
280 // Starting a new compound data item, i.e. a new parent. Save it on the parent stack.
281 // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
282 // existence until the corresponding itemEnd() call.
Shawn Willden6ad57322020-11-20 00:31:53 -0700283#if __has_feature(cxx_rtti)
284 assert(dynamic_cast<CompoundItem*>(item.get()));
285#endif
Max Bires44c78812020-04-10 09:38:23 -0700286 mParentStack.push(static_cast<CompoundItem*>(item.get()));
287 return this;
288 } else {
289 appendToLastParent(std::move(item));
290 return this;
291 }
292 }
293
294 virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
295 const uint8_t* end) override {
296 CHECK(item->isCompound() && item.get() == mParentStack.top());
297 mParentStack.pop();
298
299 if (mParentStack.empty()) {
300 mTheItem = std::move(item);
301 mPosition = end;
302 return nullptr; // We're done
303 } else {
304 appendToLastParent(std::move(item));
305 return this;
306 }
307 }
308
309 virtual void error(const uint8_t* position, const std::string& errorMessage) override {
310 mPosition = position;
311 mErrorMessage = errorMessage;
312 }
313
314 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
315 std::string /* errMsg */>
316 parseResult() {
317 std::unique_ptr<Item> p = std::move(mTheItem);
318 return {std::move(p), mPosition, std::move(mErrorMessage)};
319 }
320
321 private:
322 void appendToLastParent(std::unique_ptr<Item> item) {
323 auto parent = mParentStack.top();
Shawn Willden6ad57322020-11-20 00:31:53 -0700324#if __has_feature(cxx_rtti)
325 assert(dynamic_cast<IncompleteItem*>(parent));
326#endif
Max Bires44c78812020-04-10 09:38:23 -0700327 if (parent->type() == ARRAY) {
328 static_cast<IncompleteArray*>(parent)->add(std::move(item));
329 } else if (parent->type() == MAP) {
330 static_cast<IncompleteMap*>(parent)->add(std::move(item));
331 } else if (parent->type() == SEMANTIC) {
332 static_cast<IncompleteSemantic*>(parent)->add(std::move(item));
333 } else {
334 CHECK(false); // Impossible to get here.
335 }
336 }
337
338 std::unique_ptr<Item> mTheItem;
339 std::stack<CompoundItem*> mParentStack;
340 const uint8_t* mPosition = nullptr;
341 std::string mErrorMessage;
342};
343
344} // anonymous namespace
345
346void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
347 parseRecursively(begin, end, parseClient);
348}
349
350std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
351 std::string /* errMsg */>
352parse(const uint8_t* begin, const uint8_t* end) {
353 FullParseClient parseClient;
354 parse(begin, end, &parseClient);
355 return parseClient.parseResult();
356}
357
358} // namespace cppbor