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