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

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

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