File: | usr/include/boost/algorithm/string/detail/classification.hpp |
Warning: | line 141, column 17 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | // Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC") | |||
2 | // | |||
3 | // This Source Code Form is subject to the terms of the Mozilla Public | |||
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this | |||
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
6 | ||||
7 | #include <config.h> | |||
8 | ||||
9 | #include <dhcp/dhcp4.h> | |||
10 | #include <dhcp/dhcp6.h> | |||
11 | #include <dhcp/option4_addrlst.h> | |||
12 | #include <dhcp/option4_client_fqdn.h> | |||
13 | #include <dhcp/option4_dnr.h> | |||
14 | #include <dhcp/option6_addrlst.h> | |||
15 | #include <dhcp/option6_client_fqdn.h> | |||
16 | #include <dhcp/option6_dnr.h> | |||
17 | #include <dhcp/option6_ia.h> | |||
18 | #include <dhcp/option6_iaaddr.h> | |||
19 | #include <dhcp/option6_iaprefix.h> | |||
20 | #include <dhcp/option6_pdexclude.h> | |||
21 | #include <dhcp/option6_status_code.h> | |||
22 | #include <dhcp/option_custom.h> | |||
23 | #include <dhcp/option_definition.h> | |||
24 | #include <dhcp/option_int.h> | |||
25 | #include <dhcp/option_int_array.h> | |||
26 | #include <dhcp/option_opaque_data_tuples.h> | |||
27 | #include <dhcp/option_classless_static_route.h> | |||
28 | #include <dhcp/option_string.h> | |||
29 | #include <dhcp/option_vendor.h> | |||
30 | #include <dhcp/option_vendor_class.h> | |||
31 | #include <util/encode/encode.h> | |||
32 | #include <dns/labelsequence.h> | |||
33 | #include <dns/name.h> | |||
34 | #include <util/str.h> | |||
35 | #include <boost/algorithm/string/classification.hpp> | |||
36 | #include <boost/algorithm/string/predicate.hpp> | |||
37 | #include <boost/algorithm/string/replace.hpp> | |||
38 | #include <boost/dynamic_bitset.hpp> | |||
39 | #include <boost/make_shared.hpp> | |||
40 | #include <sstream> | |||
41 | ||||
42 | using namespace std; | |||
43 | using namespace isc::util; | |||
44 | ||||
45 | namespace isc { | |||
46 | namespace dhcp { | |||
47 | ||||
48 | OptionDefinition::OptionDefinition(const std::string& name, | |||
49 | const uint16_t code, | |||
50 | const std::string& space, | |||
51 | const std::string& type, | |||
52 | const bool array_type /* = false */) | |||
53 | : name_(name), | |||
54 | code_(code), | |||
55 | type_(OPT_UNKNOWN_TYPE), | |||
56 | array_type_(array_type), | |||
57 | encapsulated_space_(""), | |||
58 | record_fields_(), | |||
59 | user_context_(), | |||
60 | option_space_name_(space) { | |||
61 | // Data type is held as enum value by this class. | |||
62 | // Use the provided option type string to get the | |||
63 | // corresponding enum value. | |||
64 | type_ = OptionDataTypeUtil::getDataType(type); | |||
65 | } | |||
66 | ||||
67 | OptionDefinition::OptionDefinition(const std::string& name, | |||
68 | const uint16_t code, | |||
69 | const std::string& space, | |||
70 | const OptionDataType type, | |||
71 | const bool array_type /* = false */) | |||
72 | : name_(name), | |||
73 | code_(code), | |||
74 | type_(type), | |||
75 | array_type_(array_type), | |||
76 | encapsulated_space_(""), | |||
77 | option_space_name_(space){ | |||
78 | } | |||
79 | ||||
80 | OptionDefinition::OptionDefinition(const std::string& name, | |||
81 | const uint16_t code, | |||
82 | const std::string& space, | |||
83 | const std::string& type, | |||
84 | const char* encapsulated_space) | |||
85 | : name_(name), | |||
86 | code_(code), | |||
87 | // Data type is held as enum value by this class. | |||
88 | // Use the provided option type string to get the | |||
89 | // corresponding enum value. | |||
90 | type_(OptionDataTypeUtil::getDataType(type)), | |||
91 | array_type_(false), | |||
92 | encapsulated_space_(encapsulated_space), | |||
93 | record_fields_(), | |||
94 | user_context_(), | |||
95 | option_space_name_(space) { | |||
96 | } | |||
97 | ||||
98 | OptionDefinition::OptionDefinition(const std::string& name, | |||
99 | const uint16_t code, | |||
100 | const std::string& space, | |||
101 | const OptionDataType type, | |||
102 | const char* encapsulated_space) | |||
103 | : name_(name), | |||
104 | code_(code), | |||
105 | type_(type), | |||
106 | array_type_(false), | |||
107 | encapsulated_space_(encapsulated_space), | |||
108 | record_fields_(), | |||
109 | user_context_(), | |||
110 | option_space_name_(space) { | |||
111 | } | |||
112 | ||||
113 | OptionDefinitionPtr | |||
114 | OptionDefinition::create(const std::string& name, | |||
115 | const uint16_t code, | |||
116 | const std::string& space, | |||
117 | const std::string& type, | |||
118 | const bool array_type) { | |||
119 | return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type)); | |||
120 | } | |||
121 | ||||
122 | OptionDefinitionPtr | |||
123 | OptionDefinition::create(const std::string& name, | |||
124 | const uint16_t code, | |||
125 | const std::string& space, | |||
126 | const OptionDataType type, | |||
127 | const bool array_type) { | |||
128 | return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type)); | |||
129 | } | |||
130 | ||||
131 | OptionDefinitionPtr | |||
132 | OptionDefinition::create(const std::string& name, | |||
133 | const uint16_t code, | |||
134 | const std::string& space, | |||
135 | const std::string& type, | |||
136 | const char* encapsulated_space) { | |||
137 | return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space)); | |||
138 | } | |||
139 | ||||
140 | OptionDefinitionPtr | |||
141 | OptionDefinition::create(const std::string& name, | |||
142 | const uint16_t code, | |||
143 | const std::string& space, | |||
144 | const OptionDataType type, | |||
145 | const char* encapsulated_space) { | |||
146 | return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space)); | |||
147 | } | |||
148 | ||||
149 | bool | |||
150 | OptionDefinition::equals(const OptionDefinition& other) const { | |||
151 | return (name_ == other.name_ && | |||
152 | code_ == other.code_ && | |||
153 | type_ == other.type_ && | |||
154 | array_type_ == other.array_type_ && | |||
155 | encapsulated_space_ == other.encapsulated_space_ && | |||
156 | record_fields_ == other.record_fields_ && | |||
157 | option_space_name_ == other.option_space_name_); | |||
158 | } | |||
159 | ||||
160 | void | |||
161 | OptionDefinition::addRecordField(const std::string& data_type_name) { | |||
162 | OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name); | |||
163 | addRecordField(data_type); | |||
164 | } | |||
165 | ||||
166 | void | |||
167 | OptionDefinition::addRecordField(const OptionDataType data_type) { | |||
168 | if (type_ != OPT_RECORD_TYPE) { | |||
169 | isc_throw(isc::InvalidOperation,do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '" << OptionDataTypeUtil::getDataTypeName(type_) << "' to add data fields to the record"; throw isc::InvalidOperation ("option_definition.cc", 172, oss__.str().c_str()); } while ( 1) | |||
170 | "'record' option type must be used instead of '"do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '" << OptionDataTypeUtil::getDataTypeName(type_) << "' to add data fields to the record"; throw isc::InvalidOperation ("option_definition.cc", 172, oss__.str().c_str()); } while ( 1) | |||
171 | << OptionDataTypeUtil::getDataTypeName(type_)do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '" << OptionDataTypeUtil::getDataTypeName(type_) << "' to add data fields to the record"; throw isc::InvalidOperation ("option_definition.cc", 172, oss__.str().c_str()); } while ( 1) | |||
172 | << "' to add data fields to the record")do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '" << OptionDataTypeUtil::getDataTypeName(type_) << "' to add data fields to the record"; throw isc::InvalidOperation ("option_definition.cc", 172, oss__.str().c_str()); } while ( 1); | |||
173 | } | |||
174 | if (data_type >= OPT_RECORD_TYPE || | |||
175 | data_type == OPT_ANY_ADDRESS_TYPE || | |||
176 | data_type == OPT_EMPTY_TYPE) { | |||
177 | isc_throw(isc::BadValue,do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '" << OptionDataTypeUtil::getDataTypeName(data_type) << "' to the record."; throw isc::BadValue("option_definition.cc" , 180, oss__.str().c_str()); } while (1) | |||
178 | "attempted to add invalid data type '"do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '" << OptionDataTypeUtil::getDataTypeName(data_type) << "' to the record."; throw isc::BadValue("option_definition.cc" , 180, oss__.str().c_str()); } while (1) | |||
179 | << OptionDataTypeUtil::getDataTypeName(data_type)do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '" << OptionDataTypeUtil::getDataTypeName(data_type) << "' to the record."; throw isc::BadValue("option_definition.cc" , 180, oss__.str().c_str()); } while (1) | |||
180 | << "' to the record.")do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '" << OptionDataTypeUtil::getDataTypeName(data_type) << "' to the record."; throw isc::BadValue("option_definition.cc" , 180, oss__.str().c_str()); } while (1); | |||
181 | } | |||
182 | record_fields_.push_back(data_type); | |||
183 | } | |||
184 | ||||
185 | OptionPtr | |||
186 | OptionDefinition::optionFactory(Option::Universe u, | |||
187 | uint16_t type, | |||
188 | OptionBufferConstIter begin, | |||
189 | OptionBufferConstIter end, | |||
190 | bool convenient_notation) const { | |||
191 | ||||
192 | try { | |||
193 | // Some of the options are represented by the specialized classes derived | |||
194 | // from Option class (e.g. IA_NA, IAADDR). Although, they can be also | |||
195 | // represented by the generic classes, we want the object of the specialized | |||
196 | // type to be returned. Therefore, we first check that if we are dealing | |||
197 | // with such an option. If the instance is returned we just exit at this | |||
198 | // point. If not, we will search for a generic option type to return. | |||
199 | OptionPtr option = factorySpecialFormatOption(u, begin, end, convenient_notation); | |||
200 | if (option) { | |||
201 | return (option); | |||
202 | } | |||
203 | ||||
204 | switch (type_) { | |||
205 | case OPT_EMPTY_TYPE: | |||
206 | if (getEncapsulatedSpace().empty()) { | |||
207 | return (factoryEmpty(u, type)); | |||
208 | } else { | |||
209 | return (OptionPtr(new OptionCustom(*this, u, begin, end))); | |||
210 | } | |||
211 | ||||
212 | case OPT_BINARY_TYPE: | |||
213 | // If this is Internal type, and it wasn't handled by factorySpecialFormatOption() before, | |||
214 | // let's treat it like normal Binary type. | |||
215 | case OPT_INTERNAL_TYPE: | |||
216 | return (factoryGeneric(u, type, begin, end)); | |||
217 | ||||
218 | case OPT_UINT8_TYPE: | |||
219 | return (array_type_ ? | |||
220 | factoryIntegerArray<uint8_t>(u, type, begin, end) : | |||
221 | factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(), | |||
222 | begin, end)); | |||
223 | ||||
224 | case OPT_INT8_TYPE: | |||
225 | return (array_type_ ? | |||
226 | factoryIntegerArray<int8_t>(u, type, begin, end) : | |||
227 | factoryInteger<int8_t>(u, type, getEncapsulatedSpace(), | |||
228 | begin, end)); | |||
229 | ||||
230 | case OPT_UINT16_TYPE: | |||
231 | return (array_type_ ? | |||
232 | factoryIntegerArray<uint16_t>(u, type, begin, end) : | |||
233 | factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(), | |||
234 | begin, end)); | |||
235 | ||||
236 | case OPT_INT16_TYPE: | |||
237 | return (array_type_ ? | |||
238 | factoryIntegerArray<uint16_t>(u, type, begin, end) : | |||
239 | factoryInteger<int16_t>(u, type, getEncapsulatedSpace(), | |||
240 | begin, end)); | |||
241 | ||||
242 | case OPT_UINT32_TYPE: | |||
243 | return (array_type_ ? | |||
244 | factoryIntegerArray<uint32_t>(u, type, begin, end) : | |||
245 | factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(), | |||
246 | begin, end)); | |||
247 | ||||
248 | case OPT_INT32_TYPE: | |||
249 | return (array_type_ ? | |||
250 | factoryIntegerArray<uint32_t>(u, type, begin, end) : | |||
251 | factoryInteger<int32_t>(u, type, getEncapsulatedSpace(), | |||
252 | begin, end)); | |||
253 | ||||
254 | case OPT_IPV4_ADDRESS_TYPE: | |||
255 | // If definition specifies that an option is an array | |||
256 | // of IPv4 addresses we return an instance of specialized | |||
257 | // class (OptionAddrLst4). For non-array types there is no | |||
258 | // specialized class yet implemented so we drop through | |||
259 | // to return an instance of OptionCustom. | |||
260 | if (array_type_) { | |||
261 | return (factoryAddrList4(type, begin, end)); | |||
262 | } | |||
263 | break; | |||
264 | ||||
265 | case OPT_IPV6_ADDRESS_TYPE: | |||
266 | // Handle array type only here (see comments for | |||
267 | // OPT_IPV4_ADDRESS_TYPE case). | |||
268 | if (array_type_) { | |||
269 | return (factoryAddrList6(type, begin, end)); | |||
270 | } | |||
271 | break; | |||
272 | ||||
273 | case OPT_STRING_TYPE: | |||
274 | return (OptionPtr(new OptionString(u, type, begin, end))); | |||
275 | ||||
276 | case OPT_TUPLE_TYPE: | |||
277 | // Handle array type only here (see comments for | |||
278 | // OPT_IPV4_ADDRESS_TYPE case). | |||
279 | if (array_type_) { | |||
280 | return (factoryOpaqueDataTuples(u, type, begin, end)); | |||
281 | } | |||
282 | break; | |||
283 | ||||
284 | default: | |||
285 | // Do nothing. We will return generic option a few lines down. | |||
286 | ; | |||
287 | } | |||
288 | return (OptionPtr(new OptionCustom(*this, u, begin, end))); | |||
289 | } catch (const SkipThisOptionError&) { | |||
290 | // We need to throw this one as is. | |||
291 | throw; | |||
292 | } catch (const SkipRemainingOptionsError&) { | |||
293 | // We need to throw this one as is. | |||
294 | throw; | |||
295 | } catch (const Exception& ex) { | |||
296 | isc_throw(InvalidOptionValue, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw InvalidOptionValue("option_definition.cc", 296, oss__.str(). c_str()); } while (1); | |||
297 | } | |||
298 | } | |||
299 | ||||
300 | OptionPtr | |||
301 | OptionDefinition::optionFactory(Option::Universe u, uint16_t type, | |||
302 | const OptionBuffer& buf) const { | |||
303 | return (optionFactory(u, type, buf.begin(), buf.end())); | |||
304 | } | |||
305 | ||||
306 | OptionPtr | |||
307 | OptionDefinition::optionFactory(Option::Universe u, uint16_t type, | |||
308 | const std::vector<std::string>& values) const { | |||
309 | OptionBuffer buf; | |||
310 | if (!array_type_ && type_ != OPT_RECORD_TYPE) { | |||
311 | if (values.empty()) { | |||
312 | if (type_ != OPT_EMPTY_TYPE) { | |||
313 | isc_throw(InvalidOptionValue, "no option value specified")do { std::ostringstream oss__; oss__ << "no option value specified" ; throw InvalidOptionValue("option_definition.cc", 313, oss__ .str().c_str()); } while (1); | |||
314 | } | |||
315 | } else if (type_ == OPT_INTERNAL_TYPE) { | |||
316 | // If an Option of type Internal is configured using csv-format=true, it means it is | |||
317 | // convenient notation option config that needs special parsing. Let's treat it like | |||
318 | // String type. optionFactory() will be called with convenient_notation flag set to | |||
319 | // true, so that the factory will have a chance to handle it in a special way. | |||
320 | ||||
321 | // At this stage any escape backslash chars were lost during last call of | |||
322 | // isc::util::str::tokens() inside of | |||
323 | // OptionDataParser::createOption(ConstElementPtr option_data), so we must | |||
324 | // restore them. Some INTERNAL options may use escaped delimiters, e.g. DNR options. | |||
325 | // Values are concatenated back to comma separated format and will be written to | |||
326 | // the OptionBuffer as one String type option. | |||
327 | std::ostringstream stream; | |||
328 | bool first = true; | |||
329 | for (auto val : values) { | |||
330 | boost::algorithm::replace_all(val, ",", "\\,"); | |||
331 | if (first) { | |||
332 | first = false; | |||
333 | } else { | |||
334 | stream << ","; | |||
335 | } | |||
336 | ||||
337 | stream << val; | |||
338 | } | |||
339 | ||||
340 | writeToBuffer(u, stream.str(), OPT_STRING_TYPE, buf); | |||
341 | } else { | |||
342 | writeToBuffer(u, util::str::trim(values[0]), type_, buf); | |||
343 | } | |||
344 | } else if (array_type_ && type_ != OPT_RECORD_TYPE) { | |||
345 | for (size_t i = 0; i < values.size(); ++i) { | |||
346 | writeToBuffer(u, util::str::trim(values[i]), type_, buf); | |||
347 | } | |||
348 | } else if (type_ == OPT_RECORD_TYPE) { | |||
349 | const RecordFieldsCollection& records = getRecordFields(); | |||
350 | if (records.size() > values.size()) { | |||
351 | isc_throw(InvalidOptionValue, "number of data fields for the option"do { std::ostringstream oss__; oss__ << "number of data fields for the option" << " type '" << getCode() << "' is greater than number" << " of values provided."; throw InvalidOptionValue("option_definition.cc" , 353, oss__.str().c_str()); } while (1) | |||
352 | << " type '" << getCode() << "' is greater than number"do { std::ostringstream oss__; oss__ << "number of data fields for the option" << " type '" << getCode() << "' is greater than number" << " of values provided."; throw InvalidOptionValue("option_definition.cc" , 353, oss__.str().c_str()); } while (1) | |||
353 | << " of values provided.")do { std::ostringstream oss__; oss__ << "number of data fields for the option" << " type '" << getCode() << "' is greater than number" << " of values provided."; throw InvalidOptionValue("option_definition.cc" , 353, oss__.str().c_str()); } while (1); | |||
354 | } | |||
355 | for (size_t i = 0; i < records.size(); ++i) { | |||
356 | writeToBuffer(u, util::str::trim(values[i]), records[i], buf); | |||
357 | } | |||
358 | if (array_type_ && (values.size() > records.size())) { | |||
359 | for (size_t i = records.size(); i < values.size(); ++i) { | |||
360 | writeToBuffer(u, util::str::trim(values[i]), | |||
361 | records.back(), buf); | |||
362 | } | |||
363 | } | |||
364 | } | |||
365 | return (optionFactory(u, type, buf.begin(), buf.end(), (type_ == OPT_INTERNAL_TYPE))); | |||
366 | } | |||
367 | ||||
368 | void | |||
369 | OptionDefinition::validate() const { | |||
370 | ||||
371 | using namespace boost::algorithm; | |||
372 | ||||
373 | std::ostringstream err_str; | |||
374 | ||||
375 | // Allowed characters in the option name are: lower or | |||
376 | // upper case letters, digits, underscores and hyphens. | |||
377 | // Empty option spaces are not allowed. | |||
378 | if (!all(name_, boost::is_from_range('a', 'z') || | |||
| ||||
379 | boost::is_from_range('A', 'Z') || | |||
380 | boost::is_digit() || | |||
381 | boost::is_any_of(std::string("-_"))) || | |||
382 | name_.empty() || | |||
383 | // Hyphens and underscores are not allowed at the beginning | |||
384 | // and at the end of the option name. | |||
385 | all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) || | |||
386 | all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) { | |||
387 | err_str << "invalid option name '" << name_ << "'"; | |||
388 | ||||
389 | } else if (!OptionSpace::validateName(option_space_name_)) { | |||
390 | err_str << "invalid option space name: '" | |||
391 | << option_space_name_ << "'"; | |||
392 | ||||
393 | } else if (!encapsulated_space_.empty() && | |||
394 | !OptionSpace::validateName(encapsulated_space_)) { | |||
395 | err_str << "invalid encapsulated option space name: '" | |||
396 | << encapsulated_space_ << "'"; | |||
397 | ||||
398 | } else if (type_ >= OPT_UNKNOWN_TYPE) { | |||
399 | // Option definition must be of a known type. | |||
400 | err_str << "option type " << type_ << " not supported."; | |||
401 | ||||
402 | } else if (type_ == OPT_RECORD_TYPE) { | |||
403 | // At least two data fields should be added to the record. Otherwise | |||
404 | // non-record option definition could be used. | |||
405 | if (getRecordFields().size() < 2) { | |||
406 | err_str << "invalid number of data fields: " | |||
407 | << getRecordFields().size() | |||
408 | << " specified for the option of type 'record'. Expected at" | |||
409 | << " least 2 fields."; | |||
410 | ||||
411 | } else { | |||
412 | // If the number of fields is valid we have to check if their order | |||
413 | // is valid too. We check that string or binary data fields are not | |||
414 | // laid before other fields. But we allow that they are laid at the | |||
415 | // end of an option. | |||
416 | const RecordFieldsCollection& fields = getRecordFields(); | |||
417 | for (RecordFieldsConstIter it = fields.begin(); | |||
418 | it != fields.end(); ++it) { | |||
419 | if (*it == OPT_STRING_TYPE && | |||
420 | it < fields.end() - 1) { | |||
421 | err_str << "string data field can't be laid before data" | |||
422 | << " fields of other types."; | |||
423 | break; | |||
424 | } | |||
425 | if (*it == OPT_BINARY_TYPE && | |||
426 | it < fields.end() - 1) { | |||
427 | err_str << "binary data field can't be laid before data" | |||
428 | << " fields of other types."; | |||
429 | break; | |||
430 | } | |||
431 | // Empty type is not allowed within a record. | |||
432 | if (*it == OPT_EMPTY_TYPE) { | |||
433 | err_str << "empty data type can't be stored as a field in" | |||
434 | << " an option record."; | |||
435 | break; | |||
436 | } | |||
437 | // Internal type is not allowed within a record. | |||
438 | if (*it == OPT_INTERNAL_TYPE) { | |||
439 | err_str << "internal data type can't be stored as a field in" | |||
440 | << " an option record."; | |||
441 | break; | |||
442 | } | |||
443 | } | |||
444 | // If the array flag is set the last field is an array. | |||
445 | if (err_str.str().empty() && array_type_) { | |||
446 | const OptionDataType& last_type = fields.back(); | |||
447 | if (last_type == OPT_STRING_TYPE) { | |||
448 | err_str | |||
449 | << "array of strings is not a valid option definition."; | |||
450 | } else if (last_type == OPT_BINARY_TYPE) { | |||
451 | err_str << "array of binary values is not a valid option " | |||
452 | "definition."; | |||
453 | } | |||
454 | // Empty type was already checked. | |||
455 | } | |||
456 | } | |||
457 | ||||
458 | } else if (array_type_) { | |||
459 | if (type_ == OPT_STRING_TYPE) { | |||
460 | // Array of strings is not allowed because there is no way | |||
461 | // to determine the size of a particular string and thus there | |||
462 | // it no way to tell when other data fields begin. | |||
463 | err_str << "array of strings is not a valid option definition."; | |||
464 | } else if (type_ == OPT_BINARY_TYPE) { | |||
465 | err_str << "array of binary values is not" | |||
466 | << " a valid option definition."; | |||
467 | ||||
468 | } else if (type_ == OPT_EMPTY_TYPE) { | |||
469 | err_str << "array of empty value is not" | |||
470 | << " a valid option definition."; | |||
471 | ||||
472 | } else if (type_ == OPT_INTERNAL_TYPE) { | |||
473 | err_str << "array of internal type value is not" | |||
474 | << " a valid option definition."; | |||
475 | ||||
476 | } | |||
477 | } | |||
478 | ||||
479 | // Non-empty error string means that we have hit the error. We throw | |||
480 | // exception and include error string. | |||
481 | if (!err_str.str().empty()) { | |||
482 | isc_throw(MalformedOptionDefinition, err_str.str())do { std::ostringstream oss__; oss__ << err_str.str(); throw MalformedOptionDefinition("option_definition.cc", 482, oss__ .str().c_str()); } while (1); | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | bool | |||
487 | OptionDefinition::haveCompressedFqdnListFormat() const { | |||
488 | return (haveType(OPT_FQDN_TYPE) && getArrayType()); | |||
489 | } | |||
490 | ||||
491 | bool | |||
492 | OptionDefinition::convertToBool(const std::string& value_str) const { | |||
493 | // Case-insensitive check that the input is one of: "true" or "false". | |||
494 | if (boost::iequals(value_str, "true")) { | |||
495 | return (true); | |||
496 | ||||
497 | } else if (boost::iequals(value_str, "false")) { | |||
498 | return (false); | |||
499 | ||||
500 | } | |||
501 | ||||
502 | // The input string is neither "true" nor "false", so let's check | |||
503 | // if it is not an integer wrapped in a string. | |||
504 | int result; | |||
505 | try { | |||
506 | result = boost::lexical_cast<int>(value_str); | |||
507 | ||||
508 | } catch (const boost::bad_lexical_cast&) { | |||
509 | isc_throw(BadDataTypeCast, "unable to covert the value '"do { std::ostringstream oss__; oss__ << "unable to covert the value '" << value_str << "' to boolean data type"; throw BadDataTypeCast ("option_definition.cc", 510, oss__.str().c_str()); } while ( 1) | |||
510 | << value_str << "' to boolean data type")do { std::ostringstream oss__; oss__ << "unable to covert the value '" << value_str << "' to boolean data type"; throw BadDataTypeCast ("option_definition.cc", 510, oss__.str().c_str()); } while ( 1); | |||
511 | } | |||
512 | // The boolean value is encoded in DHCP option as 0 or 1. Therefore, | |||
513 | // we only allow a user to specify those values for options which | |||
514 | // have boolean fields. | |||
515 | if (result != 1 && result != 0) { | |||
516 | isc_throw(BadDataTypeCast, "unable to convert '" << value_strdo { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to boolean data type"; throw BadDataTypeCast ("option_definition.cc", 517, oss__.str().c_str()); } while ( 1) | |||
517 | << "' to boolean data type")do { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to boolean data type"; throw BadDataTypeCast ("option_definition.cc", 517, oss__.str().c_str()); } while ( 1); | |||
518 | } | |||
519 | return (static_cast<bool>(result)); | |||
520 | } | |||
521 | ||||
522 | template<typename T> | |||
523 | T | |||
524 | OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str) | |||
525 | const { | |||
526 | // The lexical cast should be attempted when converting to an integer | |||
527 | // value only. | |||
528 | if (!OptionDataTypeTraits<T>::integer_type) { | |||
529 | isc_throw(BadDataTypeCast,do { std::ostringstream oss__; oss__ << "must not convert '" << value_str << "' to non-integer data type"; throw BadDataTypeCast("option_definition.cc", 531, oss__.str().c_str ()); } while (1) | |||
530 | "must not convert '" << value_strdo { std::ostringstream oss__; oss__ << "must not convert '" << value_str << "' to non-integer data type"; throw BadDataTypeCast("option_definition.cc", 531, oss__.str().c_str ()); } while (1) | |||
531 | << "' to non-integer data type")do { std::ostringstream oss__; oss__ << "must not convert '" << value_str << "' to non-integer data type"; throw BadDataTypeCast("option_definition.cc", 531, oss__.str().c_str ()); } while (1); | |||
532 | } | |||
533 | ||||
534 | // We use the 64-bit value here because it has wider range than | |||
535 | // any other type we use here and it allows to detect out of | |||
536 | // bounds conditions e.g. negative value specified for uintX_t | |||
537 | // data type. Obviously if the value exceeds the limits of int64 | |||
538 | // this function will not handle that properly. | |||
539 | int64_t result = 0; | |||
540 | try { | |||
541 | result = boost::lexical_cast<int64_t>(value_str); | |||
542 | ||||
543 | } catch (const boost::bad_lexical_cast&) { | |||
544 | // boost::lexical_cast does not handle hexadecimal | |||
545 | // but stringstream does so do it the hard way. | |||
546 | std::stringstream ss; | |||
547 | ss << std::hex << value_str; | |||
548 | ss >> result; | |||
549 | if (ss.fail() || !ss.eof()) { | |||
550 | isc_throw(BadDataTypeCast, "unable to convert the value '"do { std::ostringstream oss__; oss__ << "unable to convert the value '" << value_str << "' to integer data type"; throw BadDataTypeCast ("option_definition.cc", 551, oss__.str().c_str()); } while ( 1) | |||
551 | << value_str << "' to integer data type")do { std::ostringstream oss__; oss__ << "unable to convert the value '" << value_str << "' to integer data type"; throw BadDataTypeCast ("option_definition.cc", 551, oss__.str().c_str()); } while ( 1); | |||
552 | } | |||
553 | } | |||
554 | // Perform range checks. | |||
555 | if (OptionDataTypeTraits<T>::integer_type) { | |||
556 | if (result > numeric_limits<T>::max() || | |||
557 | result < numeric_limits<T>::min()) { | |||
558 | isc_throw(BadDataTypeCast, "unable to convert '"do { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to numeric type. This value is " "expected to be in the range of " << +numeric_limits< T>::min() << ".." << +numeric_limits<T>:: max(); throw BadDataTypeCast("option_definition.cc", 562, oss__ .str().c_str()); } while (1) | |||
559 | << value_str << "' to numeric type. This value is "do { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to numeric type. This value is " "expected to be in the range of " << +numeric_limits< T>::min() << ".." << +numeric_limits<T>:: max(); throw BadDataTypeCast("option_definition.cc", 562, oss__ .str().c_str()); } while (1) | |||
560 | "expected to be in the range of "do { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to numeric type. This value is " "expected to be in the range of " << +numeric_limits< T>::min() << ".." << +numeric_limits<T>:: max(); throw BadDataTypeCast("option_definition.cc", 562, oss__ .str().c_str()); } while (1) | |||
561 | << +numeric_limits<T>::min() << ".."do { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to numeric type. This value is " "expected to be in the range of " << +numeric_limits< T>::min() << ".." << +numeric_limits<T>:: max(); throw BadDataTypeCast("option_definition.cc", 562, oss__ .str().c_str()); } while (1) | |||
562 | << +numeric_limits<T>::max())do { std::ostringstream oss__; oss__ << "unable to convert '" << value_str << "' to numeric type. This value is " "expected to be in the range of " << +numeric_limits< T>::min() << ".." << +numeric_limits<T>:: max(); throw BadDataTypeCast("option_definition.cc", 562, oss__ .str().c_str()); } while (1); | |||
563 | } | |||
564 | } | |||
565 | return (static_cast<T>(result)); | |||
566 | } | |||
567 | ||||
568 | void | |||
569 | OptionDefinition::writeToBuffer(Option::Universe u, | |||
570 | const std::string& value, | |||
571 | const OptionDataType type, | |||
572 | OptionBuffer& buf) const { | |||
573 | // We are going to write value given by value argument to the buffer. | |||
574 | // The actual type of the value is given by second argument. Check | |||
575 | // this argument to determine how to write this value to the buffer. | |||
576 | switch (type) { | |||
577 | case OPT_BINARY_TYPE: | |||
578 | OptionDataTypeUtil::writeBinary(value, buf); | |||
579 | return; | |||
580 | case OPT_BOOLEAN_TYPE: | |||
581 | // We encode the true value as 1 and false as 0 on 8 bits. | |||
582 | // That way we actually waste 7 bits but it seems to be the | |||
583 | // simpler way to encode boolean. | |||
584 | // @todo Consider if any other encode methods can be used. | |||
585 | OptionDataTypeUtil::writeBool(convertToBool(value), buf); | |||
586 | return; | |||
587 | case OPT_INT8_TYPE: | |||
588 | OptionDataTypeUtil::writeInt<uint8_t> | |||
589 | (lexicalCastWithRangeCheck<int8_t>(value), | |||
590 | buf); | |||
591 | return; | |||
592 | case OPT_INT16_TYPE: | |||
593 | OptionDataTypeUtil::writeInt<uint16_t> | |||
594 | (lexicalCastWithRangeCheck<int16_t>(value), | |||
595 | buf); | |||
596 | return; | |||
597 | case OPT_INT32_TYPE: | |||
598 | OptionDataTypeUtil::writeInt<uint32_t> | |||
599 | (lexicalCastWithRangeCheck<int32_t>(value), | |||
600 | buf); | |||
601 | return; | |||
602 | case OPT_UINT8_TYPE: | |||
603 | OptionDataTypeUtil::writeInt<uint8_t> | |||
604 | (lexicalCastWithRangeCheck<uint8_t>(value), | |||
605 | buf); | |||
606 | return; | |||
607 | case OPT_UINT16_TYPE: | |||
608 | OptionDataTypeUtil::writeInt<uint16_t> | |||
609 | (lexicalCastWithRangeCheck<uint16_t>(value), | |||
610 | buf); | |||
611 | return; | |||
612 | case OPT_UINT32_TYPE: | |||
613 | OptionDataTypeUtil::writeInt<uint32_t> | |||
614 | (lexicalCastWithRangeCheck<uint32_t>(value), | |||
615 | buf); | |||
616 | return; | |||
617 | case OPT_IPV4_ADDRESS_TYPE: | |||
618 | case OPT_IPV6_ADDRESS_TYPE: | |||
619 | { | |||
620 | asiolink::IOAddress address(value); | |||
621 | if (!address.isV4() && !address.isV6()) { | |||
622 | isc_throw(BadDataTypeCast, "provided address "do { std::ostringstream oss__; oss__ << "provided address " << address << " is not a valid IPv4 or IPv6 address." ; throw BadDataTypeCast("option_definition.cc", 624, oss__.str ().c_str()); } while (1) | |||
623 | << addressdo { std::ostringstream oss__; oss__ << "provided address " << address << " is not a valid IPv4 or IPv6 address." ; throw BadDataTypeCast("option_definition.cc", 624, oss__.str ().c_str()); } while (1) | |||
624 | << " is not a valid IPv4 or IPv6 address.")do { std::ostringstream oss__; oss__ << "provided address " << address << " is not a valid IPv4 or IPv6 address." ; throw BadDataTypeCast("option_definition.cc", 624, oss__.str ().c_str()); } while (1); | |||
625 | } | |||
626 | OptionDataTypeUtil::writeAddress(address, buf); | |||
627 | return; | |||
628 | } | |||
629 | case OPT_IPV6_PREFIX_TYPE: | |||
630 | { | |||
631 | std::string txt = value; | |||
632 | ||||
633 | // first let's remove any whitespaces | |||
634 | boost::erase_all(txt, " "); // space | |||
635 | boost::erase_all(txt, "\t"); // tabulation | |||
636 | ||||
637 | // Is this prefix/len notation? | |||
638 | size_t pos = txt.find("/"); | |||
639 | ||||
640 | if (pos == string::npos) { | |||
641 | isc_throw(BadDataTypeCast, "provided address/prefix "do { std::ostringstream oss__; oss__ << "provided address/prefix " << value << " is not valid."; throw BadDataTypeCast ("option_definition.cc", 643, oss__.str().c_str()); } while ( 1) | |||
642 | << valuedo { std::ostringstream oss__; oss__ << "provided address/prefix " << value << " is not valid."; throw BadDataTypeCast ("option_definition.cc", 643, oss__.str().c_str()); } while ( 1) | |||
643 | << " is not valid.")do { std::ostringstream oss__; oss__ << "provided address/prefix " << value << " is not valid."; throw BadDataTypeCast ("option_definition.cc", 643, oss__.str().c_str()); } while ( 1); | |||
644 | } | |||
645 | ||||
646 | std::string txt_address = txt.substr(0, pos); | |||
647 | isc::asiolink::IOAddress address = isc::asiolink::IOAddress(txt_address); | |||
648 | if (!address.isV6()) { | |||
649 | isc_throw(BadDataTypeCast, "provided address "do { std::ostringstream oss__; oss__ << "provided address " << txt_address << " is not a valid IPv4 or IPv6 address." ; throw BadDataTypeCast("option_definition.cc", 651, oss__.str ().c_str()); } while (1) | |||
650 | << txt_addressdo { std::ostringstream oss__; oss__ << "provided address " << txt_address << " is not a valid IPv4 or IPv6 address." ; throw BadDataTypeCast("option_definition.cc", 651, oss__.str ().c_str()); } while (1) | |||
651 | << " is not a valid IPv4 or IPv6 address.")do { std::ostringstream oss__; oss__ << "provided address " << txt_address << " is not a valid IPv4 or IPv6 address." ; throw BadDataTypeCast("option_definition.cc", 651, oss__.str ().c_str()); } while (1); | |||
652 | } | |||
653 | ||||
654 | std::string txt_prefix = txt.substr(pos + 1); | |||
655 | uint8_t len = 0; | |||
656 | try { | |||
657 | // start with the first character after / | |||
658 | len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix); | |||
659 | } catch (...) { | |||
660 | isc_throw(BadDataTypeCast, "provided prefix "do { std::ostringstream oss__; oss__ << "provided prefix " << txt_prefix << " is not valid."; throw BadDataTypeCast ("option_definition.cc", 662, oss__.str().c_str()); } while ( 1) | |||
661 | << txt_prefixdo { std::ostringstream oss__; oss__ << "provided prefix " << txt_prefix << " is not valid."; throw BadDataTypeCast ("option_definition.cc", 662, oss__.str().c_str()); } while ( 1) | |||
662 | << " is not valid.")do { std::ostringstream oss__; oss__ << "provided prefix " << txt_prefix << " is not valid."; throw BadDataTypeCast ("option_definition.cc", 662, oss__.str().c_str()); } while ( 1); | |||
663 | } | |||
664 | ||||
665 | // Write a prefix. | |||
666 | OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf); | |||
667 | ||||
668 | return; | |||
669 | } | |||
670 | case OPT_PSID_TYPE: | |||
671 | { | |||
672 | std::string txt = value; | |||
673 | ||||
674 | // first let's remove any whitespaces | |||
675 | boost::erase_all(txt, " "); // space | |||
676 | boost::erase_all(txt, "\t"); // tabulation | |||
677 | ||||
678 | // Is this prefix/len notation? | |||
679 | size_t pos = txt.find("/"); | |||
680 | ||||
681 | if (pos == string::npos) { | |||
682 | isc_throw(BadDataTypeCast, "provided PSID value "do { std::ostringstream oss__; oss__ << "provided PSID value " << value << " is not valid"; throw BadDataTypeCast ("option_definition.cc", 683, oss__.str().c_str()); } while ( 1) | |||
683 | << value << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID value " << value << " is not valid"; throw BadDataTypeCast ("option_definition.cc", 683, oss__.str().c_str()); } while ( 1); | |||
684 | } | |||
685 | ||||
686 | const std::string txt_psid = txt.substr(0, pos); | |||
687 | const std::string txt_psid_len = txt.substr(pos + 1); | |||
688 | ||||
689 | uint16_t psid = 0; | |||
690 | uint8_t psid_len = 0; | |||
691 | ||||
692 | try { | |||
693 | psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid); | |||
694 | } catch (...) { | |||
695 | isc_throw(BadDataTypeCast, "provided PSID "do { std::ostringstream oss__; oss__ << "provided PSID " << txt_psid << " is not valid"; throw BadDataTypeCast ("option_definition.cc", 696, oss__.str().c_str()); } while ( 1) | |||
696 | << txt_psid << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID " << txt_psid << " is not valid"; throw BadDataTypeCast ("option_definition.cc", 696, oss__.str().c_str()); } while ( 1); | |||
697 | } | |||
698 | ||||
699 | try { | |||
700 | psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len); | |||
701 | } catch (...) { | |||
702 | isc_throw(BadDataTypeCast, "provided PSID length "do { std::ostringstream oss__; oss__ << "provided PSID length " << txt_psid_len << " is not valid"; throw BadDataTypeCast ("option_definition.cc", 703, oss__.str().c_str()); } while ( 1) | |||
703 | << txt_psid_len << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID length " << txt_psid_len << " is not valid"; throw BadDataTypeCast ("option_definition.cc", 703, oss__.str().c_str()); } while ( 1); | |||
704 | } | |||
705 | ||||
706 | OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf); | |||
707 | return; | |||
708 | } | |||
709 | case OPT_STRING_TYPE: | |||
710 | OptionDataTypeUtil::writeString(value, buf); | |||
711 | return; | |||
712 | case OPT_FQDN_TYPE: | |||
713 | OptionDataTypeUtil::writeFqdn(value, buf); | |||
714 | return; | |||
715 | case OPT_TUPLE_TYPE: | |||
716 | { | |||
717 | // In case of V4_SZTP_REDIRECT option #143, bootstrap-server-list is formatted | |||
718 | // as a list of tuples "uri-length;URI" where uri-length is coded on 2 octets, | |||
719 | // which is not typical for V4 Universe. | |||
720 | OpaqueDataTuple::LengthFieldType lft = getCode() == DHO_V4_SZTP_REDIRECT | |||
721 | ? OpaqueDataTuple::LENGTH_2_BYTES | |||
722 | : OptionDataTypeUtil::getTupleLenFieldType(u); | |||
723 | OptionDataTypeUtil::writeTuple(value, lft, buf); | |||
724 | return; | |||
725 | } | |||
726 | default: | |||
727 | // We hit this point because invalid option data type has been specified | |||
728 | // This may be the case because 'empty' or 'record' data type has been | |||
729 | // specified. We don't throw exception here because it will be thrown | |||
730 | // at the exit point from this function. | |||
731 | ; | |||
732 | } | |||
733 | isc_throw(isc::BadValue, "attempt to write invalid option data field type"do { std::ostringstream oss__; oss__ << "attempt to write invalid option data field type" " into the option buffer: " << type; throw isc::BadValue ("option_definition.cc", 734, oss__.str().c_str()); } while ( 1) | |||
734 | " into the option buffer: " << type)do { std::ostringstream oss__; oss__ << "attempt to write invalid option data field type" " into the option buffer: " << type; throw isc::BadValue ("option_definition.cc", 734, oss__.str().c_str()); } while ( 1); | |||
735 | ||||
736 | } | |||
737 | ||||
738 | OptionPtr | |||
739 | OptionDefinition::factoryAddrList4(uint16_t type, | |||
740 | OptionBufferConstIter begin, | |||
741 | OptionBufferConstIter end) { | |||
742 | boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin, | |||
743 | end)); | |||
744 | return (option); | |||
745 | } | |||
746 | ||||
747 | OptionPtr | |||
748 | OptionDefinition::factoryAddrList6(uint16_t type, | |||
749 | OptionBufferConstIter begin, | |||
750 | OptionBufferConstIter end) { | |||
751 | boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin, | |||
752 | end)); | |||
753 | return (option); | |||
754 | } | |||
755 | ||||
756 | ||||
757 | OptionPtr | |||
758 | OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) { | |||
759 | OptionPtr option(new Option(u, type)); | |||
760 | return (option); | |||
761 | } | |||
762 | ||||
763 | OptionPtr | |||
764 | OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type, | |||
765 | OptionBufferConstIter begin, | |||
766 | OptionBufferConstIter end) { | |||
767 | OptionPtr option(new Option(u, type, begin, end)); | |||
768 | return (option); | |||
769 | } | |||
770 | ||||
771 | OptionPtr | |||
772 | OptionDefinition::factoryIA6(uint16_t type, | |||
773 | OptionBufferConstIter begin, | |||
774 | OptionBufferConstIter end) { | |||
775 | if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) { | |||
776 | isc_throw(isc::OutOfRange, "input option buffer has invalid size,"do { std::ostringstream oss__; oss__ << "input option buffer has invalid size," << " expected at least " << Option6IA::OPTION6_IA_LEN << " bytes"; throw isc::OutOfRange("option_definition.cc" , 778, oss__.str().c_str()); } while (1) | |||
777 | << " expected at least " << Option6IA::OPTION6_IA_LENdo { std::ostringstream oss__; oss__ << "input option buffer has invalid size," << " expected at least " << Option6IA::OPTION6_IA_LEN << " bytes"; throw isc::OutOfRange("option_definition.cc" , 778, oss__.str().c_str()); } while (1) | |||
778 | << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size," << " expected at least " << Option6IA::OPTION6_IA_LEN << " bytes"; throw isc::OutOfRange("option_definition.cc" , 778, oss__.str().c_str()); } while (1); | |||
779 | } | |||
780 | boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end)); | |||
781 | return (option); | |||
782 | } | |||
783 | ||||
784 | OptionPtr | |||
785 | OptionDefinition::factoryIAAddr6(uint16_t type, | |||
786 | OptionBufferConstIter begin, | |||
787 | OptionBufferConstIter end) { | |||
788 | if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) { | |||
789 | isc_throw(isc::OutOfRange,do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes" ; throw isc::OutOfRange("option_definition.cc", 791, oss__.str ().c_str()); } while (1) | |||
790 | "input option buffer has invalid size, expected at least "do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes" ; throw isc::OutOfRange("option_definition.cc", 791, oss__.str ().c_str()); } while (1) | |||
791 | << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least " << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes" ; throw isc::OutOfRange("option_definition.cc", 791, oss__.str ().c_str()); } while (1); | |||
792 | } | |||
793 | boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin, | |||
794 | end)); | |||
795 | return (option); | |||
796 | } | |||
797 | ||||
798 | OptionPtr | |||
799 | OptionDefinition::factoryIAPrefix6(uint16_t type, | |||
800 | OptionBufferConstIter begin, | |||
801 | OptionBufferConstIter end) { | |||
802 | if (std::distance(begin, end) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) { | |||
803 | isc_throw(isc::OutOfRange,do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least " << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes" ; throw isc::OutOfRange("option_definition.cc", 805, oss__.str ().c_str()); } while (1) | |||
804 | "input option buffer has invalid size, expected at least "do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least " << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes" ; throw isc::OutOfRange("option_definition.cc", 805, oss__.str ().c_str()); } while (1) | |||
805 | << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least " << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes" ; throw isc::OutOfRange("option_definition.cc", 805, oss__.str ().c_str()); } while (1); | |||
806 | } | |||
807 | boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin, | |||
808 | end)); | |||
809 | return (option); | |||
810 | } | |||
811 | ||||
812 | OptionPtr | |||
813 | OptionDefinition::factoryOpaqueDataTuples(Option::Universe u, | |||
814 | uint16_t type, | |||
815 | OptionBufferConstIter begin, | |||
816 | OptionBufferConstIter end) { | |||
817 | boost::shared_ptr<OptionOpaqueDataTuples> | |||
818 | option(new OptionOpaqueDataTuples(u, type, begin, end)); | |||
819 | ||||
820 | return (option); | |||
821 | } | |||
822 | ||||
823 | OptionPtr | |||
824 | OptionDefinition::factoryOpaqueDataTuples(Option::Universe u, | |||
825 | uint16_t type, | |||
826 | OptionBufferConstIter begin, | |||
827 | OptionBufferConstIter end, | |||
828 | OpaqueDataTuple::LengthFieldType length_field_type) { | |||
829 | boost::shared_ptr<OptionOpaqueDataTuples> | |||
830 | option(new OptionOpaqueDataTuples(u, type, begin, end, length_field_type)); | |||
831 | ||||
832 | return (option); | |||
833 | } | |||
834 | ||||
835 | OptionPtr | |||
836 | OptionDefinition::factoryFqdnList(Option::Universe u, | |||
837 | OptionBufferConstIter begin, | |||
838 | OptionBufferConstIter end) const { | |||
839 | ||||
840 | const std::vector<uint8_t> data(begin, end); | |||
841 | if (data.empty()) { | |||
842 | isc_throw(InvalidOptionValue, "FQDN list option has invalid length of 0")do { std::ostringstream oss__; oss__ << "FQDN list option has invalid length of 0" ; throw InvalidOptionValue("option_definition.cc", 842, oss__ .str().c_str()); } while (1); | |||
843 | } | |||
844 | InputBuffer in_buf(static_cast<const void*>(&data[0]), data.size()); | |||
845 | std::vector<uint8_t> out_buf; | |||
846 | out_buf.reserve(data.size()); | |||
847 | while (in_buf.getPosition() < in_buf.getLength()) { | |||
848 | // Reuse readFqdn and writeFqdn code but on the whole buffer | |||
849 | // so the DNS name code handles compression for us. | |||
850 | try { | |||
851 | isc::dns::Name name(in_buf); | |||
852 | isc::dns::LabelSequence labels(name); | |||
853 | if (labels.getDataLength() > 0) { | |||
854 | size_t read_len = 0; | |||
855 | const uint8_t* label = labels.getData(&read_len); | |||
856 | out_buf.insert(out_buf.end(), label, label + read_len); | |||
857 | } | |||
858 | } catch (const isc::Exception& ex) { | |||
859 | if (Option::lenient_parsing_) { | |||
860 | isc_throw(SkipThisOptionError,do { std::ostringstream oss__; oss__ << "invalid FQDN list content: " << ex.what(); throw SkipThisOptionError("option_definition.cc" , 861, oss__.str().c_str()); } while (1) | |||
861 | "invalid FQDN list content: " << ex.what())do { std::ostringstream oss__; oss__ << "invalid FQDN list content: " << ex.what(); throw SkipThisOptionError("option_definition.cc" , 861, oss__.str().c_str()); } while (1); | |||
862 | } | |||
863 | ||||
864 | isc_throw(InvalidOptionValue, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw InvalidOptionValue("option_definition.cc", 864, oss__.str(). c_str()); } while (1); | |||
865 | } | |||
866 | } | |||
867 | return OptionPtr(new OptionCustom(*this, u, | |||
868 | out_buf.begin(), out_buf.end())); | |||
869 | } | |||
870 | ||||
871 | OptionPtr | |||
872 | OptionDefinition::factorySpecialFormatOption(Option::Universe u, | |||
873 | OptionBufferConstIter begin, | |||
874 | OptionBufferConstIter end, | |||
875 | bool convenient_notation) const { | |||
876 | if ((u == Option::V6) && haveSpace(DHCP6_OPTION_SPACE"dhcp6")) { | |||
877 | switch (getCode()) { | |||
878 | case D6O_IA_NA: | |||
879 | case D6O_IA_PD: | |||
880 | // Record of 3 uint32, no array. | |||
881 | return (factoryIA6(getCode(), begin, end)); | |||
882 | ||||
883 | case D6O_IAADDR: | |||
884 | // Record of an IPv6 address followed by 2 uint32, no array. | |||
885 | return (factoryIAAddr6(getCode(), begin, end)); | |||
886 | ||||
887 | case D6O_IAPREFIX: | |||
888 | // Record of 2 uint32, one uint8 and an IPv6 address, no array. | |||
889 | return (factoryIAPrefix6(getCode(), begin, end)); | |||
890 | ||||
891 | case D6O_CLIENT_FQDN: | |||
892 | // Record of one uint8 and one FQDN, no array. | |||
893 | return (OptionPtr(new Option6ClientFqdn(begin, end))); | |||
894 | ||||
895 | case D6O_VENDOR_OPTS: | |||
896 | // Type uint32. | |||
897 | // Vendor-Specific Information (option code 17). | |||
898 | return (OptionPtr(new OptionVendor(Option::V6, begin, end))); | |||
899 | ||||
900 | case D6O_VENDOR_CLASS: | |||
901 | // Record of one uint32 and one string. | |||
902 | // Vendor Class (option code 16). | |||
903 | return (OptionPtr(new OptionVendorClass(Option::V6, begin, end))); | |||
904 | ||||
905 | case D6O_STATUS_CODE: | |||
906 | // Record of one uint16 and one string. | |||
907 | // Status Code (option code 13). | |||
908 | return (OptionPtr(new Option6StatusCode(begin, end))); | |||
909 | ||||
910 | case D6O_BOOTFILE_PARAM: | |||
911 | // Array of tuples. | |||
912 | // Bootfile params (option code 60). | |||
913 | return (factoryOpaqueDataTuples(Option::V6, getCode(), begin, end)); | |||
914 | ||||
915 | case D6O_PD_EXCLUDE: | |||
916 | // Type IPv6 prefix. | |||
917 | // Prefix Exclude (option code 67), | |||
918 | return (OptionPtr(new Option6PDExclude(begin, end))); | |||
919 | ||||
920 | case D6O_V6_DNR: | |||
921 | return (OptionPtr(new Option6Dnr(begin, end, convenient_notation))); | |||
922 | ||||
923 | default: | |||
924 | break; | |||
925 | } | |||
926 | } else if ((u == Option::V4) && haveSpace(DHCP4_OPTION_SPACE"dhcp4")) { | |||
927 | switch (getCode()) { | |||
928 | case DHO_SERVICE_SCOPE: | |||
929 | // Record of a boolean and a string. | |||
930 | return (OptionPtr(new Option4SlpServiceScope(begin, end))); | |||
931 | ||||
932 | case DHO_FQDN: | |||
933 | // Record of 3 uint8 and a FQDN, no array. | |||
934 | return (OptionPtr(new Option4ClientFqdn(begin, end))); | |||
935 | ||||
936 | case DHO_CLASSLESS_STATIC_ROUTE: | |||
937 | return (OptionPtr(new OptionClasslessStaticRoute(begin, end, convenient_notation))); | |||
938 | ||||
939 | case DHO_VIVCO_SUBOPTIONS: | |||
940 | // Record of uint32 followed by binary. | |||
941 | // V-I Vendor Class (option code 124). | |||
942 | return (OptionPtr(new OptionVendorClass(Option::V4, begin, end))); | |||
943 | ||||
944 | case DHO_VIVSO_SUBOPTIONS: | |||
945 | // Type uint32. | |||
946 | // Vendor-Specific Information (option code 125). | |||
947 | return (OptionPtr(new OptionVendor(Option::V4, begin, end))); | |||
948 | ||||
949 | case DHO_V4_SZTP_REDIRECT: | |||
950 | // Array of tuples. | |||
951 | // DHCPv4 SZTP Redirect Option (option code 143). | |||
952 | return (factoryOpaqueDataTuples(Option::V4, getCode(), begin, end, OpaqueDataTuple::LENGTH_2_BYTES)); | |||
953 | ||||
954 | case DHO_V4_DNR: | |||
955 | return (OptionPtr(new Option4Dnr(begin, end, convenient_notation))); | |||
956 | ||||
957 | default: | |||
958 | break; | |||
959 | } | |||
960 | } | |||
961 | if ((u == Option::V4) && haveCompressedFqdnListFormat()) { | |||
962 | return (factoryFqdnList(Option::V4, begin, end)); | |||
963 | } | |||
964 | return (OptionPtr()); | |||
965 | } | |||
966 | ||||
967 | } // end of isc::dhcp namespace | |||
968 | } // end of isc namespace |
1 | // Boost string_algo library classification.hpp header file ---------------------------// |
2 | |
3 | // Copyright Pavol Droba 2002-2003. |
4 | // |
5 | // Distributed under the Boost Software License, Version 1.0. |
6 | // (See accompanying file LICENSE_1_0.txt or copy at |
7 | // http://www.boost.org/LICENSE_1_0.txt) |
8 | |
9 | // See http://www.boost.org/ for updates, documentation, and revision history. |
10 | |
11 | #ifndef BOOST_STRING_CLASSIFICATION_HPP |
12 | #define BOOST_STRING_CLASSIFICATION_HPP |
13 | |
14 | #include <algorithm> |
15 | #include <locale> |
16 | #include <boost/range/value_type.hpp> |
17 | #include <boost/range/as_literal.hpp> |
18 | #include <boost/algorithm/string/detail/classification.hpp> |
19 | #include <boost/algorithm/string/predicate_facade.hpp> |
20 | |
21 | |
22 | /*! \file |
23 | Classification predicates are included in the library to give |
24 | some more convenience when using algorithms like \c trim() and \c all(). |
25 | They wrap functionality of STL classification functions ( e.g. \c std::isspace() ) |
26 | into generic functors. |
27 | */ |
28 | |
29 | namespace boost { |
30 | namespace algorithm { |
31 | |
32 | // classification functor generator -------------------------------------// |
33 | |
34 | //! is_classified predicate |
35 | /*! |
36 | Construct the \c is_classified predicate. This predicate holds if the input is |
37 | of specified \c std::ctype category. |
38 | |
39 | \param Type A \c std::ctype category |
40 | \param Loc A locale used for classification |
41 | \return An instance of the \c is_classified predicate |
42 | */ |
43 | inline detail::is_classifiedF |
44 | is_classified(std::ctype_base::mask Type, const std::locale& Loc=std::locale()) |
45 | { |
46 | return detail::is_classifiedF(Type, Loc); |
47 | } |
48 | |
49 | //! is_space predicate |
50 | /*! |
51 | Construct the \c is_classified predicate for the \c ctype_base::space category. |
52 | |
53 | \param Loc A locale used for classification |
54 | \return An instance of the \c is_classified predicate |
55 | */ |
56 | inline detail::is_classifiedF |
57 | is_space(const std::locale& Loc=std::locale()) |
58 | { |
59 | return detail::is_classifiedF(std::ctype_base::space, Loc); |
60 | } |
61 | |
62 | //! is_alnum predicate |
63 | /*! |
64 | Construct the \c is_classified predicate for the \c ctype_base::alnum category. |
65 | |
66 | \param Loc A locale used for classification |
67 | \return An instance of the \c is_classified predicate |
68 | */ |
69 | inline detail::is_classifiedF |
70 | is_alnum(const std::locale& Loc=std::locale()) |
71 | { |
72 | return detail::is_classifiedF(std::ctype_base::alnum, Loc); |
73 | } |
74 | |
75 | //! is_alpha predicate |
76 | /*! |
77 | Construct the \c is_classified predicate for the \c ctype_base::alpha category. |
78 | |
79 | \param Loc A locale used for classification |
80 | \return An instance of the \c is_classified predicate |
81 | */ |
82 | inline detail::is_classifiedF |
83 | is_alpha(const std::locale& Loc=std::locale()) |
84 | { |
85 | return detail::is_classifiedF(std::ctype_base::alpha, Loc); |
86 | } |
87 | |
88 | //! is_cntrl predicate |
89 | /*! |
90 | Construct the \c is_classified predicate for the \c ctype_base::cntrl category. |
91 | |
92 | \param Loc A locale used for classification |
93 | \return An instance of the \c is_classified predicate |
94 | */ |
95 | inline detail::is_classifiedF |
96 | is_cntrl(const std::locale& Loc=std::locale()) |
97 | { |
98 | return detail::is_classifiedF(std::ctype_base::cntrl, Loc); |
99 | } |
100 | |
101 | //! is_digit predicate |
102 | /*! |
103 | Construct the \c is_classified predicate for the \c ctype_base::digit category. |
104 | |
105 | \param Loc A locale used for classification |
106 | \return An instance of the \c is_classified predicate |
107 | */ |
108 | inline detail::is_classifiedF |
109 | is_digit(const std::locale& Loc=std::locale()) |
110 | { |
111 | return detail::is_classifiedF(std::ctype_base::digit, Loc); |
112 | } |
113 | |
114 | //! is_graph predicate |
115 | /*! |
116 | Construct the \c is_classified predicate for the \c ctype_base::graph category. |
117 | |
118 | \param Loc A locale used for classification |
119 | \return An instance of the \c is_classified predicate |
120 | */ |
121 | inline detail::is_classifiedF |
122 | is_graph(const std::locale& Loc=std::locale()) |
123 | { |
124 | return detail::is_classifiedF(std::ctype_base::graph, Loc); |
125 | } |
126 | |
127 | //! is_lower predicate |
128 | /*! |
129 | Construct the \c is_classified predicate for the \c ctype_base::lower category. |
130 | |
131 | \param Loc A locale used for classification |
132 | \return An instance of \c is_classified predicate |
133 | */ |
134 | inline detail::is_classifiedF |
135 | is_lower(const std::locale& Loc=std::locale()) |
136 | { |
137 | return detail::is_classifiedF(std::ctype_base::lower, Loc); |
138 | } |
139 | |
140 | //! is_print predicate |
141 | /*! |
142 | Construct the \c is_classified predicate for the \c ctype_base::print category. |
143 | |
144 | \param Loc A locale used for classification |
145 | \return An instance of the \c is_classified predicate |
146 | */ |
147 | inline detail::is_classifiedF |
148 | is_print(const std::locale& Loc=std::locale()) |
149 | { |
150 | return detail::is_classifiedF(std::ctype_base::print, Loc); |
151 | } |
152 | |
153 | //! is_punct predicate |
154 | /*! |
155 | Construct the \c is_classified predicate for the \c ctype_base::punct category. |
156 | |
157 | \param Loc A locale used for classification |
158 | \return An instance of the \c is_classified predicate |
159 | */ |
160 | inline detail::is_classifiedF |
161 | is_punct(const std::locale& Loc=std::locale()) |
162 | { |
163 | return detail::is_classifiedF(std::ctype_base::punct, Loc); |
164 | } |
165 | |
166 | //! is_upper predicate |
167 | /*! |
168 | Construct the \c is_classified predicate for the \c ctype_base::upper category. |
169 | |
170 | \param Loc A locale used for classification |
171 | \return An instance of the \c is_classified predicate |
172 | */ |
173 | inline detail::is_classifiedF |
174 | is_upper(const std::locale& Loc=std::locale()) |
175 | { |
176 | return detail::is_classifiedF(std::ctype_base::upper, Loc); |
177 | } |
178 | |
179 | //! is_xdigit predicate |
180 | /*! |
181 | Construct the \c is_classified predicate for the \c ctype_base::xdigit category. |
182 | |
183 | \param Loc A locale used for classification |
184 | \return An instance of the \c is_classified predicate |
185 | */ |
186 | inline detail::is_classifiedF |
187 | is_xdigit(const std::locale& Loc=std::locale()) |
188 | { |
189 | return detail::is_classifiedF(std::ctype_base::xdigit, Loc); |
190 | } |
191 | |
192 | //! is_any_of predicate |
193 | /*! |
194 | Construct the \c is_any_of predicate. The predicate holds if the input |
195 | is included in the specified set of characters. |
196 | |
197 | \param Set A set of characters to be recognized |
198 | \return An instance of the \c is_any_of predicate |
199 | */ |
200 | template<typename RangeT> |
201 | inline detail::is_any_ofF< |
202 | BOOST_STRING_TYPENAMEtypename range_value<RangeT>::type> |
203 | is_any_of( const RangeT& Set ) |
204 | { |
205 | iterator_range<BOOST_STRING_TYPENAMEtypename range_const_iterator<RangeT>::type> lit_set(boost::as_literal(Set)); |
206 | return detail::is_any_ofF<BOOST_STRING_TYPENAMEtypename range_value<RangeT>::type>(lit_set); |
207 | } |
208 | |
209 | //! is_from_range predicate |
210 | /*! |
211 | Construct the \c is_from_range predicate. The predicate holds if the input |
212 | is included in the specified range. (i.e. From <= Ch <= To ) |
213 | |
214 | \param From The start of the range |
215 | \param To The end of the range |
216 | \return An instance of the \c is_from_range predicate |
217 | */ |
218 | template<typename CharT> |
219 | inline detail::is_from_rangeF<CharT> is_from_range(CharT From, CharT To) |
220 | { |
221 | return detail::is_from_rangeF<CharT>(From,To); |
222 | } |
223 | |
224 | // predicate combinators ---------------------------------------------------// |
225 | |
226 | //! predicate 'and' composition predicate |
227 | /*! |
228 | Construct the \c class_and predicate. This predicate can be used |
229 | to logically combine two classification predicates. \c class_and holds, |
230 | if both predicates return true. |
231 | |
232 | \param Pred1 The first predicate |
233 | \param Pred2 The second predicate |
234 | \return An instance of the \c class_and predicate |
235 | */ |
236 | template<typename Pred1T, typename Pred2T> |
237 | inline detail::pred_andF<Pred1T, Pred2T> |
238 | operator&&( |
239 | const predicate_facade<Pred1T>& Pred1, |
240 | const predicate_facade<Pred2T>& Pred2 ) |
241 | { |
242 | // Doing the static_cast with the pointer instead of the reference |
243 | // is a workaround for some compilers which have problems with |
244 | // static_cast's of template references, i.e. CW8. /grafik/ |
245 | return detail::pred_andF<Pred1T,Pred2T>( |
246 | *static_cast<const Pred1T*>(&Pred1), |
247 | *static_cast<const Pred2T*>(&Pred2) ); |
248 | } |
249 | |
250 | //! predicate 'or' composition predicate |
251 | /*! |
252 | Construct the \c class_or predicate. This predicate can be used |
253 | to logically combine two classification predicates. \c class_or holds, |
254 | if one of the predicates return true. |
255 | |
256 | \param Pred1 The first predicate |
257 | \param Pred2 The second predicate |
258 | \return An instance of the \c class_or predicate |
259 | */ |
260 | template<typename Pred1T, typename Pred2T> |
261 | inline detail::pred_orF<Pred1T, Pred2T> |
262 | operator||( |
263 | const predicate_facade<Pred1T>& Pred1, |
264 | const predicate_facade<Pred2T>& Pred2 ) |
265 | { |
266 | // Doing the static_cast with the pointer instead of the reference |
267 | // is a workaround for some compilers which have problems with |
268 | // static_cast's of template references, i.e. CW8. /grafik/ |
269 | return detail::pred_orF<Pred1T,Pred2T>( |
270 | *static_cast<const Pred1T*>(&Pred1), |
271 | *static_cast<const Pred2T*>(&Pred2)); |
272 | } |
273 | |
274 | //! predicate negation operator |
275 | /*! |
276 | Construct the \c class_not predicate. This predicate represents a negation. |
277 | \c class_or holds if of the predicates return false. |
278 | |
279 | \param Pred The predicate to be negated |
280 | \return An instance of the \c class_not predicate |
281 | */ |
282 | template<typename PredT> |
283 | inline detail::pred_notF<PredT> |
284 | operator!( const predicate_facade<PredT>& Pred ) |
285 | { |
286 | // Doing the static_cast with the pointer instead of the reference |
287 | // is a workaround for some compilers which have problems with |
288 | // static_cast's of template references, i.e. CW8. /grafik/ |
289 | return detail::pred_notF<PredT>(*static_cast<const PredT*>(&Pred)); |
290 | } |
291 | |
292 | } // namespace algorithm |
293 | |
294 | // pull names to the boost namespace |
295 | using algorithm::is_classified; |
296 | using algorithm::is_space; |
297 | using algorithm::is_alnum; |
298 | using algorithm::is_alpha; |
299 | using algorithm::is_cntrl; |
300 | using algorithm::is_digit; |
301 | using algorithm::is_graph; |
302 | using algorithm::is_lower; |
303 | using algorithm::is_upper; |
304 | using algorithm::is_print; |
305 | using algorithm::is_punct; |
306 | using algorithm::is_xdigit; |
307 | using algorithm::is_any_of; |
308 | using algorithm::is_from_range; |
309 | |
310 | } // namespace boost |
311 | |
312 | #endif // BOOST_STRING_PREDICATE_HPP |
1 | // Boost string_algo library classification.hpp header file ---------------------------// | |||
2 | ||||
3 | // Copyright Pavol Droba 2002-2003. | |||
4 | // | |||
5 | // Distributed under the Boost Software License, Version 1.0. | |||
6 | // (See accompanying file LICENSE_1_0.txt or copy at | |||
7 | // http://www.boost.org/LICENSE_1_0.txt) | |||
8 | ||||
9 | // See http://www.boost.org/ for updates, documentation, and revision history. | |||
10 | ||||
11 | #ifndef BOOST_STRING_CLASSIFICATION_DETAIL_HPP | |||
12 | #define BOOST_STRING_CLASSIFICATION_DETAIL_HPP | |||
13 | ||||
14 | #include <boost/algorithm/string/config.hpp> | |||
15 | #include <algorithm> | |||
16 | #include <cstring> | |||
17 | #include <functional> | |||
18 | #include <locale> | |||
19 | ||||
20 | #include <boost/range/begin.hpp> | |||
21 | #include <boost/range/distance.hpp> | |||
22 | #include <boost/range/end.hpp> | |||
23 | ||||
24 | #include <boost/algorithm/string/predicate_facade.hpp> | |||
25 | #include <boost/type_traits/remove_const.hpp> | |||
26 | ||||
27 | namespace boost { | |||
28 | namespace algorithm { | |||
29 | namespace detail { | |||
30 | ||||
31 | // classification functors -----------------------------------------------// | |||
32 | ||||
33 | // is_classified functor | |||
34 | struct is_classifiedF : | |||
35 | public predicate_facade<is_classifiedF> | |||
36 | { | |||
37 | // Boost.ResultOf support | |||
38 | typedef bool result_type; | |||
39 | ||||
40 | // Constructor from a locale | |||
41 | is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) : | |||
42 | m_Type(Type), m_Locale(Loc) {} | |||
43 | // Operation | |||
44 | template<typename CharT> | |||
45 | bool operator()( CharT Ch ) const | |||
46 | { | |||
47 | return std::use_facet< std::ctype<CharT> >(m_Locale).is( m_Type, Ch ); | |||
48 | } | |||
49 | ||||
50 | #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x582) && !defined(_USE_OLD_RW_STL) | |||
51 | template<> | |||
52 | bool operator()( char const Ch ) const | |||
53 | { | |||
54 | return std::use_facet< std::ctype<char> >(m_Locale).is( m_Type, Ch ); | |||
55 | } | |||
56 | #endif | |||
57 | ||||
58 | private: | |||
59 | std::ctype_base::mask m_Type; | |||
60 | std::locale m_Locale; | |||
61 | }; | |||
62 | ||||
63 | ||||
64 | // is_any_of functor | |||
65 | /* | |||
66 | returns true if the value is from the specified set | |||
67 | */ | |||
68 | template<typename CharT> | |||
69 | struct is_any_ofF : | |||
70 | public predicate_facade<is_any_ofF<CharT> > | |||
71 | { | |||
72 | private: | |||
73 | // set cannot operate on const value-type | |||
74 | typedef typename ::boost::remove_const<CharT>::type set_value_type; | |||
75 | ||||
76 | public: | |||
77 | // Boost.ResultOf support | |||
78 | typedef bool result_type; | |||
79 | ||||
80 | // Constructor | |||
81 | template<typename RangeT> | |||
82 | is_any_ofF( const RangeT& Range ) : m_Size(0) | |||
83 | { | |||
84 | // Prepare storage | |||
85 | m_Storage.m_dynSet=0; | |||
86 | ||||
87 | std::size_t Size=::boost::distance(Range); | |||
88 | m_Size=Size; | |||
89 | set_value_type* Storage=0; | |||
90 | ||||
91 | if(use_fixed_storage(m_Size)) | |||
92 | { | |||
93 | // Use fixed storage | |||
94 | Storage=&m_Storage.m_fixSet[0]; | |||
95 | } | |||
96 | else | |||
97 | { | |||
98 | // Use dynamic storage | |||
99 | m_Storage.m_dynSet=new set_value_type[m_Size]; | |||
100 | Storage=m_Storage.m_dynSet; | |||
101 | } | |||
102 | ||||
103 | // Use fixed storage | |||
104 | ::std::copy(::boost::begin(Range), ::boost::end(Range), Storage); | |||
105 | ::std::sort(Storage, Storage+m_Size); | |||
106 | } | |||
107 | ||||
108 | // Copy constructor | |||
109 | is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size) | |||
110 | { | |||
111 | // Prepare storage | |||
112 | m_Storage.m_dynSet=0; | |||
113 | const set_value_type* SrcStorage=0; | |||
114 | set_value_type* DestStorage=0; | |||
115 | ||||
116 | if(use_fixed_storage(m_Size)) | |||
117 | { | |||
118 | // Use fixed storage | |||
119 | DestStorage=&m_Storage.m_fixSet[0]; | |||
120 | SrcStorage=&Other.m_Storage.m_fixSet[0]; | |||
121 | } | |||
122 | else | |||
123 | { | |||
124 | // Use dynamic storage | |||
125 | m_Storage.m_dynSet=new set_value_type[m_Size]; | |||
126 | DestStorage=m_Storage.m_dynSet; | |||
127 | SrcStorage=Other.m_Storage.m_dynSet; | |||
128 | } | |||
129 | ||||
130 | // Use fixed storage | |||
131 | ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); | |||
132 | } | |||
133 | ||||
134 | // Destructor | |||
135 | ~is_any_ofF() | |||
136 | { | |||
137 | if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) | |||
138 | { | |||
139 | delete [] m_Storage.m_dynSet; | |||
140 | } | |||
141 | } | |||
| ||||
142 | ||||
143 | // Assignment | |||
144 | is_any_ofF& operator=(const is_any_ofF& Other) | |||
145 | { | |||
146 | // Handle self assignment | |||
147 | if(this==&Other) return *this; | |||
148 | ||||
149 | // Prepare storage | |||
150 | const set_value_type* SrcStorage; | |||
151 | set_value_type* DestStorage; | |||
152 | ||||
153 | if(use_fixed_storage(Other.m_Size)) | |||
154 | { | |||
155 | // Use fixed storage | |||
156 | DestStorage=&m_Storage.m_fixSet[0]; | |||
157 | SrcStorage=&Other.m_Storage.m_fixSet[0]; | |||
158 | ||||
159 | // Delete old storage if was present | |||
160 | if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) | |||
161 | { | |||
162 | delete [] m_Storage.m_dynSet; | |||
163 | } | |||
164 | ||||
165 | // Set new size | |||
166 | m_Size=Other.m_Size; | |||
167 | } | |||
168 | else | |||
169 | { | |||
170 | // Other uses dynamic storage | |||
171 | SrcStorage=Other.m_Storage.m_dynSet; | |||
172 | ||||
173 | // Check what kind of storage are we using right now | |||
174 | if(use_fixed_storage(m_Size)) | |||
175 | { | |||
176 | // Using fixed storage, allocate new | |||
177 | set_value_type* pTemp=new set_value_type[Other.m_Size]; | |||
178 | DestStorage=pTemp; | |||
179 | m_Storage.m_dynSet=pTemp; | |||
180 | m_Size=Other.m_Size; | |||
181 | } | |||
182 | else | |||
183 | { | |||
184 | // Using dynamic storage, check if can reuse | |||
185 | if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size<Other.m_Size*2) | |||
186 | { | |||
187 | // Reuse the current storage | |||
188 | DestStorage=m_Storage.m_dynSet; | |||
189 | m_Size=Other.m_Size; | |||
190 | } | |||
191 | else | |||
192 | { | |||
193 | // Allocate the new one | |||
194 | set_value_type* pTemp=new set_value_type[Other.m_Size]; | |||
195 | DestStorage=pTemp; | |||
196 | ||||
197 | // Delete old storage if necessary | |||
198 | if(m_Storage.m_dynSet!=0) | |||
199 | { | |||
200 | delete [] m_Storage.m_dynSet; | |||
201 | } | |||
202 | // Store the new storage | |||
203 | m_Storage.m_dynSet=pTemp; | |||
204 | // Set new size | |||
205 | m_Size=Other.m_Size; | |||
206 | } | |||
207 | } | |||
208 | } | |||
209 | ||||
210 | // Copy the data | |||
211 | ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); | |||
212 | ||||
213 | return *this; | |||
214 | } | |||
215 | ||||
216 | // Operation | |||
217 | template<typename Char2T> | |||
218 | bool operator()( Char2T Ch ) const | |||
219 | { | |||
220 | const set_value_type* Storage= | |||
221 | (use_fixed_storage(m_Size)) | |||
222 | ? &m_Storage.m_fixSet[0] | |||
223 | : m_Storage.m_dynSet; | |||
224 | ||||
225 | return ::std::binary_search(Storage, Storage+m_Size, Ch); | |||
226 | } | |||
227 | private: | |||
228 | // check if the size is eligible for fixed storage | |||
229 | static bool use_fixed_storage(std::size_t size) | |||
230 | { | |||
231 | return size<=sizeof(set_value_type*)*2; | |||
232 | } | |||
233 | ||||
234 | ||||
235 | private: | |||
236 | // storage | |||
237 | // The actual used storage is selected on the type | |||
238 | union | |||
239 | { | |||
240 | set_value_type* m_dynSet; | |||
241 | set_value_type m_fixSet[sizeof(set_value_type*)*2]; | |||
242 | } | |||
243 | m_Storage; | |||
244 | ||||
245 | // storage size | |||
246 | ::std::size_t m_Size; | |||
247 | }; | |||
248 | ||||
249 | // is_from_range functor | |||
250 | /* | |||
251 | returns true if the value is from the specified range. | |||
252 | (i.e. x>=From && x>=To) | |||
253 | */ | |||
254 | template<typename CharT> | |||
255 | struct is_from_rangeF : | |||
256 | public predicate_facade< is_from_rangeF<CharT> > | |||
257 | { | |||
258 | // Boost.ResultOf support | |||
259 | typedef bool result_type; | |||
260 | ||||
261 | // Constructor | |||
262 | is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {} | |||
263 | ||||
264 | // Operation | |||
265 | template<typename Char2T> | |||
266 | bool operator()( Char2T Ch ) const | |||
267 | { | |||
268 | return ( m_From <= Ch ) && ( Ch <= m_To ); | |||
269 | } | |||
270 | ||||
271 | private: | |||
272 | CharT m_From; | |||
273 | CharT m_To; | |||
274 | }; | |||
275 | ||||
276 | // class_and composition predicate | |||
277 | template<typename Pred1T, typename Pred2T> | |||
278 | struct pred_andF : | |||
279 | public predicate_facade< pred_andF<Pred1T,Pred2T> > | |||
280 | { | |||
281 | public: | |||
282 | ||||
283 | // Boost.ResultOf support | |||
284 | typedef bool result_type; | |||
285 | ||||
286 | // Constructor | |||
287 | pred_andF( Pred1T Pred1, Pred2T Pred2 ) : | |||
288 | m_Pred1(Pred1), m_Pred2(Pred2) {} | |||
289 | ||||
290 | // Operation | |||
291 | template<typename CharT> | |||
292 | bool operator()( CharT Ch ) const | |||
293 | { | |||
294 | return m_Pred1(Ch) && m_Pred2(Ch); | |||
295 | } | |||
296 | ||||
297 | private: | |||
298 | Pred1T m_Pred1; | |||
299 | Pred2T m_Pred2; | |||
300 | }; | |||
301 | ||||
302 | // class_or composition predicate | |||
303 | template<typename Pred1T, typename Pred2T> | |||
304 | struct pred_orF : | |||
305 | public predicate_facade< pred_orF<Pred1T,Pred2T> > | |||
306 | { | |||
307 | public: | |||
308 | // Boost.ResultOf support | |||
309 | typedef bool result_type; | |||
310 | ||||
311 | // Constructor | |||
312 | pred_orF( Pred1T Pred1, Pred2T Pred2 ) : | |||
313 | m_Pred1(Pred1), m_Pred2(Pred2) {} | |||
314 | ||||
315 | // Operation | |||
316 | template<typename CharT> | |||
317 | bool operator()( CharT Ch ) const | |||
318 | { | |||
319 | return m_Pred1(Ch) || m_Pred2(Ch); | |||
320 | } | |||
321 | ||||
322 | private: | |||
323 | Pred1T m_Pred1; | |||
324 | Pred2T m_Pred2; | |||
325 | }; | |||
326 | ||||
327 | // class_not composition predicate | |||
328 | template< typename PredT > | |||
329 | struct pred_notF : | |||
330 | public predicate_facade< pred_notF<PredT> > | |||
331 | { | |||
332 | public: | |||
333 | // Boost.ResultOf support | |||
334 | typedef bool result_type; | |||
335 | ||||
336 | // Constructor | |||
337 | pred_notF( PredT Pred ) : m_Pred(Pred) {} | |||
338 | ||||
339 | // Operation | |||
340 | template<typename CharT> | |||
341 | bool operator()( CharT Ch ) const | |||
342 | { | |||
343 | return !m_Pred(Ch); | |||
344 | } | |||
345 | ||||
346 | private: | |||
347 | PredT m_Pred; | |||
348 | }; | |||
349 | ||||
350 | } // namespace detail | |||
351 | } // namespace algorithm | |||
352 | } // namespace boost | |||
353 | ||||
354 | ||||
355 | #endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP |