• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
AppendData(T data)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>
ConvertAndAppendData(InputType value)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>
ConvertAndFillData(size_t pos,InputType value)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 
ValidationTestInputParser(const std::string & input,std::vector<uint8_t> * data,size_t * num_handles,std::string * error_message)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 
~ValidationTestInputParser()163 ValidationTestInputParser::~ValidationTestInputParser() {
164 }
165 
Run()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 
GetNextItem(Range * range)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 
ParseItem(const Range & range)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 
ParseUnsignedInteger(const DataType & type,const std::string & value_string)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 
ParseSignedInteger(const DataType & type,const std::string & value_string)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 
ParseFloat(const DataType & type,const std::string & value_string)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 
ParseDouble(const DataType & type,const std::string & value_string)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 
ParseBinarySequence(const DataType & type,const std::string & value_string)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 
ParseDistance(const DataType & type,const std::string & value_string)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 
ParseAnchor(const DataType & type,const std::string & value_string)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 
ParseHandles(const DataType & type,const std::string & value_string)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 
StartsWith(const Range & range,const char * prefix,size_t prefix_length)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 
ConvertToUnsignedInteger(const std::string & value_string,unsigned long long int * value)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 
ParseValidationTestInput(const std::string & input,std::vector<uint8_t> * data,size_t * num_handles,std::string * error_message)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