Bug Summary

File:usr/include/boost/algorithm/string/detail/classification.hpp
Warning:line 141, column 17
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name option_definition.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmpz0p224zs -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmpz0p224zs -resource-dir /usr/bin/../lib/clang/22 -I src/lib/dhcp/libkea-dhcp.so.129.0.0.p -I src/lib/dhcp -I ../../../src/lib/dhcp -I . -I ../../.. -I src -I ../../../src -I src/bin -I ../../../src/bin -I src/lib -I ../../../src/lib -I /usr/include -D _GLIBCXX_ASSERTIONS=1 -D _FILE_OFFSET_BITS=64 -D BOOST_ALL_NO_LIB -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/backward -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-missing-field-initializers -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-logs/scanbuild/2026-06-18-163926-5114-1 -x c++ ../../../src/lib/dhcp/option_definition.cc

../../../src/lib/dhcp/option_definition.cc

1// Copyright (C) 2012-2025 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
42using namespace std;
43using namespace isc::util;
44
45namespace isc {
46namespace dhcp {
47
48OptionDefinition::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
67OptionDefinition::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
80OptionDefinition::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
98OptionDefinition::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
113OptionDefinitionPtr
114OptionDefinition::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
122OptionDefinitionPtr
123OptionDefinition::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
131OptionDefinitionPtr
132OptionDefinition::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
140OptionDefinitionPtr
141OptionDefinition::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
149bool
150OptionDefinition::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
160void
161OptionDefinition::addRecordField(const std::string& data_type_name) {
162 OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
163 addRecordField(data_type);
164}
165
166void
167OptionDefinition::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
("../../../src/lib/dhcp/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
("../../../src/lib/dhcp/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
("../../../src/lib/dhcp/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
("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/option_definition.cc"
, 180, oss__.str().c_str()); } while (1)
;
181 }
182 record_fields_.push_back(data_type);
183}
184
185OptionPtr
186OptionDefinition::optionFactory(Option::Universe u,
187 uint16_t type,
188 OptionBufferConstIter begin,
189 OptionBufferConstIter end,
190 bool convenient_notation,
191 size_t rec_level) const {
192
193 try {
194 // Some of the options are represented by the specialized classes derived
195 // from Option class (e.g. IA_NA, IAADDR). Although, they can be also
196 // represented by the generic classes, we want the object of the specialized
197 // type to be returned. Therefore, we first check that if we are dealing
198 // with such an option. If the instance is returned we just exit at this
199 // point. If not, we will search for a generic option type to return.
200 OptionPtr option = factorySpecialFormatOption(u, begin, end,
201 convenient_notation,
202 rec_level);
203 if (option) {
204 return (option);
205 }
206
207 switch (type_) {
208 case OPT_EMPTY_TYPE:
209 if (getEncapsulatedSpace().empty()) {
210 return (factoryEmpty(u, type));
211 } else {
212 return (OptionPtr(new OptionCustom(*this, u, begin, end,
213 rec_level)));
214 }
215
216 case OPT_BINARY_TYPE:
217 // If this is Internal type, and it wasn't handled by factorySpecialFormatOption() before,
218 // let's treat it like normal Binary type.
219 case OPT_INTERNAL_TYPE:
220 return (factoryGeneric(u, type, begin, end));
221
222 case OPT_UINT8_TYPE:
223 return (array_type_ ?
224 factoryIntegerArray<uint8_t>(u, type, begin, end) :
225 factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
226 begin, end, rec_level));
227
228 case OPT_INT8_TYPE:
229 return (array_type_ ?
230 factoryIntegerArray<int8_t>(u, type, begin, end) :
231 factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
232 begin, end, rec_level));
233
234 case OPT_UINT16_TYPE:
235 return (array_type_ ?
236 factoryIntegerArray<uint16_t>(u, type, begin, end) :
237 factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
238 begin, end, rec_level));
239
240 case OPT_INT16_TYPE:
241 return (array_type_ ?
242 factoryIntegerArray<uint16_t>(u, type, begin, end) :
243 factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
244 begin, end, rec_level));
245
246 case OPT_UINT32_TYPE:
247 return (array_type_ ?
248 factoryIntegerArray<uint32_t>(u, type, begin, end) :
249 factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
250 begin, end, rec_level));
251
252 case OPT_INT32_TYPE:
253 return (array_type_ ?
254 factoryIntegerArray<uint32_t>(u, type, begin, end) :
255 factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
256 begin, end, rec_level));
257
258 case OPT_IPV4_ADDRESS_TYPE:
259 // If definition specifies that an option is an array
260 // of IPv4 addresses we return an instance of specialized
261 // class (OptionAddrLst4). For non-array types there is no
262 // specialized class yet implemented so we drop through
263 // to return an instance of OptionCustom.
264 if (array_type_) {
265 return (factoryAddrList4(type, begin, end));
266 }
267 break;
268
269 case OPT_IPV6_ADDRESS_TYPE:
270 // Handle array type only here (see comments for
271 // OPT_IPV4_ADDRESS_TYPE case).
272 if (array_type_) {
273 return (factoryAddrList6(type, begin, end));
274 }
275 break;
276
277 case OPT_STRING_TYPE:
278 return (OptionPtr(new OptionString(u, type, begin, end)));
279
280 case OPT_TUPLE_TYPE:
281 // Handle array type only here (see comments for
282 // OPT_IPV4_ADDRESS_TYPE case).
283 if (array_type_) {
284 return (factoryOpaqueDataTuples(u, type, begin, end));
285 }
286 break;
287
288 default:
289 // Do nothing. We will return generic option a few lines down.
290 ;
291 }
292 return (OptionPtr(new OptionCustom(*this, u, begin, end, rec_level)));
293 } catch (const SkipThisOptionError&) {
294 // We need to throw this one as is.
295 throw;
296 } catch (const SkipRemainingOptionsError&) {
297 // We need to throw this one as is.
298 throw;
299 } catch (const Exception& ex) {
300 isc_throw(InvalidOptionValue, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
InvalidOptionValue("../../../src/lib/dhcp/option_definition.cc"
, 300, oss__.str().c_str()); } while (1)
;
301 }
302}
303
304OptionPtr
305OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
306 const OptionBuffer& buf) const {
307 return (optionFactory(u, type, buf.begin(), buf.end()));
308}
309
310OptionPtr
311OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
312 const std::vector<std::string>& values) const {
313 OptionBuffer buf;
314 if (!array_type_ && type_ != OPT_RECORD_TYPE) {
315 if (values.empty()) {
316 if (type_ != OPT_EMPTY_TYPE) {
317 isc_throw(InvalidOptionValue, "no option value specified")do { std::ostringstream oss__; oss__ << "no option value specified"
; throw InvalidOptionValue("../../../src/lib/dhcp/option_definition.cc"
, 317, oss__.str().c_str()); } while (1)
;
318 }
319 } else if (type_ == OPT_INTERNAL_TYPE) {
320 // If an Option of type Internal is configured using csv-format=true, it means it is
321 // convenient notation option config that needs special parsing. Let's treat it like
322 // String type. optionFactory() will be called with convenient_notation flag set to
323 // true, so that the factory will have a chance to handle it in a special way.
324
325 // At this stage any escape backslash chars were lost during last call of
326 // isc::util::str::tokens() inside of
327 // OptionDataParser::createOption(ConstElementPtr option_data), so we must
328 // restore them. Some INTERNAL options may use escaped delimiters, e.g. DNR options.
329 // Values are concatenated back to comma separated format and will be written to
330 // the OptionBuffer as one String type option.
331 std::ostringstream stream;
332 bool first = true;
333 for (auto val : values) {
334 boost::algorithm::replace_all(val, ",", "\\,");
335 if (first) {
336 first = false;
337 } else {
338 stream << ",";
339 }
340
341 stream << val;
342 }
343
344 writeToBuffer(u, stream.str(), OPT_STRING_TYPE, buf);
345 } else {
346 writeToBuffer(u, util::str::trim(values[0]), type_, buf);
347 }
348 } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
349 for (size_t i = 0; i < values.size(); ++i) {
350 writeToBuffer(u, util::str::trim(values[i]), type_, buf);
351 }
352 } else if (type_ == OPT_RECORD_TYPE) {
353 const RecordFieldsCollection& records = getRecordFields();
354 if (records.size() > values.size()) {
355 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("../../../src/lib/dhcp/option_definition.cc"
, 357, oss__.str().c_str()); } while (1)
356 << " 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("../../../src/lib/dhcp/option_definition.cc"
, 357, oss__.str().c_str()); } while (1)
357 << " 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("../../../src/lib/dhcp/option_definition.cc"
, 357, oss__.str().c_str()); } while (1)
;
358 }
359 for (size_t i = 0; i < records.size(); ++i) {
360 writeToBuffer(u, util::str::trim(values[i]), records[i], buf);
361 }
362 if (array_type_ && (values.size() > records.size())) {
363 for (size_t i = records.size(); i < values.size(); ++i) {
364 writeToBuffer(u, util::str::trim(values[i]),
365 records.back(), buf);
366 }
367 }
368 }
369 return (optionFactory(u, type, buf.begin(), buf.end(), (type_ == OPT_INTERNAL_TYPE)));
370}
371
372void
373OptionDefinition::validate() const {
374
375 using namespace boost::algorithm;
376
377 std::ostringstream err_str;
378
379 // Allowed characters in the option name are: lower or
380 // upper case letters, digits, underscores and hyphens.
381 // Empty option spaces are not allowed.
382 if (!all(name_, boost::is_from_range('a', 'z') ||
1
Calling 'operator||<boost::algorithm::detail::pred_orF<boost::algorithm::detail::pred_orF<boost::algorithm::detail::is_from_rangeF<char>, boost::algorithm::detail::is_from_rangeF<char>>, boost::algorithm::detail::is_classifiedF>, boost::algorithm::detail::is_any_ofF<char>>'
383 boost::is_from_range('A', 'Z') ||
384 boost::is_digit() ||
385 boost::is_any_of(std::string("-_"))) ||
386 name_.empty() ||
387 // Hyphens and underscores are not allowed at the beginning
388 // and at the end of the option name.
389 all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
390 all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
391 err_str << "invalid option name '" << name_ << "'";
392
393 } else if (!OptionSpace::validateName(option_space_name_)) {
394 err_str << "invalid option space name: '"
395 << option_space_name_ << "'";
396
397 } else if (!encapsulated_space_.empty() &&
398 !OptionSpace::validateName(encapsulated_space_)) {
399 err_str << "invalid encapsulated option space name: '"
400 << encapsulated_space_ << "'";
401
402 } else if (type_ >= OPT_UNKNOWN_TYPE) {
403 // Option definition must be of a known type.
404 err_str << "option type " << type_ << " not supported.";
405
406 } else if (type_ == OPT_RECORD_TYPE) {
407 // At least two data fields should be added to the record. Otherwise
408 // non-record option definition could be used.
409 if (getRecordFields().size() < 2) {
410 err_str << "invalid number of data fields: "
411 << getRecordFields().size()
412 << " specified for the option of type 'record'. Expected at"
413 << " least 2 fields.";
414
415 } else {
416 // If the number of fields is valid we have to check if their order
417 // is valid too. We check that string or binary data fields are not
418 // laid before other fields. But we allow that they are laid at the
419 // end of an option.
420 const RecordFieldsCollection& fields = getRecordFields();
421 for (RecordFieldsConstIter it = fields.begin();
422 it != fields.end(); ++it) {
423 if (*it == OPT_STRING_TYPE &&
424 it < fields.end() - 1) {
425 err_str << "string data field can't be laid before data"
426 << " fields of other types.";
427 break;
428 }
429 if (*it == OPT_BINARY_TYPE &&
430 it < fields.end() - 1) {
431 err_str << "binary data field can't be laid before data"
432 << " fields of other types.";
433 break;
434 }
435 // Empty type is not allowed within a record.
436 if (*it == OPT_EMPTY_TYPE) {
437 err_str << "empty data type can't be stored as a field in"
438 << " an option record.";
439 break;
440 }
441 // Internal type is not allowed within a record.
442 if (*it == OPT_INTERNAL_TYPE) {
443 err_str << "internal data type can't be stored as a field in"
444 << " an option record.";
445 break;
446 }
447 }
448 // If the array flag is set the last field is an array.
449 if (err_str.str().empty() && array_type_) {
450 const OptionDataType& last_type = fields.back();
451 if (last_type == OPT_STRING_TYPE) {
452 err_str
453 << "array of strings is not a valid option definition.";
454 } else if (last_type == OPT_BINARY_TYPE) {
455 err_str << "array of binary values is not a valid option "
456 "definition.";
457 }
458 // Empty type was already checked.
459 }
460 }
461
462 } else if (array_type_) {
463 if (type_ == OPT_STRING_TYPE) {
464 // Array of strings is not allowed because there is no way
465 // to determine the size of a particular string and thus there
466 // it no way to tell when other data fields begin.
467 err_str << "array of strings is not a valid option definition.";
468 } else if (type_ == OPT_BINARY_TYPE) {
469 err_str << "array of binary values is not"
470 << " a valid option definition.";
471
472 } else if (type_ == OPT_EMPTY_TYPE) {
473 err_str << "array of empty value is not"
474 << " a valid option definition.";
475
476 } else if (type_ == OPT_INTERNAL_TYPE) {
477 err_str << "array of internal type value is not"
478 << " a valid option definition.";
479
480 }
481 }
482
483 // Non-empty error string means that we have hit the error. We throw
484 // exception and include error string.
485 if (!err_str.str().empty()) {
486 isc_throw(MalformedOptionDefinition, err_str.str())do { std::ostringstream oss__; oss__ << err_str.str(); throw
MalformedOptionDefinition("../../../src/lib/dhcp/option_definition.cc"
, 486, oss__.str().c_str()); } while (1)
;
487 }
488}
489
490bool
491OptionDefinition::haveCompressedFqdnListFormat() const {
492 return (haveType(OPT_FQDN_TYPE) && getArrayType());
493}
494
495bool
496OptionDefinition::convertToBool(const std::string& value_str) const {
497 // Case-insensitive check that the input is one of: "true" or "false".
498 if (boost::iequals(value_str, "true")) {
499 return (true);
500
501 } else if (boost::iequals(value_str, "false")) {
502 return (false);
503
504 }
505
506 // The input string is neither "true" nor "false", so let's check
507 // if it is not an integer wrapped in a string.
508 int result;
509 try {
510 result = boost::lexical_cast<int>(value_str);
511
512 } catch (const boost::bad_lexical_cast&) {
513 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
("../../../src/lib/dhcp/option_definition.cc", 514, oss__.str
().c_str()); } while (1)
514 << value_str << "' to boolean data type")do { std::ostringstream oss__; oss__ << "unable to covert the value '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 514, oss__.str
().c_str()); } while (1)
;
515 }
516 // The boolean value is encoded in DHCP option as 0 or 1. Therefore,
517 // we only allow a user to specify those values for options which
518 // have boolean fields.
519 if (result != 1 && result != 0) {
520 isc_throw(BadDataTypeCast, "unable to convert '" << value_strdo { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 521, oss__.str
().c_str()); } while (1)
521 << "' to boolean data type")do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 521, oss__.str
().c_str()); } while (1)
;
522 }
523 return (static_cast<bool>(result));
524}
525
526template<typename T>
527T
528OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str)
529 const {
530 // The lexical cast should be attempted when converting to an integer
531 // value only.
532 if (!OptionDataTypeTraits<T>::integer_type) {
533 isc_throw(BadDataTypeCast,do { std::ostringstream oss__; oss__ << "must not convert '"
<< value_str << "' to non-integer data type"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 535, oss__.str().c_str()); } while (1)
534 "must not convert '" << value_strdo { std::ostringstream oss__; oss__ << "must not convert '"
<< value_str << "' to non-integer data type"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 535, oss__.str().c_str()); } while (1)
535 << "' to non-integer data type")do { std::ostringstream oss__; oss__ << "must not convert '"
<< value_str << "' to non-integer data type"; throw
BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 535, oss__.str().c_str()); } while (1)
;
536 }
537
538 // We use the 64-bit value here because it has wider range than
539 // any other type we use here and it allows to detect out of
540 // bounds conditions e.g. negative value specified for uintX_t
541 // data type. Obviously if the value exceeds the limits of int64
542 // this function will not handle that properly.
543 int64_t result = 0;
544 try {
545 result = boost::lexical_cast<int64_t>(value_str);
546
547 } catch (const boost::bad_lexical_cast&) {
548 // boost::lexical_cast does not handle hexadecimal
549 // but stringstream does so do it the hard way.
550 std::stringstream ss;
551 ss << std::hex << value_str;
552 ss >> result;
553 if (ss.fail() || !ss.eof()) {
554 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
("../../../src/lib/dhcp/option_definition.cc", 555, oss__.str
().c_str()); } while (1)
555 << value_str << "' to integer data type")do { std::ostringstream oss__; oss__ << "unable to convert the value '"
<< value_str << "' to integer data type"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 555, oss__.str
().c_str()); } while (1)
;
556 }
557 }
558 // Perform range checks.
559 if (OptionDataTypeTraits<T>::integer_type) {
560 if (result > numeric_limits<T>::max() ||
561 result < numeric_limits<T>::min()) {
562 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("../../../src/lib/dhcp/option_definition.cc"
, 566, oss__.str().c_str()); } while (1)
563 << 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("../../../src/lib/dhcp/option_definition.cc"
, 566, oss__.str().c_str()); } while (1)
564 "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("../../../src/lib/dhcp/option_definition.cc"
, 566, oss__.str().c_str()); } while (1)
565 << +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("../../../src/lib/dhcp/option_definition.cc"
, 566, oss__.str().c_str()); } while (1)
566 << +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("../../../src/lib/dhcp/option_definition.cc"
, 566, oss__.str().c_str()); } while (1)
;
567 }
568 }
569 return (static_cast<T>(result));
570}
571
572void
573OptionDefinition::writeToBuffer(Option::Universe u,
574 const std::string& value,
575 const OptionDataType type,
576 OptionBuffer& buf) const {
577 // We are going to write value given by value argument to the buffer.
578 // The actual type of the value is given by second argument. Check
579 // this argument to determine how to write this value to the buffer.
580 switch (type) {
581 case OPT_BINARY_TYPE:
582 OptionDataTypeUtil::writeBinary(value, buf);
583 return;
584 case OPT_BOOLEAN_TYPE:
585 // We encode the true value as 1 and false as 0 on 8 bits.
586 // That way we actually waste 7 bits but it seems to be the
587 // simpler way to encode boolean.
588 // @todo Consider if any other encode methods can be used.
589 OptionDataTypeUtil::writeBool(convertToBool(value), buf);
590 return;
591 case OPT_INT8_TYPE:
592 OptionDataTypeUtil::writeInt<uint8_t>
593 (lexicalCastWithRangeCheck<int8_t>(value),
594 buf);
595 return;
596 case OPT_INT16_TYPE:
597 OptionDataTypeUtil::writeInt<uint16_t>
598 (lexicalCastWithRangeCheck<int16_t>(value),
599 buf);
600 return;
601 case OPT_INT32_TYPE:
602 OptionDataTypeUtil::writeInt<uint32_t>
603 (lexicalCastWithRangeCheck<int32_t>(value),
604 buf);
605 return;
606 case OPT_UINT8_TYPE:
607 OptionDataTypeUtil::writeInt<uint8_t>
608 (lexicalCastWithRangeCheck<uint8_t>(value),
609 buf);
610 return;
611 case OPT_UINT16_TYPE:
612 OptionDataTypeUtil::writeInt<uint16_t>
613 (lexicalCastWithRangeCheck<uint16_t>(value),
614 buf);
615 return;
616 case OPT_UINT32_TYPE:
617 OptionDataTypeUtil::writeInt<uint32_t>
618 (lexicalCastWithRangeCheck<uint32_t>(value),
619 buf);
620 return;
621 case OPT_IPV4_ADDRESS_TYPE:
622 case OPT_IPV6_ADDRESS_TYPE:
623 {
624 asiolink::IOAddress address(value);
625 if (!address.isV4() && !address.isV6()) {
626 isc_throw(BadDataTypeCast, "provided address "do { std::ostringstream oss__; oss__ << "provided address "
<< address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 628, oss__.str().c_str()); } while (1)
627 << addressdo { std::ostringstream oss__; oss__ << "provided address "
<< address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 628, oss__.str().c_str()); } while (1)
628 << " 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("../../../src/lib/dhcp/option_definition.cc"
, 628, oss__.str().c_str()); } while (1)
;
629 }
630 OptionDataTypeUtil::writeAddress(address, buf);
631 return;
632 }
633 case OPT_IPV6_PREFIX_TYPE:
634 {
635 std::string txt = value;
636
637 // first let's remove any whitespaces
638 boost::erase_all(txt, " "); // space
639 boost::erase_all(txt, "\t"); // tabulation
640
641 // Is this prefix/len notation?
642 size_t pos = txt.find("/");
643
644 if (pos == string::npos) {
645 isc_throw(BadDataTypeCast, "provided address/prefix "do { std::ostringstream oss__; oss__ << "provided address/prefix "
<< value << " is not valid."; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 647, oss__.str
().c_str()); } while (1)
646 << valuedo { std::ostringstream oss__; oss__ << "provided address/prefix "
<< value << " is not valid."; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 647, oss__.str
().c_str()); } while (1)
647 << " is not valid.")do { std::ostringstream oss__; oss__ << "provided address/prefix "
<< value << " is not valid."; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 647, oss__.str
().c_str()); } while (1)
;
648 }
649
650 std::string txt_address = txt.substr(0, pos);
651 isc::asiolink::IOAddress address = isc::asiolink::IOAddress(txt_address);
652 if (!address.isV6()) {
653 isc_throw(BadDataTypeCast, "provided address "do { std::ostringstream oss__; oss__ << "provided address "
<< txt_address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 655, oss__.str().c_str()); } while (1)
654 << txt_addressdo { std::ostringstream oss__; oss__ << "provided address "
<< txt_address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("../../../src/lib/dhcp/option_definition.cc"
, 655, oss__.str().c_str()); } while (1)
655 << " 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("../../../src/lib/dhcp/option_definition.cc"
, 655, oss__.str().c_str()); } while (1)
;
656 }
657
658 std::string txt_prefix = txt.substr(pos + 1);
659 uint8_t len = 0;
660 try {
661 // start with the first character after /
662 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
663 } catch (...) {
664 isc_throw(BadDataTypeCast, "provided prefix "do { std::ostringstream oss__; oss__ << "provided prefix "
<< txt_prefix << " is not valid."; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 666, oss__.str
().c_str()); } while (1)
665 << txt_prefixdo { std::ostringstream oss__; oss__ << "provided prefix "
<< txt_prefix << " is not valid."; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 666, oss__.str
().c_str()); } while (1)
666 << " is not valid.")do { std::ostringstream oss__; oss__ << "provided prefix "
<< txt_prefix << " is not valid."; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 666, oss__.str
().c_str()); } while (1)
;
667 }
668
669 // Write a prefix.
670 OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf);
671
672 return;
673 }
674 case OPT_PSID_TYPE:
675 {
676 std::string txt = value;
677
678 // first let's remove any whitespaces
679 boost::erase_all(txt, " "); // space
680 boost::erase_all(txt, "\t"); // tabulation
681
682 // Is this prefix/len notation?
683 size_t pos = txt.find("/");
684
685 if (pos == string::npos) {
686 isc_throw(BadDataTypeCast, "provided PSID value "do { std::ostringstream oss__; oss__ << "provided PSID value "
<< value << " is not valid"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 687, oss__.str
().c_str()); } while (1)
687 << value << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID value "
<< value << " is not valid"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 687, oss__.str
().c_str()); } while (1)
;
688 }
689
690 const std::string txt_psid = txt.substr(0, pos);
691 const std::string txt_psid_len = txt.substr(pos + 1);
692
693 uint16_t psid = 0;
694 uint8_t psid_len = 0;
695
696 try {
697 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
698 } catch (...) {
699 isc_throw(BadDataTypeCast, "provided PSID "do { std::ostringstream oss__; oss__ << "provided PSID "
<< txt_psid << " is not valid"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 700, oss__.str
().c_str()); } while (1)
700 << txt_psid << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID "
<< txt_psid << " is not valid"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 700, oss__.str
().c_str()); } while (1)
;
701 }
702
703 try {
704 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
705 } catch (...) {
706 isc_throw(BadDataTypeCast, "provided PSID length "do { std::ostringstream oss__; oss__ << "provided PSID length "
<< txt_psid_len << " is not valid"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 707, oss__.str
().c_str()); } while (1)
707 << txt_psid_len << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID length "
<< txt_psid_len << " is not valid"; throw BadDataTypeCast
("../../../src/lib/dhcp/option_definition.cc", 707, oss__.str
().c_str()); } while (1)
;
708 }
709
710 OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf);
711 return;
712 }
713 case OPT_STRING_TYPE:
714 OptionDataTypeUtil::writeString(value, buf);
715 return;
716 case OPT_FQDN_TYPE:
717 OptionDataTypeUtil::writeFqdn(value, buf);
718 return;
719 case OPT_TUPLE_TYPE:
720 {
721 // In case of V4_SZTP_REDIRECT option #143, bootstrap-server-list is formatted
722 // as a list of tuples "uri-length;URI" where uri-length is coded on 2 octets,
723 // which is not typical for V4 Universe.
724 OpaqueDataTuple::LengthFieldType lft = getCode() == DHO_V4_SZTP_REDIRECT
725 ? OpaqueDataTuple::LENGTH_2_BYTES
726 : OptionDataTypeUtil::getTupleLenFieldType(u);
727 OptionDataTypeUtil::writeTuple(value, lft, buf);
728 return;
729 }
730 default:
731 // We hit this point because invalid option data type has been specified
732 // This may be the case because 'empty' or 'record' data type has been
733 // specified. We don't throw exception here because it will be thrown
734 // at the exit point from this function.
735 ;
736 }
737 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
("../../../src/lib/dhcp/option_definition.cc", 738, oss__.str
().c_str()); } while (1)
738 " 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
("../../../src/lib/dhcp/option_definition.cc", 738, oss__.str
().c_str()); } while (1)
;
739
740}
741
742OptionPtr
743OptionDefinition::factoryAddrList4(uint16_t type,
744 OptionBufferConstIter begin,
745 OptionBufferConstIter end) {
746 boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin,
747 end));
748 return (option);
749}
750
751OptionPtr
752OptionDefinition::factoryAddrList6(uint16_t type,
753 OptionBufferConstIter begin,
754 OptionBufferConstIter end) {
755 boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin,
756 end));
757 return (option);
758}
759
760
761OptionPtr
762OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) {
763 OptionPtr option(new Option(u, type));
764 return (option);
765}
766
767OptionPtr
768OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
769 OptionBufferConstIter begin,
770 OptionBufferConstIter end) {
771 OptionPtr option(new Option(u, type, begin, end));
772 return (option);
773}
774
775OptionPtr
776OptionDefinition::factoryIA6(uint16_t type,
777 OptionBufferConstIter begin,
778 OptionBufferConstIter end,
779 size_t rec_level) {
780 if (static_cast<size_t>(std::distance(begin, end)) < Option6IA::OPTION6_IA_LEN) {
781 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("../../../src/lib/dhcp/option_definition.cc"
, 783, oss__.str().c_str()); } while (1)
782 << " 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("../../../src/lib/dhcp/option_definition.cc"
, 783, oss__.str().c_str()); } while (1)
783 << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size,"
<< " expected at least " << Option6IA::OPTION6_IA_LEN
<< " bytes"; throw isc::OutOfRange("../../../src/lib/dhcp/option_definition.cc"
, 783, oss__.str().c_str()); } while (1)
;
784 }
785 boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end, rec_level));
786 return (option);
787}
788
789OptionPtr
790OptionDefinition::factoryIAAddr6(uint16_t type,
791 OptionBufferConstIter begin,
792 OptionBufferConstIter end,
793 size_t rec_level) {
794 if (static_cast<size_t>(std::distance(begin, end)) < Option6IAAddr::OPTION6_IAADDR_LEN) {
795 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("../../../src/lib/dhcp/option_definition.cc"
, 797, oss__.str().c_str()); } while (1)
796 "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("../../../src/lib/dhcp/option_definition.cc"
, 797, oss__.str().c_str()); } while (1)
797 << 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("../../../src/lib/dhcp/option_definition.cc"
, 797, oss__.str().c_str()); } while (1)
;
798 }
799 boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin,
800 end, rec_level));
801 return (option);
802}
803
804OptionPtr
805OptionDefinition::factoryIAPrefix6(uint16_t type,
806 OptionBufferConstIter begin,
807 OptionBufferConstIter end,
808 size_t rec_level) {
809 if (static_cast<size_t>(std::distance(begin, end)) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) {
810 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("../../../src/lib/dhcp/option_definition.cc"
, 812, oss__.str().c_str()); } while (1)
811 "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("../../../src/lib/dhcp/option_definition.cc"
, 812, oss__.str().c_str()); } while (1)
812 << 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("../../../src/lib/dhcp/option_definition.cc"
, 812, oss__.str().c_str()); } while (1)
;
813 }
814 boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin,
815 end,
816 rec_level));
817 return (option);
818}
819
820OptionPtr
821OptionDefinition::factoryOpaqueDataTuples(Option::Universe u,
822 uint16_t type,
823 OptionBufferConstIter begin,
824 OptionBufferConstIter end) {
825 boost::shared_ptr<OptionOpaqueDataTuples>
826 option(new OptionOpaqueDataTuples(u, type, begin, end));
827
828 return (option);
829}
830
831OptionPtr
832OptionDefinition::factoryOpaqueDataTuples(Option::Universe u,
833 uint16_t type,
834 OptionBufferConstIter begin,
835 OptionBufferConstIter end,
836 OpaqueDataTuple::LengthFieldType length_field_type) {
837 boost::shared_ptr<OptionOpaqueDataTuples>
838 option(new OptionOpaqueDataTuples(u, type, begin, end, length_field_type));
839
840 return (option);
841}
842
843OptionPtr
844OptionDefinition::factoryFqdnList(Option::Universe u,
845 OptionBufferConstIter begin,
846 OptionBufferConstIter end) const {
847
848 const std::vector<uint8_t> data(begin, end);
849 if (data.empty()) {
850 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("../../../src/lib/dhcp/option_definition.cc"
, 850, oss__.str().c_str()); } while (1)
;
851 }
852 InputBuffer in_buf(static_cast<const void*>(&data[0]), data.size());
853 std::vector<uint8_t> out_buf;
854 out_buf.reserve(data.size());
855 while (in_buf.getPosition() < in_buf.getLength()) {
856 // Reuse readFqdn and writeFqdn code but on the whole buffer
857 // so the DNS name code handles compression for us.
858 try {
859 isc::dns::Name name(in_buf);
860 isc::dns::LabelSequence labels(name);
861 if (labels.getDataLength() > 0) {
862 size_t read_len = 0;
863 const uint8_t* label = labels.getData(&read_len);
864 out_buf.insert(out_buf.end(), label, label + read_len);
865 }
866 } catch (const isc::Exception& ex) {
867 if (Option::lenient_parsing_) {
868 isc_throw(SkipThisOptionError,do { std::ostringstream oss__; oss__ << "invalid FQDN list content: "
<< ex.what(); throw SkipThisOptionError("../../../src/lib/dhcp/option_definition.cc"
, 869, oss__.str().c_str()); } while (1)
869 "invalid FQDN list content: " << ex.what())do { std::ostringstream oss__; oss__ << "invalid FQDN list content: "
<< ex.what(); throw SkipThisOptionError("../../../src/lib/dhcp/option_definition.cc"
, 869, oss__.str().c_str()); } while (1)
;
870 }
871
872 isc_throw(InvalidOptionValue, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
InvalidOptionValue("../../../src/lib/dhcp/option_definition.cc"
, 872, oss__.str().c_str()); } while (1)
;
873 }
874 }
875 return OptionPtr(new OptionCustom(*this, u,
876 out_buf.begin(), out_buf.end()));
877}
878
879OptionPtr
880OptionDefinition::factorySpecialFormatOption(Option::Universe u,
881 OptionBufferConstIter begin,
882 OptionBufferConstIter end,
883 bool convenient_notation,
884 size_t rec_level) const {
885 if ((u == Option::V6) && haveSpace(DHCP6_OPTION_SPACE"dhcp6")) {
886 switch (getCode()) {
887 case D6O_IA_NA:
888 case D6O_IA_PD:
889 // Record of 3 uint32, no array.
890 return (factoryIA6(getCode(), begin, end, rec_level));
891
892 case D6O_IAADDR:
893 // Record of an IPv6 address followed by 2 uint32, no array.
894 return (factoryIAAddr6(getCode(), begin, end, rec_level));
895
896 case D6O_IAPREFIX:
897 // Record of 2 uint32, one uint8 and an IPv6 address, no array.
898 return (factoryIAPrefix6(getCode(), begin, end, rec_level));
899
900 case D6O_CLIENT_FQDN:
901 // Record of one uint8 and one FQDN, no array.
902 return (OptionPtr(new Option6ClientFqdn(begin, end)));
903
904 case D6O_VENDOR_OPTS:
905 // Type uint32.
906 // Vendor-Specific Information (option code 17).
907 return (OptionPtr(new OptionVendor(Option::V6, begin, end)));
908
909 case D6O_VENDOR_CLASS:
910 // Record of one uint32 and one string.
911 // Vendor Class (option code 16).
912 return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
913
914 case D6O_STATUS_CODE:
915 // Record of one uint16 and one string.
916 // Status Code (option code 13).
917 return (OptionPtr(new Option6StatusCode(begin, end)));
918
919 case D6O_BOOTFILE_PARAM:
920 // Array of tuples.
921 // Bootfile params (option code 60).
922 return (factoryOpaqueDataTuples(Option::V6, getCode(), begin, end));
923
924 case D6O_PD_EXCLUDE:
925 // Type IPv6 prefix.
926 // Prefix Exclude (option code 67),
927 return (OptionPtr(new Option6PDExclude(begin, end)));
928
929 case D6O_V6_DNR:
930 return (OptionPtr(new Option6Dnr(begin, end, convenient_notation)));
931
932 default:
933 break;
934 }
935 } else if ((u == Option::V4) && haveSpace(DHCP4_OPTION_SPACE"dhcp4")) {
936 switch (getCode()) {
937 case DHO_SERVICE_SCOPE:
938 // Record of a boolean and a string.
939 return (OptionPtr(new Option4SlpServiceScope(begin, end)));
940
941 case DHO_FQDN:
942 // Record of 3 uint8 and a FQDN, no array.
943 return (OptionPtr(new Option4ClientFqdn(begin, end)));
944
945 case DHO_CLASSLESS_STATIC_ROUTE:
946 return (OptionPtr(new OptionClasslessStaticRoute(begin, end, convenient_notation)));
947
948 case DHO_VIVCO_SUBOPTIONS:
949 // Record of uint32 followed by binary.
950 // V-I Vendor Class (option code 124).
951 return (OptionPtr(new OptionVendorClass(Option::V4, begin, end)));
952
953 case DHO_VIVSO_SUBOPTIONS:
954 // Type uint32.
955 // Vendor-Specific Information (option code 125).
956 return (OptionPtr(new OptionVendor(Option::V4, begin, end)));
957
958 case DHO_V4_SZTP_REDIRECT:
959 // Array of tuples.
960 // DHCPv4 SZTP Redirect Option (option code 143).
961 return (factoryOpaqueDataTuples(Option::V4, getCode(), begin, end, OpaqueDataTuple::LENGTH_2_BYTES));
962
963 case DHO_V4_DNR:
964 return (OptionPtr(new Option4Dnr(begin, end, convenient_notation)));
965
966 default:
967 break;
968 }
969 }
970 if ((u == Option::V4) && haveCompressedFqdnListFormat()) {
971 return (factoryFqdnList(Option::V4, begin, end));
972 }
973 return (OptionPtr());
974}
975
976} // end of isc::dhcp namespace
977} // end of isc namespace

/usr/include/boost/algorithm/string/classification.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_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
29namespace 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));
2
Calling copy constructor for 'is_any_ofF<char>'
5
Returning from copy constructor for 'is_any_ofF<char>'
6
Calling '~is_any_ofF'
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

/usr/include/boost/algorithm/string/detail/classification.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
27namespace 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))
3
Taking false branch
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];
4
Memory is allocated
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 }
7
Potential memory leak
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