xref: /aosp_15_r20/system/libcppbor/src/cppbor_parse.cpp (revision 0963554132e37a14524024fa04dc9e883c7a8221)
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