1 /*
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
19 #include <algorithm>
20 #include <cstddef>
21 #include <cstdint>
22 #include <cstring>
23 #include <memory>
24 #include <optional>
25 #include <sstream>
26 #include <stack>
27 #include <tuple>
28 #include <type_traits>
29
30 #include "cppbor.h"
31
32 #ifndef __TRUSTY__
33 #include <android-base/logging.h>
34 #define LOG_TAG "CppBor"
35 #else
36 #define CHECK(x) (void)(x)
37 #endif
38
39 namespace cppbor {
40
41 namespace {
42
43 const unsigned kMaxParseDepth = 1000;
44 const size_t kMaxReserveSize = 8192;
45
insufficientLengthString(size_t bytesNeeded,size_t bytesAvail,const std::string & type)46 std::string insufficientLengthString(size_t bytesNeeded, size_t bytesAvail,
47 const std::string& type) {
48 char buf[1024];
49 snprintf(buf, sizeof(buf), "Need %zu byte(s) for %s, have %zu.", bytesNeeded, type.c_str(),
50 bytesAvail);
51 return std::string(buf);
52 }
53
54 template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
parseLength(const uint8_t * pos,const uint8_t * end,ParseClient * parseClient)55 std::tuple<bool, uint64_t, const uint8_t*> parseLength(const uint8_t* pos, const uint8_t* end,
56 ParseClient* parseClient) {
57 if ((end - pos) < static_cast<ptrdiff_t>(sizeof(T))) {
58 parseClient->error(pos - 1, insufficientLengthString(sizeof(T), end - pos, "length field"));
59 return {false, 0, pos};
60 }
61
62 const uint8_t* intEnd = pos + sizeof(T);
63 T result = 0;
64 do {
65 result = static_cast<T>((result << 8) | *pos++);
66 } while (pos < intEnd);
67 return {true, result, pos};
68 }
69
70 std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
71 bool emitViews, ParseClient* parseClient,
72 unsigned depth);
73
handleUint(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)74 std::tuple<const uint8_t*, ParseClient*> handleUint(uint64_t value, const uint8_t* hdrBegin,
75 const uint8_t* hdrEnd,
76 ParseClient* parseClient) {
77 std::unique_ptr<Item> item = std::make_unique<Uint>(value);
78 return {hdrEnd,
79 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
80 }
81
handleNint(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)82 std::tuple<const uint8_t*, ParseClient*> handleNint(uint64_t value, const uint8_t* hdrBegin,
83 const uint8_t* hdrEnd,
84 ParseClient* parseClient) {
85 if (value > std::numeric_limits<int64_t>::max()) {
86 parseClient->error(hdrBegin, "NINT values that don't fit in int64_t are not supported.");
87 return {hdrBegin, nullptr /* end parsing */};
88 }
89 std::unique_ptr<Item> item = std::make_unique<Nint>(-1 - static_cast<int64_t>(value));
90 return {hdrEnd,
91 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
92 }
93
handleBool(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)94 std::tuple<const uint8_t*, ParseClient*> handleBool(uint64_t value, const uint8_t* hdrBegin,
95 const uint8_t* hdrEnd,
96 ParseClient* parseClient) {
97 std::unique_ptr<Item> item = std::make_unique<Bool>(value == TRUE);
98 return {hdrEnd,
99 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
100 }
101
handleNull(const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)102 std::tuple<const uint8_t*, ParseClient*> handleNull(const uint8_t* hdrBegin, const uint8_t* hdrEnd,
103 ParseClient* parseClient) {
104 std::unique_ptr<Item> item = std::make_unique<Null>();
105 return {hdrEnd,
106 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
107 }
108
109 #if defined(__STDC_IEC_559__) || FLT_MANT_DIG == 24 || __FLT_MANT_DIG__ == 24
handleFloat(uint32_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)110 std::tuple<const uint8_t*, ParseClient*> handleFloat(uint32_t value, const uint8_t* hdrBegin,
111 const uint8_t* hdrEnd,
112 ParseClient* parseClient) {
113 float f;
114 std::memcpy(&f, &value, sizeof(float));
115 std::unique_ptr<Item> item = std::make_unique<Float>(f);
116 return {hdrEnd,
117 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
118 }
119 #endif // __STDC_IEC_559__ || FLT_MANT_DIG == 24 || __FLT_MANT_DIG__ == 24
120
121 #if defined(__STDC_IEC_559__) || DBL_MANT_DIG == 53 || __DBL_MANT_DIG__ == 53
handleDouble(uint64_t value,const uint8_t * hdrBegin,const uint8_t * hdrEnd,ParseClient * parseClient)122 std::tuple<const uint8_t*, ParseClient*> handleDouble(uint64_t value, const uint8_t* hdrBegin,
123 const uint8_t* hdrEnd,
124 ParseClient* parseClient) {
125 double d;
126 std::memcpy(&d, &value, sizeof(double));
127 std::unique_ptr<Item> item = std::make_unique<Double>(d);
128 return {hdrEnd,
129 parseClient->item(item, hdrBegin, hdrEnd /* valueBegin */, hdrEnd /* itemEnd */)};
130 }
131 #endif // __STDC_IEC_559__ || DBL_MANT_DIG == 53 || __DBL_MANT_DIG__ == 53
132
133 template <typename T>
handleString(uint64_t length,const uint8_t * hdrBegin,const uint8_t * valueBegin,const uint8_t * end,const std::string & errLabel,ParseClient * parseClient)134 std::tuple<const uint8_t*, ParseClient*> handleString(uint64_t length, const uint8_t* hdrBegin,
135 const uint8_t* valueBegin, const uint8_t* end,
136 const std::string& errLabel,
137 ParseClient* parseClient) {
138 ssize_t signed_length = static_cast<ssize_t>(length);
139 if (end - valueBegin < signed_length || signed_length < 0) {
140 parseClient->error(hdrBegin, insufficientLengthString(length, end - valueBegin, errLabel));
141 return {hdrBegin, nullptr /* end parsing */};
142 }
143
144 std::unique_ptr<Item> item = std::make_unique<T>(valueBegin, valueBegin + length);
145 return {valueBegin + length,
146 parseClient->item(item, hdrBegin, valueBegin, valueBegin + length)};
147 }
148
handleIncompleteString(std::unique_ptr<Item> item,const uint8_t * hdrBegin,const uint8_t * valueBegin,const uint8_t * end,const std::string & errLabel,bool emitViews,ParseClient * parseClient,unsigned depth)149 std::tuple<const uint8_t*, ParseClient*> handleIncompleteString(
150 std::unique_ptr<Item> item, const uint8_t* hdrBegin, const uint8_t* valueBegin,
151 const uint8_t* end, const std::string& errLabel, bool emitViews, ParseClient* parseClient,
152 unsigned depth) {
153 parseClient =
154 parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
155 if (!parseClient) return {hdrBegin, nullptr};
156
157 const uint8_t* pos = valueBegin;
158 while (true) {
159 if (pos == end) {
160 parseClient->error(hdrBegin, "Not enough entries for " + errLabel + ".");
161 return {hdrBegin, nullptr /* end parsing */};
162 }
163 if (*pos == 0xFF) {
164 // We found a stop code.
165 ++pos;
166 break;
167 }
168 std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient, depth + 1);
169 if (!parseClient) return {hdrBegin, nullptr};
170 }
171 if (!parseClient) return {hdrBegin, nullptr};
172
173 return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
174 }
175
176 class IncompleteItem {
177 public:
178 static IncompleteItem* cast(Item* item);
179
~IncompleteItem()180 virtual ~IncompleteItem() {}
181 virtual void add(std::unique_ptr<Item> item) = 0;
182 virtual std::unique_ptr<Item> finalize() && = 0;
183 };
184
185 class IncompleteBstr : public Bstr, public IncompleteItem {
186 public:
IncompleteBstr()187 explicit IncompleteBstr() {}
188
189 // The finalized version creates a copy which will not have this overridden.
isCompound() const190 bool isCompound() const override { return true; }
191
add(std::unique_ptr<Item> item)192 void add(std::unique_ptr<Item> item) override {
193 if (item->type() == BSTR) {
194 mValue.insert(mValue.end(), item->asBstr()->moveValue().begin(),
195 item->asBstr()->moveValue().end());
196 } else {
197 #ifndef __TRUSTY__
198 LOG(FATAL) << "Should not happen: Expected BSTR";
199 #endif // __TRUSTY__
200 }
201 }
202
finalize()203 std::unique_ptr<Item> finalize() && override { return std::make_unique<Bstr>(mValue); }
204 };
205
206 class IncompleteTstr : public Tstr, public IncompleteItem {
207 public:
IncompleteTstr()208 explicit IncompleteTstr() {}
209
210 // The finalized version creates a copy which will not have this overridden.
isCompound() const211 bool isCompound() const override { return true; }
212
add(std::unique_ptr<Item> item)213 void add(std::unique_ptr<Item> item) override {
214 if (item->type() == TSTR) {
215 ss << item->asTstr()->moveValue();
216 } else {
217 #ifndef __TRUSTY__
218 LOG(FATAL) << "Should not happen: Expected TSTR";
219 #endif // __TRUSTY__
220 }
221 }
222
finalize()223 std::unique_ptr<Item> finalize() && override { return std::make_unique<Tstr>(ss.str()); }
224
225 private:
226 std::stringstream ss;
227 };
228
229 class IncompleteArray : public Array, public IncompleteItem {
230 public:
IncompleteArray(std::optional<size_t> size)231 explicit IncompleteArray(std::optional<size_t> size) : mSize(size) {}
232
233 // If the "complete" size is known, return it, otherwise return the current size.
size() const234 size_t size() const override { return mSize.value_or(Array::size()); }
235
add(std::unique_ptr<Item> item)236 void add(std::unique_ptr<Item> item) override {
237 if (mSize) mEntries.reserve(std::min(mSize.value(), kMaxReserveSize));
238 mEntries.push_back(std::move(item));
239 }
240
finalize()241 virtual std::unique_ptr<Item> finalize() && override {
242 // Use Array explicitly so the compiler picks the correct ctor overload
243 Array* thisArray = this;
244 return std::make_unique<Array>(std::move(*thisArray));
245 }
246
247 private:
248 std::optional<size_t> mSize;
249 };
250
251 class IncompleteMap : public Map, public IncompleteItem {
252 public:
IncompleteMap(std::optional<size_t> size)253 explicit IncompleteMap(std::optional<size_t> size) : mSize(size) {}
254
255 // If the "complete" size is known, return it, otherwise return the current size.
size() const256 size_t size() const override { return mSize.value_or(Map::size()); }
257
add(std::unique_ptr<Item> item)258 void add(std::unique_ptr<Item> item) override {
259 if (mKeyHeldForAdding) {
260 if (mSize) mEntries.reserve(std::min(mSize.value(), kMaxReserveSize));
261 mEntries.push_back({std::move(mKeyHeldForAdding), std::move(item)});
262 } else {
263 mKeyHeldForAdding = std::move(item);
264 }
265 }
266
finalize()267 virtual std::unique_ptr<Item> finalize() && override {
268 return std::make_unique<Map>(std::move(*this));
269 }
270
271 private:
272 std::unique_ptr<Item> mKeyHeldForAdding;
273 std::optional<size_t> mSize;
274 };
275
276 class IncompleteSemanticTag : public SemanticTag, public IncompleteItem {
277 public:
IncompleteSemanticTag(uint64_t value)278 explicit IncompleteSemanticTag(uint64_t value) : SemanticTag(value) {}
279
280 // We return the "complete" size, rather than the actual size.
size() const281 size_t size() const override { return 1; }
282
add(std::unique_ptr<Item> item)283 void add(std::unique_ptr<Item> item) override { mTaggedItem = std::move(item); }
284
finalize()285 virtual std::unique_ptr<Item> finalize() && override {
286 return std::make_unique<SemanticTag>(std::move(*this));
287 }
288 };
289
cast(Item * item)290 IncompleteItem* IncompleteItem::cast(Item* item) {
291 CHECK(item->isCompound());
292 // Semantic tag must be check first, because SemanticTag::type returns the wrapped item's type.
293 if (item->asSemanticTag()) {
294 #if __has_feature(cxx_rtti)
295 CHECK(dynamic_cast<IncompleteSemanticTag*>(item));
296 #endif
297 return static_cast<IncompleteSemanticTag*>(item);
298 } else if (item->type() == ARRAY) {
299 #if __has_feature(cxx_rtti)
300 CHECK(dynamic_cast<IncompleteArray*>(item));
301 #endif
302 return static_cast<IncompleteArray*>(item);
303 } else if (item->type() == MAP) {
304 #if __has_feature(cxx_rtti)
305 CHECK(dynamic_cast<IncompleteMap*>(item));
306 #endif
307 return static_cast<IncompleteMap*>(item);
308 } else if (item->type() == BSTR) {
309 #if __has_feature(cxx_rtti)
310 CHECK(dynamic_cast<IncompleteBstr*>(item));
311 #endif
312 return static_cast<IncompleteBstr*>(item);
313 } else if (item->type() == TSTR) {
314 #if __has_feature(cxx_rtti)
315 CHECK(dynamic_cast<IncompleteTstr*>(item));
316 #endif
317 return static_cast<IncompleteTstr*>(item);
318 } else {
319 CHECK(false); // Impossible to get here.
320 }
321 return nullptr;
322 }
323
handleEntries(std::optional<size_t> entryCount,const uint8_t * hdrBegin,const uint8_t * pos,const uint8_t * end,const std::string & typeName,bool emitViews,ParseClient * parseClient,unsigned depth)324 std::tuple<const uint8_t*, ParseClient*> handleEntries(std::optional<size_t> entryCount,
325 const uint8_t* hdrBegin, const uint8_t* pos,
326 const uint8_t* end,
327 const std::string& typeName, bool emitViews,
328 ParseClient* parseClient, unsigned depth) {
329 while (entryCount.value_or(1) > 0) {
330 if (entryCount.has_value()) {
331 --*entryCount;
332 }
333 if (pos == end) {
334 parseClient->error(hdrBegin, "Not enough entries for " + typeName + ".");
335 return {hdrBegin, nullptr /* end parsing */};
336 }
337 if (!entryCount.has_value() && *pos == 0xFF) {
338 // We're in an indeterminate-length object and found a stop code.
339 ++pos;
340 break;
341 }
342 std::tie(pos, parseClient) = parseRecursively(pos, end, emitViews, parseClient, depth + 1);
343 if (!parseClient) return {hdrBegin, nullptr};
344 }
345 return {pos, parseClient};
346 }
347
handleCompound(std::unique_ptr<Item> item,std::optional<uint64_t> entryCount,const uint8_t * hdrBegin,const uint8_t * valueBegin,const uint8_t * end,const std::string & typeName,bool emitViews,ParseClient * parseClient,unsigned depth)348 std::tuple<const uint8_t*, ParseClient*> handleCompound(
349 std::unique_ptr<Item> item, std::optional<uint64_t> entryCount, const uint8_t* hdrBegin,
350 const uint8_t* valueBegin, const uint8_t* end, const std::string& typeName, bool emitViews,
351 ParseClient* parseClient, unsigned depth) {
352 parseClient =
353 parseClient->item(item, hdrBegin, valueBegin, valueBegin /* don't know the end yet */);
354 if (!parseClient) return {hdrBegin, nullptr};
355
356 const uint8_t* pos;
357 std::tie(pos, parseClient) = handleEntries(entryCount, hdrBegin, valueBegin, end, typeName,
358 emitViews, parseClient, depth);
359 if (!parseClient) return {hdrBegin, nullptr};
360
361 return {pos, parseClient->itemEnd(item, hdrBegin, valueBegin, pos)};
362 }
363
parseRecursively(const uint8_t * begin,const uint8_t * end,bool emitViews,ParseClient * parseClient,unsigned depth)364 std::tuple<const uint8_t*, ParseClient*> parseRecursively(const uint8_t* begin, const uint8_t* end,
365 bool emitViews, ParseClient* parseClient,
366 unsigned depth) {
367 if (begin == end) {
368 parseClient->error(
369 begin, "Input buffer is empty. Begin and end cannot point to the same location.");
370 return {begin, nullptr};
371 }
372
373 // Limit recursion depth to avoid overflowing the stack.
374 if (depth > kMaxParseDepth) {
375 parseClient->error(begin,
376 "Max depth reached. Cannot parse CBOR structures with more "
377 "than " +
378 std::to_string(kMaxParseDepth) + " levels.");
379 return {begin, nullptr};
380 }
381
382 const uint8_t* pos = begin;
383
384 MajorType type = static_cast<MajorType>(*pos & 0xE0);
385 uint8_t tagInt = *pos & 0x1F;
386 ++pos;
387
388 bool success = true;
389 std::optional<uint64_t> addlData;
390 if (tagInt < ONE_BYTE_LENGTH) {
391 addlData = tagInt;
392 } else if (tagInt > EIGHT_BYTE_LENGTH && tagInt != INDEFINITE_LENGTH) {
393 parseClient->error(begin, "Reserved additional information value.");
394 return {begin, nullptr};
395 } else {
396 switch (tagInt) {
397 case ONE_BYTE_LENGTH:
398 std::tie(success, addlData, pos) = parseLength<uint8_t>(pos, end, parseClient);
399 break;
400
401 case TWO_BYTE_LENGTH:
402 std::tie(success, addlData, pos) = parseLength<uint16_t>(pos, end, parseClient);
403 break;
404
405 case FOUR_BYTE_LENGTH:
406 std::tie(success, addlData, pos) = parseLength<uint32_t>(pos, end, parseClient);
407 break;
408
409 case EIGHT_BYTE_LENGTH:
410 std::tie(success, addlData, pos) = parseLength<uint64_t>(pos, end, parseClient);
411 break;
412
413 case INDEFINITE_LENGTH:
414 // View only strings are not yet supported due to their disjoint nature.
415 if (type != ARRAY && type != MAP && !(type == BSTR && !emitViews) &&
416 !(type == TSTR && !emitViews)) {
417 parseClient->error(begin, "Unsupported indefinite length item.");
418 return {begin, nullptr};
419 }
420 addlData = std::nullopt;
421 break;
422
423 default:
424 CHECK(false); // It's impossible to get here
425 break;
426 }
427 }
428
429 if (!success) return {begin, nullptr};
430
431 switch (type) {
432 case UINT:
433 return handleUint(*addlData, begin, pos, parseClient);
434
435 case NINT:
436 return handleNint(*addlData, begin, pos, parseClient);
437
438 case BSTR:
439 if (!addlData.has_value()) {
440 return handleIncompleteString(std::make_unique<IncompleteBstr>(), begin, pos, end,
441 "byte string", emitViews, parseClient, depth);
442 } else if (emitViews) {
443 return handleString<ViewBstr>(*addlData, begin, pos, end, "byte string",
444 parseClient);
445 } else {
446 return handleString<Bstr>(*addlData, begin, pos, end, "byte string", parseClient);
447 }
448
449 case TSTR:
450 if (!addlData.has_value()) {
451 return handleIncompleteString(std::make_unique<IncompleteTstr>(), begin, pos, end,
452 "text string", emitViews, parseClient, depth);
453 } else if (emitViews) {
454 return handleString<ViewTstr>(*addlData, begin, pos, end, "text string",
455 parseClient);
456 } else {
457 return handleString<Tstr>(*addlData, begin, pos, end, "text string", parseClient);
458 }
459
460 case ARRAY:
461 return handleCompound(std::make_unique<IncompleteArray>(addlData), addlData, begin, pos,
462 end, "array", emitViews, parseClient, depth);
463
464 case MAP:
465 return handleCompound(std::make_unique<IncompleteMap>(addlData),
466 addlData.has_value() ? *addlData * 2 : addlData, begin, pos, end,
467 "map", emitViews, parseClient, depth);
468
469 case SEMANTIC:
470 return handleCompound(std::make_unique<IncompleteSemanticTag>(*addlData), 1, begin, pos,
471 end, "semantic", emitViews, parseClient, depth);
472
473 case SIMPLE:
474 switch (tagInt) {
475 case TRUE:
476 case FALSE:
477 return handleBool(*addlData, begin, pos, parseClient);
478 case FLOAT_V:
479 #if defined(__STDC_IEC_559__) || FLT_MANT_DIG == 24 || __FLT_MANT_DIG__ == 24
480 return handleFloat(*addlData, begin, pos, parseClient);
481 #else
482 parseClient->error(begin, "Value float is not supported for platform.");
483 return {begin, nullptr};
484 #endif // __STDC_IEC_559__ || FLT_MANT_DIG == 24 || __FLT_MANT_DIG__ == 24
485 case DOUBLE_V:
486 #if defined(__STDC_IEC_559__) || DBL_MANT_DIG == 53 || __DBL_MANT_DIG__ == 53
487 return handleDouble(*addlData, begin, pos, parseClient);
488 #else
489 parseClient->error(begin, "Value double is not supported for platform.");
490 return {begin, nullptr};
491 #endif // __STDC_IEC_559__ || DBL_MANT_DIG == 53 || __DBL_MANT_DIG__ == 53
492 case NULL_V:
493 return handleNull(begin, pos, parseClient);
494 default:
495 parseClient->error(begin, "Unsupported half-floating-point or simple value.");
496 return {begin, nullptr};
497 }
498 }
499 CHECK(false); // Impossible to get here.
500 return {};
501 }
502
503 class FullParseClient : public ParseClient {
504 public:
item(std::unique_ptr<Item> & item,const uint8_t *,const uint8_t *,const uint8_t * end)505 virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
506 const uint8_t* end) override {
507 if (mParentStack.empty() && !item->isCompound()) {
508 // This is the first and only item.
509 mTheItem = std::move(item);
510 mPosition = end;
511 return nullptr; // We're done.
512 }
513
514 if (item->isCompound()) {
515 // Starting a new compound data item, i.e. a new parent. Save it on the parent stack.
516 // It's safe to save a raw pointer because the unique_ptr is guaranteed to stay in
517 // existence until the corresponding itemEnd() call.
518 mParentStack.push(item.get());
519 return this;
520 } else {
521 return appendToLastParent(std::move(item));
522 }
523 }
524
itemEnd(std::unique_ptr<Item> & item,const uint8_t *,const uint8_t *,const uint8_t * end)525 virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t*, const uint8_t*,
526 const uint8_t* end) override {
527 CHECK(item->isCompound() && item.get() == mParentStack.top());
528 mParentStack.pop();
529 IncompleteItem* incompleteItem = IncompleteItem::cast(item.get());
530 std::unique_ptr<Item> finalizedItem = std::move(*incompleteItem).finalize();
531
532 if (mParentStack.empty()) {
533 mTheItem = std::move(finalizedItem);
534 mPosition = end;
535 return nullptr; // We're done
536 } else {
537 return appendToLastParent(std::move(finalizedItem));
538 }
539 }
540
error(const uint8_t * position,const std::string & errorMessage)541 virtual void error(const uint8_t* position, const std::string& errorMessage) override {
542 mPosition = position;
543 mErrorMessage = errorMessage;
544 }
545
546 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
547 std::string /* errMsg */>
parseResult()548 parseResult() {
549 std::unique_ptr<Item> p = std::move(mTheItem);
550 return {std::move(p), mPosition, std::move(mErrorMessage)};
551 }
552
553 private:
appendToLastParent(std::unique_ptr<Item> item)554 ParseClient* appendToLastParent(std::unique_ptr<Item> item) {
555 auto parent = mParentStack.top();
556 switch (parent->type()) {
557 case BSTR:
558 if (item->type() != BSTR) {
559 mErrorMessage += "Expected BSTR in indefinite-length string.";
560 return nullptr;
561 }
562 IncompleteItem::cast(parent)->add(std::move(item));
563 break;
564 case TSTR:
565 if (item->type() != TSTR) {
566 mErrorMessage += "Expected TSTR in indefinite-length string.";
567 return nullptr;
568 }
569 IncompleteItem::cast(parent)->add(std::move(item));
570 break;
571 default:
572 IncompleteItem::cast(parent)->add(std::move(item));
573 break;
574 }
575 return this;
576 }
577
578 std::unique_ptr<Item> mTheItem;
579 std::stack<Item*> mParentStack;
580 const uint8_t* mPosition = nullptr;
581 std::string mErrorMessage;
582 };
583
584 } // anonymous namespace
585
parse(const uint8_t * begin,const uint8_t * end,ParseClient * parseClient)586 void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
587 parseRecursively(begin, end, false, parseClient, 0);
588 }
589
590 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
591 std::string /* errMsg */>
parse(const uint8_t * begin,const uint8_t * end)592 parse(const uint8_t* begin, const uint8_t* end) {
593 FullParseClient parseClient;
594 parse(begin, end, &parseClient);
595 return parseClient.parseResult();
596 }
597
parseWithViews(const uint8_t * begin,const uint8_t * end,ParseClient * parseClient)598 void parseWithViews(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient) {
599 parseRecursively(begin, end, true, parseClient, 0);
600 }
601
602 std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
603 std::string /* errMsg */>
parseWithViews(const uint8_t * begin,const uint8_t * end)604 parseWithViews(const uint8_t* begin, const uint8_t* end) {
605 FullParseClient parseClient;
606 parseWithViews(begin, end, &parseClient);
607 return parseClient.parseResult();
608 }
609
610 } // namespace cppbor
611