Home | History | Annotate | Download | only in tests
      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