• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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