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 #pragma once
18
19 #include "cppbor.h"
20
21 namespace cppbor {
22
23 using ParseResult = std::tuple<std::unique_ptr<Item> /* result */, const uint8_t* /* newPos */,
24 std::string /* errMsg */>;
25
26 /**
27 * Parse the first CBOR data item (possibly compound) from the range [begin, end).
28 *
29 * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
30 * Item pointer is non-null, the buffer pointer points to the first byte after the
31 * successfully-parsed item and the error message string is empty. If parsing fails, the Item
32 * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
33 * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
34 * too large for the remaining buffer, etc.) and the string contains an error message describing the
35 * problem encountered.
36 */
37 ParseResult parse(const uint8_t* begin, const uint8_t* end);
38
39 /**
40 * Parse the first CBOR data item (possibly compound) from the range [begin, end).
41 *
42 * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
43 * Item pointer is non-null, the buffer pointer points to the first byte after the
44 * successfully-parsed item and the error message string is empty. If parsing fails, the Item
45 * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
46 * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
47 * too large for the remaining buffer, etc.) and the string contains an error message describing the
48 * problem encountered.
49 *
50 * The returned CBOR data item will contain View* items backed by
51 * std::string_view types over the input range.
52 * WARNING! If the input range changes underneath, the corresponding views will
53 * carry the same change.
54 */
55 ParseResult parseWithViews(const uint8_t* begin, const uint8_t* end);
56
57 /**
58 * Parse the first CBOR data item (possibly compound) from the byte vector.
59 *
60 * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
61 * Item pointer is non-null, the buffer pointer points to the first byte after the
62 * successfully-parsed item and the error message string is empty. If parsing fails, the Item
63 * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
64 * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
65 * too large for the remaining buffer, etc.) and the string contains an error message describing the
66 * problem encountered.
67 */
parse(const std::vector<uint8_t> & encoding)68 inline ParseResult parse(const std::vector<uint8_t>& encoding) {
69 return parse(encoding.data(), encoding.data() + encoding.size());
70 }
71
72 /**
73 * Parse the first CBOR data item (possibly compound) from the range [begin, begin + size).
74 *
75 * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
76 * Item pointer is non-null, the buffer pointer points to the first byte after the
77 * successfully-parsed item and the error message string is empty. If parsing fails, the Item
78 * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
79 * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
80 * too large for the remaining buffer, etc.) and the string contains an error message describing the
81 * problem encountered.
82 */
parse(const uint8_t * begin,size_t size)83 inline ParseResult parse(const uint8_t* begin, size_t size) {
84 return parse(begin, begin + size);
85 }
86
87 /**
88 * Parse the first CBOR data item (possibly compound) from the range [begin, begin + size).
89 *
90 * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
91 * Item pointer is non-null, the buffer pointer points to the first byte after the
92 * successfully-parsed item and the error message string is empty. If parsing fails, the Item
93 * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
94 * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
95 * too large for the remaining buffer, etc.) and the string contains an error message describing the
96 * problem encountered.
97 *
98 * The returned CBOR data item will contain View* items backed by
99 * std::string_view types over the input range.
100 * WARNING! If the input range changes underneath, the corresponding views will
101 * carry the same change.
102 */
parseWithViews(const uint8_t * begin,size_t size)103 inline ParseResult parseWithViews(const uint8_t* begin, size_t size) {
104 return parseWithViews(begin, begin + size);
105 }
106
107 /**
108 * Parse the first CBOR data item (possibly compound) from the value contained in a Bstr.
109 *
110 * Returns a tuple of Item pointer, buffer pointer and error message. If parsing is successful, the
111 * Item pointer is non-null, the buffer pointer points to the first byte after the
112 * successfully-parsed item and the error message string is empty. If parsing fails, the Item
113 * pointer is null, the buffer pointer points to the first byte that was unparseable (the first byte
114 * of a data item header that is malformed in some way, e.g. an invalid value, or a length that is
115 * too large for the remaining buffer, etc.) and the string contains an error message describing the
116 * problem encountered.
117 */
parse(const Bstr * bstr)118 inline ParseResult parse(const Bstr* bstr) {
119 if (!bstr)
120 return ParseResult(nullptr, nullptr, "Null Bstr pointer");
121 return parse(bstr->value());
122 }
123
124 class ParseClient;
125
126 /**
127 * Parse the CBOR data in the range [begin, end) in streaming fashion, calling methods on the
128 * provided ParseClient when elements are found.
129 */
130 void parse(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient);
131
132 /**
133 * Parse the CBOR data in the range [begin, end) in streaming fashion, calling methods on the
134 * provided ParseClient when elements are found. Uses the View* item types
135 * instead of the copying ones.
136 */
137 void parseWithViews(const uint8_t* begin, const uint8_t* end, ParseClient* parseClient);
138
139 /**
140 * Parse the CBOR data in the vector in streaming fashion, calling methods on the
141 * provided ParseClient when elements are found.
142 */
parse(const std::vector<uint8_t> & encoding,ParseClient * parseClient)143 inline void parse(const std::vector<uint8_t>& encoding, ParseClient* parseClient) {
144 return parse(encoding.data(), encoding.data() + encoding.size(), parseClient);
145 }
146
147 /**
148 * A pure interface that callers of the streaming parse functions must implement.
149 */
150 class ParseClient {
151 public:
~ParseClient()152 virtual ~ParseClient() {}
153
154 /**
155 * Called when an item is found. The Item pointer points to the found item; use type() and
156 * the appropriate as*() method to examine the value. hdrBegin points to the first byte of the
157 * header, valueBegin points to the first byte of the value and end points one past the end of
158 * the item. In the case of header-only items, such as integers, and compound items (ARRAY,
159 * MAP or SEMANTIC) whose end has not yet been found, valueBegin and end are equal and point to
160 * the byte past the header.
161 *
162 * Note that for compound types (ARRAY, MAP, and SEMANTIC), the Item will have no content. For
163 * Map and Array items, the size() method will return a correct value, but the index operators
164 * are unsafe, and the object cannot be safely compared with another Array/Map.
165 *
166 * The method returns a ParseClient*. In most cases "return this;" will be the right answer,
167 * but a different ParseClient may be returned, which the parser will begin using. If the method
168 * returns nullptr, parsing will be aborted immediately.
169 */
170 virtual ParseClient* item(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
171 const uint8_t* valueBegin, const uint8_t* end) = 0;
172
173 /**
174 * Called when the end of a compound item (MAP or ARRAY) is found. The item argument will be
175 * the same one passed to the item() call -- and may be empty if item() moved its value out.
176 * hdrBegin, valueBegin and end point to the beginning of the item header, the beginning of the
177 * first contained value, and one past the end of the last contained value, respectively.
178 *
179 * Note that the Item will have no content.
180 *
181 * As with item(), itemEnd() can change the ParseClient by returning a different one, or end the
182 * parsing by returning nullptr;
183 */
184 virtual ParseClient* itemEnd(std::unique_ptr<Item>& item, const uint8_t* hdrBegin,
185 const uint8_t* valueBegin, const uint8_t* end) = 0;
186
187 /**
188 * Called when parsing encounters an error. position is set to the first unparsed byte (one
189 * past the last successfully-parsed byte) and errorMessage contains an message explaining what
190 * sort of error occurred.
191 */
192 virtual void error(const uint8_t* position, const std::string& errorMessage) = 0;
193 };
194
195 } // namespace cppbor
196