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, const std::string& value_string); 39 40 struct DataType { 41 const char* name; 42 size_t name_size; 43 size_t data_size; 44 ParseDataFunc parse_data_func; 45 }; 46 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; 53 }; 54 55 bool GetNextItem(Range* range); 56 57 bool ParseItem(const Range& range); 58 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); 70 71 bool StartsWith(const Range& range, const char* prefix, size_t prefix_length); 72 73 bool ConvertToUnsignedInteger(const std::string& value_string, 74 unsigned long long int* value); 75 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)); 81 } 82 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; 88 } 89 AppendData(static_cast<TargetType>(value)); 90 return true; 91 } 92 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; 98 } 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; 103 } 104 105 static const DataType kDataTypes[]; 106 static const size_t kDataTypeCount; 107 108 const std::string& input_; 109 size_t input_cursor_; 110 111 std::vector<uint8_t>* data_; 112 size_t* num_handles_; 113 std::string* error_message_; 114 115 std::map<std::string, PendingDistanceItem> pending_distance_items_; 116 std::set<std::string> anchors_; 117 }; 118 119 #define DATA_TYPE(name, data_size, parse_data_func) \ 120 {name, sizeof(name) - 1, data_size, parse_data_func} 121 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) 139 }; 140 141 const size_t ValidationTestInputParser::kDataTypeCount = 142 sizeof(ValidationTestInputParser::kDataTypes) / 143 sizeof(ValidationTestInputParser::kDataTypes[0]); 144 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(); 161 } 162 163 ValidationTestInputParser::~ValidationTestInputParser() { 164 } 165 166 bool ValidationTestInputParser::Run() { 167 Range range; 168 bool result = true; 169 while (result && GetNextItem(&range)) 170 result = ParseItem(range); 171 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; 180 } 181 if (!result) { 182 data_->clear(); 183 *num_handles_ = 0; 184 } else { 185 assert(error_message_->empty()); 186 } 187 188 return result; 189 } 190 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_); 200 201 if (input_cursor_ >= input_.size()) 202 return false; 203 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; 215 } 216 } 217 return false; 218 } 219 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)); 226 } 227 } 228 229 // "[u1]" is optional. 230 return ParseUnsignedInteger(kDataTypes[0], 231 std::string(range.first, range.second)); 232 } 233 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; 239 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; 252 } 253 } 254 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; 260 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; 273 } 274 } 275 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); 279 280 float value; 281 if (sscanf(value_string.c_str(), "%f", &value) != 1) 282 return false; 283 284 AppendData(value); 285 return true; 286 } 287 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); 291 292 double value; 293 if (sscanf(value_string.c_str(), "%lf", &value) != 1) 294 return false; 295 296 AppendData(value); 297 return true; 298 } 299 300 bool ValidationTestInputParser::ParseBinarySequence( 301 const DataType& type, const std::string& value_string) { 302 if (value_string.size() != 8) 303 return false; 304 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; 314 } 315 AppendData(value); 316 return true; 317 } 318 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; 324 325 PendingDistanceItem item = {data_->size(), type.data_size}; 326 data_->resize(data_->size() + type.data_size); 327 pending_distance_items_[value_string] = item; 328 329 return true; 330 } 331 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); 337 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; 342 343 PendingDistanceItem dist_item = iter->second; 344 pending_distance_items_.erase(iter); 345 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; 355 } 356 } 357 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; 363 364 unsigned long long int value; 365 if (!ConvertToUnsignedInteger(value_string, &value)) 366 return false; 367 368 if (value > std::numeric_limits<size_t>::max()) 369 return false; 370 371 *num_handles_ = static_cast<size_t>(value); 372 return true; 373 } 374 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; 380 381 return memcmp(range.first, prefix, prefix_length) == 0; 382 } 383 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; 393 } 394 395 } // namespace 396 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(); 403 } 404 405 } // namespace test 406 } // namespace mojo 407