| 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-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 | ||||
| 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 ("../../../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 | ||||
| 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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 ("../../../src/lib/dhcp/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 (static_cast<size_t>(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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 (static_cast<size_t>(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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 (static_cast<size_t>(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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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("../../../src/lib/dhcp/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 |