Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: mojo/public/cpp/bindings/tests/validation_test_input_parser.cc

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
6
7 #include <assert.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include <limits>
12 #include <map>
13 #include <set>
14 #include <utility>
15
16 namespace mojo {
17 namespace test {
18 namespace {
19
20 class ValidationTestInputParser {
21 public:
22 ValidationTestInputParser(const std::string& input,
23 std::vector<uint8_t>* data,
24 size_t* num_handles,
25 std::string* error_message);
26 ~ValidationTestInputParser();
27
28 bool Run();
29
30 private:
31 struct DataType;
32
33 typedef std::pair<const char*, const char*> Range;
34
35 typedef bool (ValidationTestInputParser::*ParseDataFunc)(
36 const DataType& type,
37 const std::string& value_string);
38
39 struct DataType {
40 const char* name;
41 size_t name_size;
42 size_t data_size;
43 ParseDataFunc parse_data_func;
44 };
45
46 // A dist4/8 item that hasn't been matched with an anchr item.
47 struct PendingDistanceItem {
48 // Where this data item is located in |data_|.
49 size_t pos;
50 // Either 4 or 8 (bytes).
51 size_t data_size;
52 };
53
54 bool GetNextItem(Range* range);
55
56 bool ParseItem(const Range& range);
57
58 bool ParseUnsignedInteger(const DataType& type,
59 const std::string& value_string);
60 bool ParseSignedInteger(const DataType& type,
61 const std::string& value_string);
62 bool ParseFloat(const DataType& type, const std::string& value_string);
63 bool ParseDouble(const DataType& type, const std::string& value_string);
64 bool ParseBinarySequence(const DataType& type,
65 const std::string& value_string);
66 bool ParseDistance(const DataType& type, const std::string& value_string);
67 bool ParseAnchor(const DataType& type, const std::string& value_string);
68 bool ParseHandles(const DataType& type, const std::string& value_string);
69
70 bool StartsWith(const Range& range, const char* prefix, size_t prefix_length);
71
72 bool ConvertToUnsignedInteger(const std::string& value_string,
73 unsigned long long int* value);
74
75 template <typename T>
76 void AppendData(T data) {
77 size_t pos = data_->size();
78 data_->resize(pos + sizeof(T));
79 memcpy(&(*data_)[pos], &data, sizeof(T));
80 }
81
82 template <typename TargetType, typename InputType>
83 bool ConvertAndAppendData(InputType value) {
84 if (value > std::numeric_limits<TargetType>::max() ||
85 value < std::numeric_limits<TargetType>::min()) {
86 return false;
87 }
88 AppendData(static_cast<TargetType>(value));
89 return true;
90 }
91
92 template <typename TargetType, typename InputType>
93 bool ConvertAndFillData(size_t pos, InputType value) {
94 if (value > std::numeric_limits<TargetType>::max() ||
95 value < std::numeric_limits<TargetType>::min()) {
96 return false;
97 }
98 TargetType target_value = static_cast<TargetType>(value);
99 assert(pos + sizeof(TargetType) <= data_->size());
100 memcpy(&(*data_)[pos], &target_value, sizeof(TargetType));
101 return true;
102 }
103
104 static const DataType kDataTypes[];
105 static const size_t kDataTypeCount;
106
107 const std::string& input_;
108 size_t input_cursor_;
109
110 std::vector<uint8_t>* data_;
111 size_t* num_handles_;
112 std::string* error_message_;
113
114 std::map<std::string, PendingDistanceItem> pending_distance_items_;
115 std::set<std::string> anchors_;
116 };
117
118 #define DATA_TYPE(name, data_size, parse_data_func) \
119 { name, sizeof(name) - 1, data_size, parse_data_func }
120
121 const ValidationTestInputParser::DataType
122 ValidationTestInputParser::kDataTypes[] = {
123 DATA_TYPE("[u1]", 1, &ValidationTestInputParser::ParseUnsignedInteger),
124 DATA_TYPE("[u2]", 2, &ValidationTestInputParser::ParseUnsignedInteger),
125 DATA_TYPE("[u4]", 4, &ValidationTestInputParser::ParseUnsignedInteger),
126 DATA_TYPE("[u8]", 8, &ValidationTestInputParser::ParseUnsignedInteger),
127 DATA_TYPE("[s1]", 1, &ValidationTestInputParser::ParseSignedInteger),
128 DATA_TYPE("[s2]", 2, &ValidationTestInputParser::ParseSignedInteger),
129 DATA_TYPE("[s4]", 4, &ValidationTestInputParser::ParseSignedInteger),
130 DATA_TYPE("[s8]", 8, &ValidationTestInputParser::ParseSignedInteger),
131 DATA_TYPE("[b]", 1, &ValidationTestInputParser::ParseBinarySequence),
132 DATA_TYPE("[f]", 4, &ValidationTestInputParser::ParseFloat),
133 DATA_TYPE("[d]", 8, &ValidationTestInputParser::ParseDouble),
134 DATA_TYPE("[dist4]", 4, &ValidationTestInputParser::ParseDistance),
135 DATA_TYPE("[dist8]", 8, &ValidationTestInputParser::ParseDistance),
136 DATA_TYPE("[anchr]", 0, &ValidationTestInputParser::ParseAnchor),
137 DATA_TYPE("[handles]", 0, &ValidationTestInputParser::ParseHandles)};
138
139 const size_t ValidationTestInputParser::kDataTypeCount =
140 sizeof(ValidationTestInputParser::kDataTypes) /
141 sizeof(ValidationTestInputParser::kDataTypes[0]);
142
143 ValidationTestInputParser::ValidationTestInputParser(const std::string& input,
144 std::vector<uint8_t>* data,
145 size_t* num_handles,
146 std::string* error_message)
147 : input_(input),
148 input_cursor_(0),
149 data_(data),
150 num_handles_(num_handles),
151 error_message_(error_message) {
152 assert(data_);
153 assert(num_handles_);
154 assert(error_message_);
155 data_->clear();
156 *num_handles_ = 0;
157 error_message_->clear();
158 }
159
160 ValidationTestInputParser::~ValidationTestInputParser() {
161 }
162
163 bool ValidationTestInputParser::Run() {
164 Range range;
165 bool result = true;
166 while (result && GetNextItem(&range))
167 result = ParseItem(range);
168
169 if (!result) {
170 *error_message_ =
171 "Error occurred when parsing " + std::string(range.first, range.second);
172 } else if (!pending_distance_items_.empty()) {
173 // We have parsed all the contents in |input_| successfully, but there are
174 // unmatched dist4/8 items.
175 *error_message_ = "Error occurred when matching [dist4/8] and [anchr].";
176 result = false;
177 }
178 if (!result) {
179 data_->clear();
180 *num_handles_ = 0;
181 } else {
182 assert(error_message_->empty());
183 }
184
185 return result;
186 }
187
188 bool ValidationTestInputParser::GetNextItem(Range* range) {
189 const char kWhitespaceChars[] = " \t\n\r";
190 const char kItemDelimiters[] = " \t\n\r/";
191 const char kEndOfLineChars[] = "\n\r";
192 while (true) {
193 // Skip leading whitespaces.
194 // If there are no non-whitespace characters left, |input_cursor_| will be
195 // set to std::npos.
196 input_cursor_ = input_.find_first_not_of(kWhitespaceChars, input_cursor_);
197
198 if (input_cursor_ >= input_.size())
199 return false;
200
201 if (StartsWith(
202 Range(&input_[0] + input_cursor_, &input_[0] + input_.size()),
203 "//",
204 2)) {
205 // Skip contents until the end of the line.
206 input_cursor_ = input_.find_first_of(kEndOfLineChars, input_cursor_);
207 } else {
208 range->first = &input_[0] + input_cursor_;
209 input_cursor_ = input_.find_first_of(kItemDelimiters, input_cursor_);
210 range->second = input_cursor_ >= input_.size()
211 ? &input_[0] + input_.size()
212 : &input_[0] + input_cursor_;
213 return true;
214 }
215 }
216 return false;
217 }
218
219 bool ValidationTestInputParser::ParseItem(const Range& range) {
220 for (size_t i = 0; i < kDataTypeCount; ++i) {
221 if (StartsWith(range, kDataTypes[i].name, kDataTypes[i].name_size)) {
222 return (this->*kDataTypes[i].parse_data_func)(
223 kDataTypes[i],
224 std::string(range.first + kDataTypes[i].name_size, range.second));
225 }
226 }
227
228 // "[u1]" is optional.
229 return ParseUnsignedInteger(kDataTypes[0],
230 std::string(range.first, range.second));
231 }
232
233 bool ValidationTestInputParser::ParseUnsignedInteger(
234 const DataType& type,
235 const std::string& value_string) {
236 unsigned long long int value;
237 if (!ConvertToUnsignedInteger(value_string, &value))
238 return false;
239
240 switch (type.data_size) {
241 case 1:
242 return ConvertAndAppendData<uint8_t>(value);
243 case 2:
244 return ConvertAndAppendData<uint16_t>(value);
245 case 4:
246 return ConvertAndAppendData<uint32_t>(value);
247 case 8:
248 return ConvertAndAppendData<uint64_t>(value);
249 default:
250 assert(false);
251 return false;
252 }
253 }
254
255 bool ValidationTestInputParser::ParseSignedInteger(
256 const DataType& type,
257 const std::string& value_string) {
258 long long int value;
259 if (sscanf(value_string.c_str(), "%lli", &value) != 1)
260 return false;
261
262 switch (type.data_size) {
263 case 1:
264 return ConvertAndAppendData<int8_t>(value);
265 case 2:
266 return ConvertAndAppendData<int16_t>(value);
267 case 4:
268 return ConvertAndAppendData<int32_t>(value);
269 case 8:
270 return ConvertAndAppendData<int64_t>(value);
271 default:
272 assert(false);
273 return false;
274 }
275 }
276
277 bool ValidationTestInputParser::ParseFloat(const DataType& type,
278 const std::string& value_string) {
279 static_assert(sizeof(float) == 4, "sizeof(float) is not 4");
280
281 float value;
282 if (sscanf(value_string.c_str(), "%f", &value) != 1)
283 return false;
284
285 AppendData(value);
286 return true;
287 }
288
289 bool ValidationTestInputParser::ParseDouble(const DataType& type,
290 const std::string& value_string) {
291 static_assert(sizeof(double) == 8, "sizeof(double) is not 8");
292
293 double value;
294 if (sscanf(value_string.c_str(), "%lf", &value) != 1)
295 return false;
296
297 AppendData(value);
298 return true;
299 }
300
301 bool ValidationTestInputParser::ParseBinarySequence(
302 const DataType& type,
303 const std::string& value_string) {
304 if (value_string.size() != 8)
305 return false;
306
307 uint8_t value = 0;
308 for (std::string::const_iterator iter = value_string.begin();
309 iter != value_string.end();
310 ++iter) {
311 value <<= 1;
312 if (*iter == '1')
313 value++;
314 else if (*iter != '0')
315 return false;
316 }
317 AppendData(value);
318 return true;
319 }
320
321 bool ValidationTestInputParser::ParseDistance(const DataType& type,
322 const std::string& value_string) {
323 if (pending_distance_items_.find(value_string) !=
324 pending_distance_items_.end())
325 return false;
326
327 PendingDistanceItem item = {data_->size(), type.data_size};
328 data_->resize(data_->size() + type.data_size);
329 pending_distance_items_[value_string] = item;
330
331 return true;
332 }
333
334 bool ValidationTestInputParser::ParseAnchor(const DataType& type,
335 const std::string& value_string) {
336 if (anchors_.find(value_string) != anchors_.end())
337 return false;
338 anchors_.insert(value_string);
339
340 std::map<std::string, PendingDistanceItem>::iterator iter =
341 pending_distance_items_.find(value_string);
342 if (iter == pending_distance_items_.end())
343 return false;
344
345 PendingDistanceItem dist_item = iter->second;
346 pending_distance_items_.erase(iter);
347
348 size_t distance = data_->size() - dist_item.pos;
349 switch (dist_item.data_size) {
350 case 4:
351 return ConvertAndFillData<uint32_t>(dist_item.pos, distance);
352 case 8:
353 return ConvertAndFillData<uint64_t>(dist_item.pos, distance);
354 default:
355 assert(false);
356 return false;
357 }
358 }
359
360 bool ValidationTestInputParser::ParseHandles(const DataType& type,
361 const std::string& value_string) {
362 // It should be the first item.
363 if (!data_->empty())
364 return false;
365
366 unsigned long long int value;
367 if (!ConvertToUnsignedInteger(value_string, &value))
368 return false;
369
370 if (value > std::numeric_limits<size_t>::max())
371 return false;
372
373 *num_handles_ = static_cast<size_t>(value);
374 return true;
375 }
376
377 bool ValidationTestInputParser::StartsWith(const Range& range,
378 const char* prefix,
379 size_t prefix_length) {
380 if (static_cast<size_t>(range.second - range.first) < prefix_length)
381 return false;
382
383 return memcmp(range.first, prefix, prefix_length) == 0;
384 }
385
386 bool ValidationTestInputParser::ConvertToUnsignedInteger(
387 const std::string& value_string,
388 unsigned long long int* value) {
389 const char* format = nullptr;
390 if (value_string.find_first_of("xX") != std::string::npos)
391 format = "%llx";
392 else
393 format = "%llu";
394 return sscanf(value_string.c_str(), format, value) == 1;
395 }
396
397 } // namespace
398
399 bool ParseValidationTestInput(const std::string& input,
400 std::vector<uint8_t>* data,
401 size_t* num_handles,
402 std::string* error_message) {
403 ValidationTestInputParser parser(input, data, num_handles, error_message);
404 return parser.Run();
405 }
406
407 } // namespace test
408 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/tests/validation_test_input_parser.h ('k') | mojo/public/cpp/bindings/tests/validation_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698