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.
5 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
16 #include "mojo/public/c/system/macros.h"
22 class ValidationTestInputParser
{
24 ValidationTestInputParser(const std::string
& input
,
25 std::vector
<uint8_t>* data
,
27 std::string
* error_message
);
28 ~ValidationTestInputParser();
35 typedef std::pair
<const char*, const char*> Range
;
37 typedef bool (ValidationTestInputParser::*ParseDataFunc
)(
38 const DataType
& type
, const std::string
& value_string
);
44 ParseDataFunc parse_data_func
;
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_|.
51 // Either 4 or 8 (bytes).
55 bool GetNextItem(Range
* range
);
57 bool ParseItem(const Range
& range
);
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
);
71 bool StartsWith(const Range
& range
, const char* prefix
, size_t prefix_length
);
73 bool ConvertToUnsignedInteger(const std::string
& value_string
,
74 unsigned long long int* value
);
77 void AppendData(T data
) {
78 size_t pos
= data_
->size();
79 data_
->resize(pos
+ sizeof(T
));
80 memcpy(&(*data_
)[pos
], &data
, sizeof(T
));
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()) {
89 AppendData(static_cast<TargetType
>(value
));
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()) {
99 TargetType target_value
= static_cast<TargetType
>(value
);
100 assert(pos
+ sizeof(TargetType
) <= data_
->size());
101 memcpy(&(*data_
)[pos
], &target_value
, sizeof(TargetType
));
105 static const DataType kDataTypes
[];
106 static const size_t kDataTypeCount
;
108 const std::string
& input_
;
109 size_t input_cursor_
;
111 std::vector
<uint8_t>* data_
;
112 size_t* num_handles_
;
113 std::string
* error_message_
;
115 std::map
<std::string
, PendingDistanceItem
> pending_distance_items_
;
116 std::set
<std::string
> anchors_
;
119 #define DATA_TYPE(name, data_size, parse_data_func) \
120 {name, sizeof(name) - 1, data_size, parse_data_func}
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
)
141 const size_t ValidationTestInputParser::kDataTypeCount
=
142 sizeof(ValidationTestInputParser::kDataTypes
) /
143 sizeof(ValidationTestInputParser::kDataTypes
[0]);
145 ValidationTestInputParser::ValidationTestInputParser(
146 const std::string
& input
,
147 std::vector
<uint8_t>* data
,
149 std::string
* error_message
)
153 num_handles_(num_handles
),
154 error_message_(error_message
) {
156 assert(num_handles_
);
157 assert(error_message_
);
160 error_message_
->clear();
163 ValidationTestInputParser::~ValidationTestInputParser() {
166 bool ValidationTestInputParser::Run() {
169 while (result
&& GetNextItem(&range
))
170 result
= ParseItem(range
);
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].";
185 assert(error_message_
->empty());
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";
196 // Skip leading whitespaces.
197 // If there are no non-whitespace characters left, |input_cursor_| will be
199 input_cursor_
= input_
.find_first_not_of(kWhitespaceChars
, input_cursor_
);
201 if (input_cursor_
>= input_
.size())
204 if (StartsWith(Range(&input_
[0] + input_cursor_
,
205 &input_
[0] + input_
.size()),
207 // Skip contents until the end of the line.
208 input_cursor_
= input_
.find_first_of(kEndOfLineChars
, input_cursor_
);
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_
;
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
)(
225 std::string(range
.first
+ kDataTypes
[i
].name_size
, range
.second
));
229 // "[u1]" is optional.
230 return ParseUnsignedInteger(kDataTypes
[0],
231 std::string(range
.first
, range
.second
));
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
))
240 switch (type
.data_size
) {
242 return ConvertAndAppendData
<uint8_t>(value
);
244 return ConvertAndAppendData
<uint16_t>(value
);
246 return ConvertAndAppendData
<uint32_t>(value
);
248 return ConvertAndAppendData
<uint64_t>(value
);
255 bool ValidationTestInputParser::ParseSignedInteger(
256 const DataType
& type
, const std::string
& value_string
) {
258 if (sscanf(value_string
.c_str(), "%lli", &value
) != 1)
261 switch (type
.data_size
) {
263 return ConvertAndAppendData
<int8_t>(value
);
265 return ConvertAndAppendData
<int16_t>(value
);
267 return ConvertAndAppendData
<int32_t>(value
);
269 return ConvertAndAppendData
<int64_t>(value
);
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
);
281 if (sscanf(value_string
.c_str(), "%f", &value
) != 1)
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
);
293 if (sscanf(value_string
.c_str(), "%lf", &value
) != 1)
300 bool ValidationTestInputParser::ParseBinarySequence(
301 const DataType
& type
, const std::string
& value_string
) {
302 if (value_string
.size() != 8)
306 for (std::string::const_iterator iter
= value_string
.begin();
307 iter
!= value_string
.end();
312 else if (*iter
!= '0')
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())
325 PendingDistanceItem item
= {data_
->size(), type
.data_size
};
326 data_
->resize(data_
->size() + type
.data_size
);
327 pending_distance_items_
[value_string
] = item
;
332 bool ValidationTestInputParser::ParseAnchor(const DataType
& type
,
333 const std::string
& value_string
) {
334 if (anchors_
.find(value_string
) != anchors_
.end())
336 anchors_
.insert(value_string
);
338 std::map
<std::string
, PendingDistanceItem
>::iterator iter
=
339 pending_distance_items_
.find(value_string
);
340 if (iter
== pending_distance_items_
.end())
343 PendingDistanceItem dist_item
= iter
->second
;
344 pending_distance_items_
.erase(iter
);
346 size_t distance
= data_
->size() - dist_item
.pos
;
347 switch (dist_item
.data_size
) {
349 return ConvertAndFillData
<uint32_t>(dist_item
.pos
, distance
);
351 return ConvertAndFillData
<uint64_t>(dist_item
.pos
, distance
);
358 bool ValidationTestInputParser::ParseHandles(const DataType
& type
,
359 const std::string
& value_string
) {
360 // It should be the first item.
364 unsigned long long int value
;
365 if (!ConvertToUnsignedInteger(value_string
, &value
))
368 if (value
> std::numeric_limits
<size_t>::max())
371 *num_handles_
= static_cast<size_t>(value
);
375 bool ValidationTestInputParser::StartsWith(const Range
& range
,
377 size_t prefix_length
) {
378 if (static_cast<size_t>(range
.second
- range
.first
) < prefix_length
)
381 return memcmp(range
.first
, prefix
, prefix_length
) == 0;
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
)
392 return sscanf(value_string
.c_str(), format
, value
) == 1;
397 bool ParseValidationTestInput(const std::string
& input
,
398 std::vector
<uint8_t>* data
,
400 std::string
* error_message
) {
401 ValidationTestInputParser
parser(input
, data
, num_handles
, error_message
);