Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / mojo / public / cpp / bindings / tests / validation_test_input_parser.cc
blobf5a5962d9f87510b5e5db3758685f7c4f8b41ab1
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.
5 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
7 #include <assert.h>
8 #include <stdio.h>
9 #include <string.h>
11 #include <limits>
12 #include <map>
13 #include <set>
14 #include <utility>
16 #include "mojo/public/c/system/macros.h"
18 namespace mojo {
19 namespace test {
20 namespace {
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();
30 bool Run();
32 private:
33 struct DataType;
35 typedef std::pair<const char*, const char*> Range;
37 typedef bool (ValidationTestInputParser::*ParseDataFunc)(
38 const DataType& type, const std::string& value_string);
40 struct DataType {
41 const char* name;
42 size_t name_size;
43 size_t data_size;
44 ParseDataFunc parse_data_func;
47 // A dist4/8 item that hasn't been matched with an anchr item.
48 struct PendingDistanceItem {
49 // Where this data item is located in |data_|.
50 size_t pos;
51 // Either 4 or 8 (bytes).
52 size_t data_size;
55 bool GetNextItem(Range* range);
57 bool ParseItem(const Range& range);
59 bool ParseUnsignedInteger(const DataType& type,
60 const std::string& value_string);
61 bool ParseSignedInteger(const DataType& type,
62 const std::string& value_string);
63 bool ParseFloat(const DataType& type, const std::string& value_string);
64 bool ParseDouble(const DataType& type, const std::string& value_string);
65 bool ParseBinarySequence(const DataType& type,
66 const std::string& value_string);
67 bool ParseDistance(const DataType& type, const std::string& value_string);
68 bool ParseAnchor(const DataType& type, const std::string& value_string);
69 bool ParseHandles(const DataType& type, const std::string& value_string);
71 bool StartsWith(const Range& range, const char* prefix, size_t prefix_length);
73 bool ConvertToUnsignedInteger(const std::string& value_string,
74 unsigned long long int* value);
76 template <typename T>
77 void AppendData(T data) {
78 size_t pos = data_->size();
79 data_->resize(pos + sizeof(T));
80 memcpy(&(*data_)[pos], &data, sizeof(T));
83 template <typename TargetType, typename InputType>
84 bool ConvertAndAppendData(InputType value) {
85 if (value > std::numeric_limits<TargetType>::max() ||
86 value < std::numeric_limits<TargetType>::min()) {
87 return false;
89 AppendData(static_cast<TargetType>(value));
90 return true;
93 template <typename TargetType, typename InputType>
94 bool ConvertAndFillData(size_t pos, InputType value) {
95 if (value > std::numeric_limits<TargetType>::max() ||
96 value < std::numeric_limits<TargetType>::min()) {
97 return false;
99 TargetType target_value = static_cast<TargetType>(value);
100 assert(pos + sizeof(TargetType) <= data_->size());
101 memcpy(&(*data_)[pos], &target_value, sizeof(TargetType));
102 return true;
105 static const DataType kDataTypes[];
106 static const size_t kDataTypeCount;
108 const std::string& input_;
109 size_t input_cursor_;
111 std::vector<uint8_t>* data_;
112 size_t* num_handles_;
113 std::string* error_message_;
115 std::map<std::string, PendingDistanceItem> pending_distance_items_;
116 std::set<std::string> anchors_;
119 #define DATA_TYPE(name, data_size, parse_data_func) \
120 {name, sizeof(name) - 1, data_size, parse_data_func}
122 const ValidationTestInputParser::DataType
123 ValidationTestInputParser::kDataTypes[] = {
124 DATA_TYPE("[u1]", 1, &ValidationTestInputParser::ParseUnsignedInteger),
125 DATA_TYPE("[u2]", 2, &ValidationTestInputParser::ParseUnsignedInteger),
126 DATA_TYPE("[u4]", 4, &ValidationTestInputParser::ParseUnsignedInteger),
127 DATA_TYPE("[u8]", 8, &ValidationTestInputParser::ParseUnsignedInteger),
128 DATA_TYPE("[s1]", 1, &ValidationTestInputParser::ParseSignedInteger),
129 DATA_TYPE("[s2]", 2, &ValidationTestInputParser::ParseSignedInteger),
130 DATA_TYPE("[s4]", 4, &ValidationTestInputParser::ParseSignedInteger),
131 DATA_TYPE("[s8]", 8, &ValidationTestInputParser::ParseSignedInteger),
132 DATA_TYPE("[b]", 1, &ValidationTestInputParser::ParseBinarySequence),
133 DATA_TYPE("[f]", 4, &ValidationTestInputParser::ParseFloat),
134 DATA_TYPE("[d]", 8, &ValidationTestInputParser::ParseDouble),
135 DATA_TYPE("[dist4]", 4, &ValidationTestInputParser::ParseDistance),
136 DATA_TYPE("[dist8]", 8, &ValidationTestInputParser::ParseDistance),
137 DATA_TYPE("[anchr]", 0, &ValidationTestInputParser::ParseAnchor),
138 DATA_TYPE("[handles]", 0, &ValidationTestInputParser::ParseHandles)
141 const size_t ValidationTestInputParser::kDataTypeCount =
142 sizeof(ValidationTestInputParser::kDataTypes) /
143 sizeof(ValidationTestInputParser::kDataTypes[0]);
145 ValidationTestInputParser::ValidationTestInputParser(
146 const std::string& input,
147 std::vector<uint8_t>* data,
148 size_t* num_handles,
149 std::string* error_message)
150 : input_(input),
151 input_cursor_(0),
152 data_(data),
153 num_handles_(num_handles),
154 error_message_(error_message) {
155 assert(data_);
156 assert(num_handles_);
157 assert(error_message_);
158 data_->clear();
159 *num_handles_ = 0;
160 error_message_->clear();
163 ValidationTestInputParser::~ValidationTestInputParser() {
166 bool ValidationTestInputParser::Run() {
167 Range range;
168 bool result = true;
169 while (result && GetNextItem(&range))
170 result = ParseItem(range);
172 if (!result) {
173 *error_message_ = "Error occurred when parsing " +
174 std::string(range.first, range.second);
175 } else if (!pending_distance_items_.empty()) {
176 // We have parsed all the contents in |input_| successfully, but there are
177 // unmatched dist4/8 items.
178 *error_message_ = "Error occurred when matching [dist4/8] and [anchr].";
179 result = false;
181 if (!result) {
182 data_->clear();
183 *num_handles_ = 0;
184 } else {
185 assert(error_message_->empty());
188 return result;
191 bool ValidationTestInputParser::GetNextItem(Range* range) {
192 const char kWhitespaceChars[] = " \t\n\r";
193 const char kItemDelimiters[] = " \t\n\r/";
194 const char kEndOfLineChars[] = "\n\r";
195 while (true) {
196 // Skip leading whitespaces.
197 // If there are no non-whitespace characters left, |input_cursor_| will be
198 // set to std::npos.
199 input_cursor_ = input_.find_first_not_of(kWhitespaceChars, input_cursor_);
201 if (input_cursor_ >= input_.size())
202 return false;
204 if (StartsWith(Range(&input_[0] + input_cursor_,
205 &input_[0] + input_.size()),
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() : &input_[0] + input_cursor_;
214 return true;
217 return false;
220 bool ValidationTestInputParser::ParseItem(const Range& range) {
221 for (size_t i = 0; i < kDataTypeCount; ++i) {
222 if (StartsWith(range, kDataTypes[i].name, kDataTypes[i].name_size)) {
223 return (this->*kDataTypes[i].parse_data_func)(
224 kDataTypes[i],
225 std::string(range.first + kDataTypes[i].name_size, range.second));
229 // "[u1]" is optional.
230 return ParseUnsignedInteger(kDataTypes[0],
231 std::string(range.first, range.second));
234 bool ValidationTestInputParser::ParseUnsignedInteger(
235 const DataType& type, const std::string& value_string) {
236 unsigned long long int value;
237 if (!ConvertToUnsignedInteger(value_string, &value))
238 return false;
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;
255 bool ValidationTestInputParser::ParseSignedInteger(
256 const DataType& type, const std::string& value_string) {
257 long long int value;
258 if (sscanf(value_string.c_str(), "%lli", &value) != 1)
259 return false;
261 switch (type.data_size) {
262 case 1:
263 return ConvertAndAppendData<int8_t>(value);
264 case 2:
265 return ConvertAndAppendData<int16_t>(value);
266 case 4:
267 return ConvertAndAppendData<int32_t>(value);
268 case 8:
269 return ConvertAndAppendData<int64_t>(value);
270 default:
271 assert(false);
272 return false;
276 bool ValidationTestInputParser::ParseFloat(
277 const DataType& type, const std::string& value_string) {
278 MOJO_COMPILE_ASSERT(sizeof(float) == 4, float_size_is_not_4);
280 float value;
281 if (sscanf(value_string.c_str(), "%f", &value) != 1)
282 return false;
284 AppendData(value);
285 return true;
288 bool ValidationTestInputParser::ParseDouble(const DataType& type,
289 const std::string& value_string) {
290 MOJO_COMPILE_ASSERT(sizeof(double) == 8, double_size_is_not_8);
292 double value;
293 if (sscanf(value_string.c_str(), "%lf", &value) != 1)
294 return false;
296 AppendData(value);
297 return true;
300 bool ValidationTestInputParser::ParseBinarySequence(
301 const DataType& type, const std::string& value_string) {
302 if (value_string.size() != 8)
303 return false;
305 uint8_t value = 0;
306 for (std::string::const_iterator iter = value_string.begin();
307 iter != value_string.end();
308 ++iter) {
309 value <<= 1;
310 if (*iter == '1')
311 value++;
312 else if (*iter != '0')
313 return false;
315 AppendData(value);
316 return true;
319 bool ValidationTestInputParser::ParseDistance(const DataType& type,
320 const std::string& value_string) {
321 if (pending_distance_items_.find(value_string) !=
322 pending_distance_items_.end())
323 return false;
325 PendingDistanceItem item = {data_->size(), type.data_size};
326 data_->resize(data_->size() + type.data_size);
327 pending_distance_items_[value_string] = item;
329 return true;
332 bool ValidationTestInputParser::ParseAnchor(const DataType& type,
333 const std::string& value_string) {
334 if (anchors_.find(value_string) != anchors_.end())
335 return false;
336 anchors_.insert(value_string);
338 std::map<std::string, PendingDistanceItem>::iterator iter =
339 pending_distance_items_.find(value_string);
340 if (iter == pending_distance_items_.end())
341 return false;
343 PendingDistanceItem dist_item = iter->second;
344 pending_distance_items_.erase(iter);
346 size_t distance = data_->size() - dist_item.pos;
347 switch (dist_item.data_size) {
348 case 4:
349 return ConvertAndFillData<uint32_t>(dist_item.pos, distance);
350 case 8:
351 return ConvertAndFillData<uint64_t>(dist_item.pos, distance);
352 default:
353 assert(false);
354 return false;
358 bool ValidationTestInputParser::ParseHandles(const DataType& type,
359 const std::string& value_string) {
360 // It should be the first item.
361 if (!data_->empty())
362 return false;
364 unsigned long long int value;
365 if (!ConvertToUnsignedInteger(value_string, &value))
366 return false;
368 if (value > std::numeric_limits<size_t>::max())
369 return false;
371 *num_handles_ = static_cast<size_t>(value);
372 return true;
375 bool ValidationTestInputParser::StartsWith(const Range& range,
376 const char* prefix,
377 size_t prefix_length) {
378 if (static_cast<size_t>(range.second - range.first) < prefix_length)
379 return false;
381 return memcmp(range.first, prefix, prefix_length) == 0;
384 bool ValidationTestInputParser::ConvertToUnsignedInteger(
385 const std::string& value_string,
386 unsigned long long int* value) {
387 const char* format = NULL;
388 if (value_string.find_first_of("xX") != std::string::npos)
389 format = "%llx";
390 else
391 format = "%llu";
392 return sscanf(value_string.c_str(), format, value) == 1;
395 } // namespace
397 bool ParseValidationTestInput(const std::string& input,
398 std::vector<uint8_t>* data,
399 size_t* num_handles,
400 std::string* error_message) {
401 ValidationTestInputParser parser(input, data, num_handles, error_message);
402 return parser.Run();
405 } // namespace test
406 } // namespace mojo