| 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 |