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

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

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