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