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