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