OLD | NEW |
| (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 | |
OLD | NEW |