| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | // Copyright (c) 2000-2014 Ericsson Telecom AB |
| 3 | // All rights reserved. This program and the accompanying materials |
| 4 | // are made available under the terms of the Eclipse Public License v1.0 |
| 5 | // which accompanies this distribution, and is available at |
| 6 | // http://www.eclipse.org/legal/epl-v10.html |
| 7 | /////////////////////////////////////////////////////////////////////////////// |
| 8 | #include "Constraint.hh" |
| 9 | #include "CompilerError.hh" |
| 10 | #include "Int.hh" |
| 11 | #include "Type.hh" |
| 12 | #include "Value.hh" |
| 13 | #include "subtype.hh" |
| 14 | #include "Identifier.hh" |
| 15 | #include "CompField.hh" |
| 16 | #include "asn1/Block.hh" |
| 17 | #include "asn1/TokenBuf.hh" |
| 18 | |
| 19 | namespace Common { |
| 20 | |
| 21 | // ================================= |
| 22 | // ===== Constraints |
| 23 | // ================================= |
| 24 | |
| 25 | Constraints::Constraints(const Constraints& p) |
| 26 | : Node(p), cons(), my_type(0), subtype(0), extendable(false), extension(0) |
| 27 | { |
| 28 | size_t nof_cons = p.cons.size(); |
| 29 | for (size_t i = 0; i < nof_cons; i++) cons.add(p.cons[i]->clone()); |
| 30 | } |
| 31 | |
| 32 | Constraints::~Constraints() |
| 33 | { |
| 34 | size_t nof_cons = cons.size(); |
| 35 | for (size_t i = 0; i < nof_cons; i++) delete cons[i]; |
| 36 | cons.clear(); |
| 37 | delete subtype; |
| 38 | delete extension; |
| 39 | } |
| 40 | |
| 41 | Constraints *Constraints::clone() const |
| 42 | { |
| 43 | return new Constraints(*this); |
| 44 | } |
| 45 | |
| 46 | void Constraints::add_con(Constraint *p_con) |
| 47 | { |
| 48 | if (!p_con) FATAL_ERROR("Constraints::add_con()"); |
| 49 | cons.add(p_con); |
| 50 | if (my_type) p_con->set_my_type(my_type); |
| 51 | } |
| 52 | |
| 53 | Constraint* Constraints::get_tableconstraint() const |
| 54 | { |
| 55 | size_t nof_cons = cons.size(); |
| 56 | for (size_t i = 0; i < nof_cons; i++) { |
| 57 | Constraint *con = cons[i]; |
| 58 | if (con->get_constrtype() == Constraint::CT_TABLE) return con; |
| 59 | } |
| 60 | return 0; |
| 61 | } |
| 62 | |
| 63 | void Constraints::set_my_type(Type *p_my_type) |
| 64 | { |
| 65 | my_type=p_my_type; |
| 66 | size_t nof_cons = cons.size(); |
| 67 | for (size_t i = 0; i < nof_cons; i++) cons[i]->set_my_type(p_my_type); |
| 68 | } |
| 69 | |
| 70 | void Constraints::chk_table() |
| 71 | { |
| 72 | if(!my_type) FATAL_ERROR("Constraints::chk_table()"); |
| 73 | size_t nof_cons = cons.size(); |
| 74 | for (size_t i = 0; i < nof_cons; i++) { |
| 75 | Error_Context cntxt(my_type, "In constraint #%lu of type `%s'", |
| 76 | (unsigned long) (i + 1), my_type->get_typename().c_str()); |
| 77 | Constraint::constrtype_t cst = cons[i]->get_constrtype(); |
| 78 | if (cst==Constraint::CT_TABLE) cons[i]->chk(); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | void Constraints::chk(SubtypeConstraint* parent_subtype) |
| 83 | { |
| 84 | if(!my_type) FATAL_ERROR("Common::Constraints::chk()"); |
| 85 | if (parent_subtype) { |
| 86 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 87 | subtype->copy(parent_subtype); |
| 88 | } |
| 89 | size_t nof_cons = cons.size(); |
| 90 | for (size_t i = 0; i < nof_cons; i++) { |
| 91 | Error_Context cntxt(my_type, "In constraint #%lu of type `%s'", |
| 92 | (unsigned long) (i + 1), my_type->get_typename().c_str()); |
| 93 | cons[i]->set_fullname(my_type->get_fullname()+".<constraint_"+Int2string(i+1)+">.<"+string(cons[i]->get_name())+">"); |
| 94 | cons[i]->set_my_cons(this); |
| 95 | Constraint::constrtype_t cst = cons[i]->get_constrtype(); |
| 96 | if (cst!=Constraint::CT_TABLE) cons[i]->chk(); |
| 97 | if ( (cst==Constraint::CT_IGNORE) || (cst==Constraint::CT_TABLE) ) continue; // ignore |
| 98 | SubtypeConstraint* sc = cons[i]->get_subtype(); |
| 99 | SubtypeConstraint* sc_ext = cons[i]->get_extension(); |
| 100 | if (!sc) break; // stop on error |
| 101 | extendable = cons[i]->is_extendable(); |
| 102 | if (extension) { // only the root part shall be kept |
| 103 | delete extension; |
| 104 | extension = 0; |
| 105 | } |
| 106 | if (subtype) { |
| 107 | if (sc->is_subset(subtype)==TFALSE) { |
| 108 | cons[i]->error("Constraint #%lu is %s, this is not a subset of %s", |
| 109 | (unsigned long) (i + 1), |
| 110 | sc->to_string().c_str(), |
| 111 | subtype->to_string().c_str()); |
| 112 | break; // stop on error |
| 113 | } |
| 114 | if (sc_ext && (sc_ext->is_subset(subtype)==TFALSE)) { |
| 115 | cons[i]->error("Extension addition of constraint #%lu is %s, this is not a subset of %s", |
| 116 | (unsigned long) (i + 1), |
| 117 | sc_ext->to_string().c_str(), |
| 118 | subtype->to_string().c_str()); |
| 119 | break; // stop on error |
| 120 | } |
| 121 | if (sc_ext) { |
| 122 | extension = new SubtypeConstraint(my_type->get_subtype_type()); |
| 123 | extension->copy(sc_ext); |
| 124 | extension->intersection(subtype); |
| 125 | } |
| 126 | subtype->intersection(sc); |
| 127 | } else { |
| 128 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 129 | subtype->copy(sc); |
| 130 | if (sc_ext) { |
| 131 | extension = new SubtypeConstraint(my_type->get_subtype_type()); |
| 132 | extension->copy(sc_ext); |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | // ================================= |
| 139 | // ===== Constraint |
| 140 | // ================================= |
| 141 | |
| 142 | Constraint::Constraint(const Constraint& p): |
| 143 | Node(p), Location(p), constrtype(p.constrtype), |
| 144 | my_type(0), my_scope(0), my_parent(0), my_cons(0), |
| 145 | checked(false), subtype(0), extendable(false), extension(0) |
| 146 | { |
| 147 | } |
| 148 | |
| 149 | Constraint::Constraint(constrtype_t p_constrtype): |
| 150 | Node(), Location(), constrtype(p_constrtype), |
| 151 | my_type(0), my_scope(0), my_parent(0), my_cons(0), |
| 152 | checked(false), subtype(0), extendable(false), extension(0) |
| 153 | { |
| 154 | } |
| 155 | |
| 156 | Constraint::~Constraint() |
| 157 | { |
| 158 | delete subtype; |
| 159 | delete extension; |
| 160 | } |
| 161 | |
| 162 | Scope* Constraint::get_my_scope() |
| 163 | { |
| 164 | if (!my_type) FATAL_ERROR("Constraint::get_my_scope()"); |
| 165 | return my_scope ? my_scope : my_type->get_my_scope(); |
| 166 | } |
| 167 | |
| 168 | void Constraint::set_my_cons(Constraints* p_my_cons) |
| 169 | { |
| 170 | my_cons = p_my_cons; |
| 171 | } |
| 172 | |
| 173 | Constraints* Constraint::get_my_cons() |
| 174 | { |
| 175 | Constraint* c = this; |
| 176 | while (c) { |
| 177 | if (c->my_cons) return c->my_cons; |
| 178 | c = c->my_parent; |
| 179 | } |
| 180 | FATAL_ERROR("Constraint::get_my_cons()"); |
| 181 | return NULL; |
| 182 | } |
| 183 | |
| 184 | bool Constraint::in_char_context() const |
| 185 | { |
| 186 | Constraint* parent = my_parent; |
| 187 | while (parent) { |
| 188 | if (parent->get_constrtype()==CT_PERMITTEDALPHABET) return true; |
| 189 | parent = parent->get_my_parent(); |
| 190 | } |
| 191 | return false; |
| 192 | } |
| 193 | |
| 194 | bool Constraint::in_inner_constraint() const |
| 195 | { |
| 196 | Constraint* parent = my_parent; |
| 197 | while (parent) { |
| 198 | switch (parent->get_constrtype()) { |
| 199 | case CT_SINGLEINNERTYPE: |
| 200 | case CT_MULTIPLEINNERTYPE: |
| 201 | return true; |
| 202 | default: |
| 203 | break; |
| 204 | } |
| 205 | parent = parent->get_my_parent(); |
| 206 | } |
| 207 | return false; |
| 208 | } |
| 209 | |
| 210 | // ================================= |
| 211 | // ===== ElementSetSpecsConstraint |
| 212 | // ================================= |
| 213 | |
| 214 | ElementSetSpecsConstraint::ElementSetSpecsConstraint(const ElementSetSpecsConstraint& p) |
| 215 | : Constraint(p) |
| 216 | { |
| 217 | extendable = true; |
| 218 | root_constr = p.root_constr ? p.root_constr->clone() : 0; |
| 219 | ext_constr = p.ext_constr ? p.ext_constr->clone() : 0; |
| 220 | } |
| 221 | |
| 222 | ElementSetSpecsConstraint::ElementSetSpecsConstraint(Constraint* p_root_constr, Constraint* p_ext_constr) |
| 223 | : Constraint(CT_ELEMENTSETSPEC), root_constr(p_root_constr), ext_constr(p_ext_constr) |
| 224 | { |
| 225 | if (!p_root_constr) FATAL_ERROR("ElementSetSpecsConstraint::ElementSetSpecsConstraint()"); |
| 226 | // p_ext_constr can be NULL |
| 227 | extendable = true; |
| 228 | } |
| 229 | |
| 230 | ElementSetSpecsConstraint::~ElementSetSpecsConstraint() |
| 231 | { |
| 232 | delete root_constr; |
| 233 | delete ext_constr; |
| 234 | } |
| 235 | |
| 236 | void ElementSetSpecsConstraint::chk() |
| 237 | { |
| 238 | if (checked) return; |
| 239 | checked = true; |
| 240 | if (!root_constr || !my_type) FATAL_ERROR("ElementSetSpecsConstraint::chk()"); |
| 241 | Error_Context cntxt(this, "While checking ElementSetSpecs constraint"); |
| 242 | root_constr->set_my_type(my_type); |
| 243 | if (ext_constr) ext_constr->set_my_type(my_type); |
| 244 | root_constr->set_my_scope(get_my_scope()); |
| 245 | if (ext_constr) ext_constr->set_my_scope(get_my_scope()); |
| 246 | root_constr->set_my_parent(this); |
| 247 | if (ext_constr) ext_constr->set_my_parent(this); |
| 248 | root_constr->chk(); |
| 249 | if (ext_constr) ext_constr->chk(); |
| 250 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); |
| 251 | // naming ((r1,x1),...,(r2,x2)) according to X.680(11/2008) I.4.3.8 |
| 252 | SubtypeConstraint* r1 = root_constr->get_subtype(); |
| 253 | if (!r1) return; // root_constr is invalid, error already reported there |
| 254 | SubtypeConstraint* x1 = root_constr->get_extension(); |
| 255 | if (!ext_constr) { |
| 256 | // only root part exists |
| 257 | subtype = new SubtypeConstraint(my_subtype_type); |
| 258 | subtype->copy(r1); |
| 259 | if (x1) { |
| 260 | extension = new SubtypeConstraint(my_subtype_type); |
| 261 | extension->copy(x1); |
| 262 | } |
| 263 | return; |
| 264 | } |
| 265 | SubtypeConstraint* r2 = ext_constr->get_subtype(); |
| 266 | if (!r2) return; // ext_constr is invalid, error already reported there |
| 267 | SubtypeConstraint* x2 = ext_constr->get_extension(); |
| 268 | subtype = new SubtypeConstraint(my_subtype_type); |
| 269 | subtype->copy(r1); |
| 270 | extension = new SubtypeConstraint(my_subtype_type); |
| 271 | extension->copy(r2); |
| 272 | if (x1) extension->union_(x1); |
| 273 | if (x2) extension->union_(x2); |
| 274 | extension->except(r1); |
| 275 | } |
| 276 | |
| 277 | void ElementSetSpecsConstraint::set_fullname(const string& p_fullname) |
| 278 | { |
| 279 | Node::set_fullname(p_fullname); |
| 280 | root_constr->set_fullname(p_fullname+".<root_part>.<"+string(root_constr->get_name())+">"); |
| 281 | if (ext_constr) |
| 282 | ext_constr->set_fullname(p_fullname+".<extension_part>.<"+string(ext_constr->get_name())+">"); |
| 283 | } |
| 284 | |
| 285 | // ================================= |
| 286 | // ===== IgnoredConstraint |
| 287 | // ================================= |
| 288 | |
| 289 | IgnoredConstraint::IgnoredConstraint(const IgnoredConstraint& p) |
| 290 | : Constraint(p), my_name(p.my_name) |
| 291 | { |
| 292 | } |
| 293 | |
| 294 | IgnoredConstraint::IgnoredConstraint(const char* p_name) |
| 295 | : Constraint(CT_IGNORE), my_name(p_name) |
| 296 | { |
| 297 | if (p_name==NULL) FATAL_ERROR("IgnoredConstraint::IgnoredConstraint()"); |
| 298 | } |
| 299 | |
| 300 | void IgnoredConstraint::chk() |
| 301 | { |
| 302 | if (checked) return; |
| 303 | checked = true; |
| 304 | if (!my_type) FATAL_ERROR("IgnoredConstraint::chk()"); |
| 305 | if (in_char_context()) { |
| 306 | error("%s not allowed inside a permitted alphabet constraint", get_name()); |
| 307 | return; |
| 308 | } else { |
| 309 | if (my_parent) warning("%s inside a %s is treated as `ALL' (constraint is dropped)", get_name(), my_parent->get_name()); |
| 310 | //else warning("%s is ignored", get_name()); |
| 311 | } |
| 312 | // ignored constraint does not constrain the type, set to full set |
| 313 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 314 | } |
| 315 | |
| 316 | // ================================= |
| 317 | // ===== SingleValueConstraint |
| 318 | // ================================= |
| 319 | |
| 320 | SingleValueConstraint::SingleValueConstraint(const SingleValueConstraint& p) |
| 321 | : Constraint(p) |
| 322 | { |
| 323 | value = p.value ? p.value->clone() : 0; |
| 324 | } |
| 325 | |
| 326 | SingleValueConstraint::~SingleValueConstraint() |
| 327 | { |
| 328 | delete value; |
| 329 | } |
| 330 | |
| 331 | SingleValueConstraint::SingleValueConstraint(Value* p_value) |
| 332 | : Constraint(CT_SINGLEVALUE), value(p_value) |
| 333 | { |
| 334 | if (!p_value) FATAL_ERROR("SingleValueConstraint::SingleValueConstraint()"); |
| 335 | } |
| 336 | |
| 337 | void SingleValueConstraint::chk() |
| 338 | { |
| 339 | if (checked) return; |
| 340 | checked = true; |
| 341 | if (!value || !my_type) FATAL_ERROR("SingleValueConstraint::chk()"); |
| 342 | Error_Context cntxt(this, "While checking single value constraint"); |
| 343 | value->set_my_scope(get_my_scope()); |
| 344 | value->set_my_governor(my_type); |
| 345 | my_type->chk_this_value_ref(value); |
| 346 | my_type->chk_this_value(value, 0, Type::EXPECTED_CONSTANT, |
| 347 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); |
| 348 | if (in_char_context()) { |
| 349 | subtype = SubtypeConstraint::create_from_asn_charvalues(my_type, value); |
| 350 | } else { |
| 351 | subtype = SubtypeConstraint::create_from_asn_value(my_type, value); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | void SingleValueConstraint::set_fullname(const string& p_fullname) |
| 356 | { |
| 357 | Node::set_fullname(p_fullname); |
| 358 | value->set_fullname(p_fullname+".<value>"); |
| 359 | } |
| 360 | |
| 361 | // ================================= |
| 362 | // ===== ContainedSubtypeConstraint |
| 363 | // ================================= |
| 364 | |
| 365 | ContainedSubtypeConstraint::ContainedSubtypeConstraint(const ContainedSubtypeConstraint& p) |
| 366 | : Constraint(p) |
| 367 | { |
| 368 | type = p.type ? p.type->clone() : 0; |
| 369 | } |
| 370 | |
| 371 | ContainedSubtypeConstraint::~ContainedSubtypeConstraint() |
| 372 | { |
| 373 | delete type; |
| 374 | } |
| 375 | |
| 376 | ContainedSubtypeConstraint::ContainedSubtypeConstraint(Type* p_type, bool p_has_includes) |
| 377 | : Constraint(CT_CONTAINEDSUBTYPE), type(p_type), has_includes(p_has_includes) |
| 378 | { |
| 379 | if (!p_type) FATAL_ERROR("ContainedSubtypeConstraint::ContainedSubtypeConstraint()"); |
| 380 | } |
| 381 | |
| 382 | void ContainedSubtypeConstraint::chk() |
| 383 | { |
| 384 | if (checked) return; |
| 385 | checked = true; |
| 386 | if (!type || !my_type) FATAL_ERROR("ContainedSubtypeConstraint::chk()"); |
| 387 | Error_Context cntxt(this, "While checking contained subtype constraint"); |
| 388 | |
| 389 | type->set_my_scope(get_my_scope()); |
| 390 | type->chk(); |
| 391 | if (type->get_typetype()==Type::T_ERROR) return; |
| 392 | |
| 393 | if (my_type->get_type_refd_last()->get_typetype()==Type::T_OPENTYPE) { |
| 394 | // TODO: open type and anytype should have their own ST_ANY subtype, now this is only ignored |
| 395 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 396 | return; |
| 397 | } |
| 398 | |
| 399 | if (!type->is_identical(my_type)) { |
| 400 | error("Contained subtype constraint is invalid, constrained and constraining types have different root type"); |
| 401 | return; |
| 402 | } |
| 403 | // check subtype of referenced type |
| 404 | SubType* t_st = type->get_sub_type(); |
| 405 | if (t_st==NULL) { |
| 406 | error("Contained subtype constraint is invalid, the constraining type has no subtype constraint"); |
| 407 | return; |
| 408 | } |
| 409 | |
| 410 | // check circular subtype reference |
| 411 | Type* my_owner = get_my_cons()->get_my_type(); |
| 412 | if (!my_owner || !my_owner->get_sub_type()) FATAL_ERROR("ContainedSubtypeConstraint::chk()"); |
| 413 | if (!my_owner->get_sub_type()->add_parent_subtype(t_st)) return; |
| 414 | |
| 415 | if (t_st->get_subtypetype()==SubtypeConstraint::ST_ERROR) return; |
| 416 | if (t_st->get_subtypetype()!=my_type->get_subtype_type()) FATAL_ERROR("ContainedSubtypeConstraint::chk()"); |
| 417 | |
| 418 | subtype = SubtypeConstraint::create_from_contained_subtype(t_st->get_root(), in_char_context(), this); |
| 419 | } |
| 420 | |
| 421 | void ContainedSubtypeConstraint::set_fullname(const string& p_fullname) |
| 422 | { |
| 423 | Node::set_fullname(p_fullname); |
| 424 | type->set_fullname(p_fullname+".<type>"); |
| 425 | } |
| 426 | |
| 427 | // ================================= |
| 428 | // ===== RangeEndpoint |
| 429 | // ================================= |
| 430 | |
| 431 | RangeEndpoint::RangeEndpoint(const RangeEndpoint& p): |
| 432 | Node(p), Location(p), type(p.type), inclusive(p.inclusive) |
| 433 | { |
| 434 | value = p.value ? p.value->clone() : 0; |
| 435 | } |
| 436 | |
| 437 | RangeEndpoint::~RangeEndpoint() |
| 438 | { |
| 439 | delete value; |
| 440 | } |
| 441 | |
| 442 | RangeEndpoint::RangeEndpoint(endpoint_t p_type): |
| 443 | Node(), Location(), type(p_type), value(0), inclusive(true) |
| 444 | { |
| 445 | if (type==VALUE) FATAL_ERROR("RangeEndpoint::RangeEndpoint()"); |
| 446 | } |
| 447 | |
| 448 | RangeEndpoint::RangeEndpoint(Value* p_value): |
| 449 | Node(), Location(), type(RangeEndpoint::VALUE), value(p_value), inclusive(true) |
| 450 | { |
| 451 | if (!p_value) FATAL_ERROR("RangeEndpoint::RangeEndpoint()"); |
| 452 | } |
| 453 | |
| 454 | void RangeEndpoint::chk(Type* my_type, ValueRangeConstraint* constraint) |
| 455 | { |
| 456 | if (value) { |
| 457 | value->set_my_scope(constraint->get_my_scope()); |
| 458 | my_type->chk_this_value_ref(value); |
| 459 | my_type->chk_this_value(value, 0, Type::EXPECTED_CONSTANT, |
| 460 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | void RangeEndpoint::set_fullname(const string& p_fullname) |
| 465 | { |
| 466 | Node::set_fullname(p_fullname); |
| 467 | if (value) value->set_fullname(p_fullname+".<value>"); |
| 468 | } |
| 469 | |
| 470 | // ================================= |
| 471 | // ===== ValueRangeConstraint |
| 472 | // ================================= |
| 473 | |
| 474 | ValueRangeConstraint::ValueRangeConstraint(const ValueRangeConstraint& p) |
| 475 | : Constraint(p) |
| 476 | { |
| 477 | lower_endpoint = p.lower_endpoint ? p.lower_endpoint->clone() : 0; |
| 478 | upper_endpoint = p.upper_endpoint ? p.upper_endpoint->clone() : 0; |
| 479 | } |
| 480 | |
| 481 | ValueRangeConstraint::ValueRangeConstraint(RangeEndpoint* p_lower, RangeEndpoint* p_upper) |
| 482 | : Constraint(CT_VALUERANGE), lower_endpoint(p_lower), upper_endpoint(p_upper) |
| 483 | { |
| 484 | if (!p_lower || !p_upper) FATAL_ERROR("ValueRangeConstraint::ValueRangeConstraint()"); |
| 485 | } |
| 486 | |
| 487 | void ValueRangeConstraint::chk() |
| 488 | { |
| 489 | if (checked) return; |
| 490 | checked = true; |
| 491 | if (!lower_endpoint || !upper_endpoint || !my_type) FATAL_ERROR("ValueRangeConstraint::chk()"); |
| 492 | Error_Context cntxt(this, "While checking value range constraint"); |
| 493 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); |
| 494 | switch (my_subtype_type) { |
| 495 | case SubtypeConstraint::ST_INTEGER: |
| 496 | case SubtypeConstraint::ST_FLOAT: |
| 497 | break; |
| 498 | case SubtypeConstraint::ST_CHARSTRING: |
| 499 | switch (my_type->get_type_refd_last()->get_typetype()) { |
| 500 | case Type::T_NUMERICSTRING: |
| 501 | case Type::T_PRINTABLESTRING: |
| 502 | case Type::T_IA5STRING: |
| 503 | case Type::T_VISIBLESTRING: |
| 504 | if (!in_char_context()) { |
| 505 | error("Value range constraint must be inside a permitted alphabet or size constraint"); |
| 506 | return; |
| 507 | } |
| 508 | break; |
| 509 | default: |
| 510 | error("Value range constraint is not allowed for type `%s'", my_type->get_typename().c_str()); |
| 511 | return; |
| 512 | } |
| 513 | break; |
| 514 | case SubtypeConstraint::ST_UNIVERSAL_CHARSTRING: |
| 515 | switch (my_type->get_type_refd_last()->get_typetype()) { |
| 516 | case Type::T_UTF8STRING: |
| 517 | case Type::T_UNIVERSALSTRING: |
| 518 | case Type::T_BMPSTRING: |
| 519 | if (!in_char_context()) { |
| 520 | error("Value range constraint must be inside a permitted alphabet or size constraint"); |
| 521 | return; |
| 522 | } |
| 523 | break; |
| 524 | default: |
| 525 | error("Value range constraint is not allowed for type `%s'", my_type->get_typename().c_str()); |
| 526 | return; |
| 527 | } |
| 528 | break; |
| 529 | default: |
| 530 | error("Value range constraint is not allowed for type `%s'", my_type->get_typename().c_str()); |
| 531 | return; |
| 532 | } |
| 533 | lower_endpoint->chk(my_type, this); |
| 534 | upper_endpoint->chk(my_type, this); |
| 535 | Value* vmin = lower_endpoint->get_value(); |
| 536 | if (vmin) vmin = vmin->get_value_refd_last(); |
| 537 | Value* vmax = upper_endpoint->get_value(); |
| 538 | if (vmax) vmax = vmax->get_value_refd_last(); |
| 539 | // the subtype of the Constraints object at the time of calling this chk() |
| 540 | // function is constructed from all the previously calculated constraints |
| 541 | // (it is not yet the final subtype). This is needed to calculate the |
| 542 | // current MIN and MAX values. |
| 543 | SubtypeConstraint* parent_subtype = get_my_cons()->get_subtype(); |
| 544 | subtype = SubtypeConstraint::create_from_asn_range( |
| 545 | vmin, lower_endpoint->get_exclusive(), |
| 546 | vmax, upper_endpoint->get_exclusive(), |
| 547 | this, my_subtype_type, |
| 548 | in_inner_constraint() ? NULL /*the parent is invalid for an inner field*/ : parent_subtype); |
| 549 | } |
| 550 | |
| 551 | void ValueRangeConstraint::set_fullname(const string& p_fullname) |
| 552 | { |
| 553 | Node::set_fullname(p_fullname); |
| 554 | lower_endpoint->set_fullname(p_fullname+".<lower_endpoint>"); |
| 555 | upper_endpoint->set_fullname(p_fullname+".<upper_endpoint>"); |
| 556 | } |
| 557 | |
| 558 | // ================================= |
| 559 | // ===== SizeConstraint |
| 560 | // ================================= |
| 561 | |
| 562 | SizeConstraint::SizeConstraint(const SizeConstraint& p) |
| 563 | : Constraint(p) |
| 564 | { |
| 565 | constraint = p.constraint ? p.constraint->clone() : 0; |
| 566 | } |
| 567 | |
| 568 | SizeConstraint::SizeConstraint(Constraint* p) |
| 569 | : Constraint(CT_SIZE), constraint(p) |
| 570 | { |
| 571 | if (!p) FATAL_ERROR("SizeConstraint::SizeConstraint()"); |
| 572 | } |
| 573 | |
| 574 | void SizeConstraint::chk() |
| 575 | { |
| 576 | if (checked) return; |
| 577 | checked = true; |
| 578 | if (!constraint || !my_type) FATAL_ERROR("SizeConstraint::chk()"); |
| 579 | Error_Context cntxt(this, "While checking size constraint"); |
| 580 | constraint->set_my_type(Type::get_pooltype(Type::T_INT_A)); |
| 581 | constraint->set_my_scope(get_my_scope()); |
| 582 | constraint->set_my_parent(this); |
| 583 | constraint->chk(); |
| 584 | subtype = SubtypeConstraint::create_asn_size_constraint( |
| 585 | constraint->get_subtype(), in_char_context(), my_type, this); |
| 586 | extendable = constraint->is_extendable(); |
| 587 | if (constraint->get_extension()) { |
| 588 | extension = SubtypeConstraint::create_asn_size_constraint( |
| 589 | constraint->get_extension(), in_char_context(), my_type, this); |
| 590 | } |
| 591 | } |
| 592 | |
| 593 | void SizeConstraint::set_fullname(const string& p_fullname) |
| 594 | { |
| 595 | Node::set_fullname(p_fullname); |
| 596 | constraint->set_fullname(p_fullname+".<"+string(constraint->get_name())+">"); |
| 597 | } |
| 598 | |
| 599 | // ================================= |
| 600 | // ===== PermittedAlphabetConstraint |
| 601 | // ================================= |
| 602 | |
| 603 | PermittedAlphabetConstraint::PermittedAlphabetConstraint(const PermittedAlphabetConstraint& p) |
| 604 | : Constraint(p) |
| 605 | { |
| 606 | constraint = p.constraint ? p.constraint->clone() : 0; |
| 607 | } |
| 608 | |
| 609 | PermittedAlphabetConstraint::PermittedAlphabetConstraint(Constraint* p) |
| 610 | : Constraint(CT_PERMITTEDALPHABET), constraint(p) |
| 611 | { |
| 612 | if (!p) FATAL_ERROR("PermittedAlphabetConstraint::PermittedAlphabetConstraint()"); |
| 613 | } |
| 614 | |
| 615 | void PermittedAlphabetConstraint::chk() |
| 616 | { |
| 617 | if (checked) return; |
| 618 | checked = true; |
| 619 | if (!constraint || !my_type) FATAL_ERROR("PermittedAlphabetConstraint::chk()"); |
| 620 | Error_Context cntxt(this, "While checking permitted alphabet constraint"); |
| 621 | constraint->set_my_type(my_type); |
| 622 | constraint->set_my_scope(get_my_scope()); |
| 623 | constraint->set_my_parent(this); |
| 624 | constraint->chk(); |
| 625 | subtype = SubtypeConstraint::create_permitted_alphabet_constraint( |
| 626 | constraint->get_subtype(), in_char_context(), my_type, this); |
| 627 | extendable = constraint->is_extendable(); |
| 628 | if (constraint->get_extension()) { |
| 629 | extension = SubtypeConstraint::create_permitted_alphabet_constraint( |
| 630 | constraint->get_extension(), in_char_context(), my_type, this); |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | void PermittedAlphabetConstraint::set_fullname(const string& p_fullname) |
| 635 | { |
| 636 | Node::set_fullname(p_fullname); |
| 637 | constraint->set_fullname(p_fullname+".<"+string(constraint->get_name())+">"); |
| 638 | } |
| 639 | |
| 640 | // ================================= |
| 641 | // ===== SetOperationConstraint |
| 642 | // ================================= |
| 643 | |
| 644 | SetOperationConstraint::SetOperationConstraint(const SetOperationConstraint& p) |
| 645 | : Constraint(p), operationtype(p.operationtype) |
| 646 | { |
| 647 | operand_a = p.operand_a ? p.operand_a->clone() : 0; |
| 648 | operand_b = p.operand_b ? p.operand_b->clone() : 0; |
| 649 | } |
| 650 | |
| 651 | void SetOperationConstraint::set_first_operand(Constraint* p_a) |
| 652 | { |
| 653 | if (operand_a || !p_a) FATAL_ERROR("SetOperationConstraint::set_first_operand()"); |
| 654 | operand_a = p_a; |
| 655 | } |
| 656 | |
| 657 | SetOperationConstraint::SetOperationConstraint(Constraint* p_a, operationtype_t p_optype, Constraint* p_b) |
| 658 | : Constraint(CT_SETOPERATION), operationtype(p_optype), operand_a(p_a), operand_b(p_b) |
| 659 | { |
| 660 | // p_a can be null |
| 661 | if (!p_b) FATAL_ERROR("SetOperationConstraint::SetOperationConstraint()"); |
| 662 | } |
| 663 | |
| 664 | const char* SetOperationConstraint::get_operationtype_str() const |
| 665 | { |
| 666 | switch (operationtype) { |
| 667 | case UNION: |
| 668 | return "union"; |
| 669 | case INTERSECTION: |
| 670 | return "intersection"; |
| 671 | case EXCEPT: |
| 672 | return "except"; |
| 673 | } |
| 674 | return "<invalid>"; |
| 675 | } |
| 676 | |
| 677 | void SetOperationConstraint::chk() |
| 678 | { |
| 679 | if (checked) return; |
| 680 | checked = true; |
| 681 | if (!operand_a || !operand_b || !my_type) FATAL_ERROR("SetOperationConstraint::chk()"); |
| 682 | Error_Context cntxt(this, "While checking %s operation", get_operationtype_str()); |
| 683 | operand_a->set_my_type(my_type); |
| 684 | operand_b->set_my_type(my_type); |
| 685 | operand_a->set_my_scope(get_my_scope()); |
| 686 | operand_b->set_my_scope(get_my_scope()); |
| 687 | operand_a->set_my_parent(this); |
| 688 | operand_b->set_my_parent(this); |
| 689 | operand_a->chk(); |
| 690 | operand_b->chk(); |
| 691 | |
| 692 | extendable = (operationtype!=EXCEPT) ? |
| 693 | (operand_a->is_extendable() || operand_b->is_extendable()) : |
| 694 | operand_a->is_extendable(); |
| 695 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); |
| 696 | // naming ((r1,x1),...,(r2,x2)) according to X.680(11/2008) I.4.3.8 |
| 697 | SubtypeConstraint* r1 = operand_a->get_subtype(); |
| 698 | SubtypeConstraint* x1 = operand_a->get_extension(); |
| 699 | SubtypeConstraint* r2 = operand_b->get_subtype(); |
| 700 | SubtypeConstraint* x2 = operand_b->get_extension(); |
| 701 | if (!r1 || !r2) return; // something invalid, error already reported there |
| 702 | subtype = new SubtypeConstraint(my_subtype_type); |
| 703 | subtype->copy(r1); |
| 704 | switch (operationtype) { |
| 705 | case UNION: |
| 706 | subtype->union_(r2); |
| 707 | if (x1 || x2) { |
| 708 | extension = new SubtypeConstraint(my_subtype_type); |
| 709 | if (x1 && x2) { |
| 710 | extension->copy(subtype); |
| 711 | extension->union_(x1); |
| 712 | extension->union_(x2); |
| 713 | extension->except(subtype); |
| 714 | } else { |
| 715 | extension->copy(x1?x1:x2); |
| 716 | } |
| 717 | } |
| 718 | break; |
| 719 | case INTERSECTION: |
| 720 | subtype->intersection(r2); |
| 721 | if (x1 || x2) { |
| 722 | extension = new SubtypeConstraint(my_subtype_type); |
| 723 | if (x1 && x2) { |
| 724 | extension->copy(r1); |
| 725 | extension->union_(x1); |
| 726 | SubtypeConstraint* ext_tmp = new SubtypeConstraint(my_subtype_type); |
| 727 | ext_tmp->copy(r2); |
| 728 | ext_tmp->union_(x2); |
| 729 | extension->intersection(ext_tmp); |
| 730 | delete ext_tmp; |
| 731 | extension->except(subtype); |
| 732 | } else { |
| 733 | extension->copy(r1); |
| 734 | extension->intersection(x1?x1:x2); |
| 735 | } |
| 736 | } |
| 737 | break; |
| 738 | case EXCEPT: |
| 739 | subtype->except(r2); |
| 740 | if (x1) { |
| 741 | extension = new SubtypeConstraint(my_subtype_type); |
| 742 | if (x2) { |
| 743 | extension->copy(x1); |
| 744 | SubtypeConstraint* ext_tmp = new SubtypeConstraint(my_subtype_type); |
| 745 | ext_tmp->copy(r2); |
| 746 | ext_tmp->union_(x2); |
| 747 | extension->except(ext_tmp); |
| 748 | delete ext_tmp; |
| 749 | extension->except(subtype); |
| 750 | } else { |
| 751 | extension->copy(x1); |
| 752 | extension->except(r2); |
| 753 | extension->except(subtype); |
| 754 | } |
| 755 | } |
| 756 | break; |
| 757 | default: |
| 758 | FATAL_ERROR("SetOperationConstraint::chk()"); |
| 759 | } |
| 760 | } |
| 761 | |
| 762 | void SetOperationConstraint::set_fullname(const string& p_fullname) |
| 763 | { |
| 764 | Node::set_fullname(p_fullname); |
| 765 | operand_a->set_fullname(p_fullname+".<first_operand>.<"+string(operand_a->get_name())+">"); |
| 766 | operand_b->set_fullname(p_fullname+".<second_operand>.<"+string(operand_b->get_name())+">"); |
| 767 | } |
| 768 | |
| 769 | // ================================= |
| 770 | // ===== FullSetConstraint |
| 771 | // ================================= |
| 772 | |
| 773 | void FullSetConstraint::chk() |
| 774 | { |
| 775 | SubtypeConstraint::subtype_t my_subtype_type = my_type->get_subtype_type(); |
| 776 | subtype = new SubtypeConstraint(my_subtype_type); |
| 777 | } |
| 778 | |
| 779 | // ================================= |
| 780 | // ===== PatternConstraint |
| 781 | // ================================= |
| 782 | |
| 783 | PatternConstraint::PatternConstraint(const PatternConstraint& p) |
| 784 | : Constraint(p) |
| 785 | { |
| 786 | value = p.value ? p.value->clone() : 0; |
| 787 | } |
| 788 | |
| 789 | PatternConstraint::~PatternConstraint() |
| 790 | { |
| 791 | delete value; |
| 792 | } |
| 793 | |
| 794 | PatternConstraint::PatternConstraint(Value* p_value) |
| 795 | : Constraint(CT_PATTERN), value(p_value) |
| 796 | { |
| 797 | if (!p_value) FATAL_ERROR("PatternConstraint::PatternConstraint()"); |
| 798 | } |
| 799 | |
| 800 | void PatternConstraint::chk() |
| 801 | { |
| 802 | if (checked) return; |
| 803 | checked = true; |
| 804 | if (!value || !my_type) FATAL_ERROR("PatternConstraint::chk()"); |
| 805 | Error_Context cntxt(this, "While checking pattern constraint"); |
| 806 | switch (my_type->get_subtype_type()) { |
| 807 | case SubtypeConstraint::ST_CHARSTRING: |
| 808 | case SubtypeConstraint::ST_UNIVERSAL_CHARSTRING: |
| 809 | break; |
| 810 | default: |
| 811 | error("Pattern constraint is not allowed for type `%s'", my_type->get_typename().c_str()); |
| 812 | return; |
| 813 | } |
| 814 | value->set_my_scope(get_my_scope()); |
| 815 | value->set_my_governor(my_type); |
| 816 | my_type->chk_this_value_ref(value); |
| 817 | my_type->chk_this_value(value, 0, Type::EXPECTED_CONSTANT, |
| 818 | INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, NO_SUB_CHK); |
| 819 | // ignore ASN.1 pattern constraint (9.1 Transformation rules, point 4.) |
| 820 | if (in_char_context()) { |
| 821 | error("%s not allowed inside a permitted alphabet constraint", get_name()); |
| 822 | return; |
| 823 | } else { |
| 824 | if (my_parent) warning("%s inside a %s is treated as `ALL' (constraint is dropped)", |
| 825 | get_name(), my_parent->get_name()); |
| 826 | else warning("%s is ignored", get_name()); |
| 827 | } |
| 828 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 829 | } |
| 830 | |
| 831 | void PatternConstraint::set_fullname(const string& p_fullname) |
| 832 | { |
| 833 | Node::set_fullname(p_fullname); |
| 834 | value->set_fullname(p_fullname+".<value>"); |
| 835 | } |
| 836 | |
| 837 | // ================================= |
| 838 | // ===== SingleInnerTypeConstraint |
| 839 | // ================================= |
| 840 | |
| 841 | SingleInnerTypeConstraint::SingleInnerTypeConstraint(const SingleInnerTypeConstraint& p) |
| 842 | : Constraint(p) |
| 843 | { |
| 844 | constraint = p.constraint ? p.constraint->clone() : 0; |
| 845 | } |
| 846 | |
| 847 | SingleInnerTypeConstraint::SingleInnerTypeConstraint(Constraint* p) |
| 848 | : Constraint(CT_SINGLEINNERTYPE), constraint(p) |
| 849 | { |
| 850 | if (!p) FATAL_ERROR("SingleInnerTypeConstraint::SingleInnerTypeConstraint()"); |
| 851 | } |
| 852 | |
| 853 | void SingleInnerTypeConstraint::chk() |
| 854 | { |
| 855 | if (checked) return; |
| 856 | checked = true; |
| 857 | if (!constraint || !my_type) FATAL_ERROR("SingleInnerTypeConstraint::chk()"); |
| 858 | Error_Context cntxt(this, "While checking inner type constraint"); |
| 859 | Type* t = my_type->get_type_refd_last(); |
| 860 | if (!t->is_seof()) { |
| 861 | error("Single inner type constraint (WITH COMPONENT) cannot be used on type `%s'", my_type->get_typename().c_str()); |
| 862 | return; |
| 863 | } |
| 864 | Type* field_type = t->get_ofType(); // determine the type of the field to which it refers |
| 865 | constraint->set_my_type(field_type); |
| 866 | constraint->set_my_scope(get_my_scope()); |
| 867 | constraint->set_my_parent(this); |
| 868 | constraint->chk(); |
| 869 | //if (constraint->get_subtype()) { // if the constraint was not erroneous |
| 870 | // TODO: this could be added to the a tree structure constraint on my_type, |
| 871 | // tree structure needed because of set operations, constraint cannot |
| 872 | // be added to field_type |
| 873 | //} |
| 874 | // inner subtype is ignored ( ETSI ES 201 873-7 V4.1.2 -> 9.1 Transformation rules ) |
| 875 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 876 | } |
| 877 | |
| 878 | void SingleInnerTypeConstraint::set_fullname(const string& p_fullname) |
| 879 | { |
| 880 | Node::set_fullname(p_fullname); |
| 881 | constraint->set_fullname(p_fullname+".<"+string(constraint->get_name())+">"); |
| 882 | } |
| 883 | |
| 884 | // ================================= |
| 885 | // ===== NamedConstraint |
| 886 | // ================================= |
| 887 | |
| 888 | NamedConstraint::NamedConstraint(Identifier* p_id, Constraint* p_value_constraint, presence_constraint_t p_presence_constraint): |
| 889 | Constraint(CT_NAMED), id(p_id), value_constraint(p_value_constraint), presence_constraint(p_presence_constraint) |
| 890 | { |
| 891 | if (!id) FATAL_ERROR("NamedConstraint::NamedConstraint()"); |
| 892 | } |
| 893 | |
| 894 | NamedConstraint::NamedConstraint(const NamedConstraint& p) |
| 895 | : Constraint(p) |
| 896 | { |
| 897 | id = p.id->clone(); |
| 898 | value_constraint = p.value_constraint ? p.value_constraint->clone() : 0; |
| 899 | presence_constraint = p.presence_constraint; |
| 900 | } |
| 901 | |
| 902 | NamedConstraint::~NamedConstraint() |
| 903 | { |
| 904 | delete id; |
| 905 | delete value_constraint; |
| 906 | } |
| 907 | |
| 908 | const char* NamedConstraint::get_presence_constraint_name() const |
| 909 | { |
| 910 | switch (presence_constraint) { |
| 911 | case PC_NONE: return ""; |
| 912 | case PC_PRESENT: return "PRESENT"; |
| 913 | case PC_ABSENT: return "ABSENT"; |
| 914 | case PC_OPTIONAL: return "OPTIONAL"; |
| 915 | default: FATAL_ERROR("NamedConstraint::get_presence_constraint_name()"); |
| 916 | } |
| 917 | } |
| 918 | |
| 919 | void NamedConstraint::chk() |
| 920 | { |
| 921 | if (checked) return; |
| 922 | checked = true; |
| 923 | if (!my_type) FATAL_ERROR("NamedConstraint::chk()"); |
| 924 | Error_Context cntxt(this, "While checking named constraint"); |
| 925 | if (value_constraint) { |
| 926 | value_constraint->set_my_type(my_type); |
| 927 | value_constraint->set_my_scope(get_my_scope()); |
| 928 | value_constraint->set_my_parent(this); |
| 929 | value_constraint->chk(); |
| 930 | } |
| 931 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); // ignored |
| 932 | } |
| 933 | |
| 934 | void NamedConstraint::set_fullname(const string& p_fullname) |
| 935 | { |
| 936 | Node::set_fullname(p_fullname); |
| 937 | if (value_constraint) { |
| 938 | value_constraint->set_fullname(p_fullname+".<"+string(value_constraint->get_name())+">"); |
| 939 | } |
| 940 | } |
| 941 | |
| 942 | // ================================= |
| 943 | // ===== MultipleInnerTypeConstraint |
| 944 | // ================================= |
| 945 | |
| 946 | MultipleInnerTypeConstraint::MultipleInnerTypeConstraint(const MultipleInnerTypeConstraint& p) |
| 947 | : Constraint(p) |
| 948 | { |
| 949 | partial = p.partial; |
| 950 | for (size_t i=0; i<p.named_con_vec.size(); i++) { |
| 951 | named_con_vec.add( p.named_con_vec[i]->clone() ); |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | MultipleInnerTypeConstraint::~MultipleInnerTypeConstraint() |
| 956 | { |
| 957 | named_con_map.clear(); |
| 958 | for (size_t i=0; i<named_con_vec.size(); i++) { |
| 959 | delete named_con_vec[i]; |
| 960 | } |
| 961 | named_con_vec.clear(); |
| 962 | } |
| 963 | |
| 964 | void MultipleInnerTypeConstraint::addNamedConstraint(NamedConstraint* named_con) |
| 965 | { |
| 966 | if (!named_con) FATAL_ERROR("MultipleInnerTypeConstraint::addNamedConstraint()"); |
| 967 | if (checked) FATAL_ERROR("MultipleInnerTypeConstraint::addNamedConstraint()"); |
| 968 | named_con_vec.add(named_con); |
| 969 | } |
| 970 | |
| 971 | void MultipleInnerTypeConstraint::chk() |
| 972 | { |
| 973 | if (checked) return; |
| 974 | checked = true; |
| 975 | if (!my_type) FATAL_ERROR("MultipleInnerTypeConstraint::chk()"); |
| 976 | Type* t = my_type->get_type_refd_last(); |
| 977 | |
| 978 | switch (t->get_typetype()) { |
| 979 | case Type::T_REAL: { // associated ASN.1 type is a SEQUENCE |
| 980 | Identifier t_id(Identifier::ID_ASN, string("REAL")); |
| 981 | t = t->get_my_scope()->get_scope_asss()->get_local_ass_byId(t_id)->get_Type(); |
| 982 | if (t->get_typetype()!=Type::T_SEQ_A) FATAL_ERROR("MultipleInnerTypeConstraint::chk()"); |
| 983 | } break; |
| 984 | case Type::T_CHOICE_A: |
| 985 | case Type::T_SEQ_A: // T_EXTERNAL, T_EMBEDDED_PDV, T_UNRESTRICTEDSTRING |
| 986 | case Type::T_SET_A: |
| 987 | break; |
| 988 | default: |
| 989 | FATAL_ERROR("MultipleInnerTypeConstraint::chk()"); |
| 990 | } |
| 991 | // check that all NamedConstraints refer to an existing component |
| 992 | // if it exists add it to the map<> and check uniqueness |
| 993 | // for SEQUENCE check order of fields |
| 994 | size_t max_idx = 0; // current highest field index, to detect invalid order |
| 995 | bool invalid_order = false; |
| 996 | size_t present_count = 0; |
| 997 | size_t absent_count = 0; |
| 998 | for (size_t i=0; i<named_con_vec.size(); i++) { |
| 999 | const Identifier& id = named_con_vec[i]->get_id(); |
| 1000 | if (t->has_comp_withName(id)) { |
| 1001 | if (named_con_map.has_key(id)) { |
| 1002 | named_con_vec[i]->error("Duplicate reference to field `%s' of type `%s'", |
| 1003 | id.get_dispname().c_str(), my_type->get_typename().c_str()); |
| 1004 | named_con_map[id]->note("Previous reference to field `%s' is here", |
| 1005 | id.get_dispname().c_str()); |
| 1006 | } else { |
| 1007 | named_con_map.add(id, named_con_vec[i]); |
| 1008 | if (t->get_typetype()==Type::T_SEQ_A) { |
| 1009 | size_t curr_idx = t->get_comp_index_byName(id); |
| 1010 | if (curr_idx<max_idx) invalid_order = true; |
| 1011 | else max_idx = curr_idx; |
| 1012 | } |
| 1013 | switch (named_con_vec[i]->get_presence_constraint()) { |
| 1014 | case NamedConstraint::PC_PRESENT: |
| 1015 | present_count++; |
| 1016 | break; |
| 1017 | case NamedConstraint::PC_ABSENT: |
| 1018 | absent_count++; |
| 1019 | break; |
| 1020 | default: |
| 1021 | break; |
| 1022 | } |
| 1023 | } |
| 1024 | CompField* cf = t->get_comp_byName(id); |
| 1025 | switch (t->get_typetype()) { |
| 1026 | case Type::T_SEQ_A: |
| 1027 | case Type::T_SET_A: |
| 1028 | if (!cf->get_is_optional() && (named_con_vec[i]->get_presence_constraint()!=NamedConstraint::PC_NONE)) { |
| 1029 | named_con_vec[i]->error("Presence constraint `%s' cannot be used on mandatory field `%s'", |
| 1030 | named_con_vec[i]->get_presence_constraint_name(), id.get_dispname().c_str()); |
| 1031 | } |
| 1032 | break; |
| 1033 | default: |
| 1034 | break; |
| 1035 | } |
| 1036 | Type* field_type = cf->get_type(); |
| 1037 | named_con_vec[i]->set_my_type(field_type); |
| 1038 | named_con_vec[i]->set_my_scope(get_my_scope()); |
| 1039 | named_con_vec[i]->set_my_parent(this); |
| 1040 | named_con_vec[i]->chk(); |
| 1041 | } else { |
| 1042 | named_con_vec[i]->error("Type `%s' does not have a field named `%s'", |
| 1043 | my_type->get_typename().c_str(), id.get_dispname().c_str()); |
| 1044 | } |
| 1045 | } |
| 1046 | if (invalid_order) { |
| 1047 | error("The order of fields must be the same as in the definition of type `%s'", |
| 1048 | my_type->get_typename().c_str()); |
| 1049 | } |
| 1050 | if (t->get_typetype()==Type::T_CHOICE_A) { |
| 1051 | if (present_count>1) { |
| 1052 | error("CHOICE type `%s' cannot have more than one `PRESENT' field", my_type->get_typename().c_str()); |
| 1053 | } |
| 1054 | // in FullSpecification all not listed fields that can be absent are implicitly ABSENT |
| 1055 | size_t real_absent_count = absent_count + ((!get_partial())?(t->get_nof_comps()-named_con_map.size()):0); |
| 1056 | if (real_absent_count>=t->get_nof_comps()) { |
| 1057 | error("All fields of CHOICE type `%s' are `ABSENT'", my_type->get_typename().c_str()); |
| 1058 | if (real_absent_count>absent_count) { |
| 1059 | note("%ld not listed field%s implicitly `ABSENT' because FullSpecification was used", |
| 1060 | (long)(real_absent_count-absent_count), ((real_absent_count-absent_count)>1)?"s are":" is"); |
| 1061 | } |
| 1062 | } |
| 1063 | } |
| 1064 | |
| 1065 | // inner subtype is ignored ( ETSI ES 201 873-7 V4.1.2 -> 9.1 Transformation rules ) |
| 1066 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); |
| 1067 | } |
| 1068 | |
| 1069 | void MultipleInnerTypeConstraint::set_fullname(const string& p_fullname) |
| 1070 | { |
| 1071 | Node::set_fullname(p_fullname); |
| 1072 | for (size_t i=0; i<named_con_vec.size(); i++) { |
| 1073 | named_con_vec[i]->set_fullname(p_fullname+".<"+string(named_con_vec[i]->get_name())+" "+Int2string(i)+">"); |
| 1074 | } |
| 1075 | } |
| 1076 | |
| 1077 | // ================================= |
| 1078 | // ===== UnparsedMultipleInnerTypeConstraint |
| 1079 | // ================================= |
| 1080 | |
| 1081 | UnparsedMultipleInnerTypeConstraint::UnparsedMultipleInnerTypeConstraint(const UnparsedMultipleInnerTypeConstraint& p) |
| 1082 | : Constraint(p) |
| 1083 | { |
| 1084 | block = p.block ? p.block->clone() : 0; |
| 1085 | constraint = 0; |
| 1086 | } |
| 1087 | |
| 1088 | UnparsedMultipleInnerTypeConstraint::UnparsedMultipleInnerTypeConstraint(Block* p_block) |
| 1089 | : Constraint(CT_UNPARSEDMULTIPLEINNERTYPE), block(p_block), constraint(0) |
| 1090 | { |
| 1091 | if (!block) FATAL_ERROR("UnparsedMultipleInnerTypeConstraint::UnparsedMultipleInnerTypeConstraint()"); |
| 1092 | } |
| 1093 | |
| 1094 | UnparsedMultipleInnerTypeConstraint::~UnparsedMultipleInnerTypeConstraint() |
| 1095 | { |
| 1096 | delete block; |
| 1097 | delete constraint; |
| 1098 | } |
| 1099 | |
| 1100 | void UnparsedMultipleInnerTypeConstraint::chk() |
| 1101 | { |
| 1102 | if (checked) return; |
| 1103 | checked = true; |
| 1104 | if (!my_type) FATAL_ERROR("UnparsedMultipleInnerTypeConstraint::chk()"); |
| 1105 | Error_Context cntxt(this, "While checking inner type constraint"); |
| 1106 | Type* t = my_type->get_type_refd_last(); |
| 1107 | switch (t->get_typetype()) { |
| 1108 | case Type::T_REAL: // associated ASN.1 type is a SEQUENCE |
| 1109 | case Type::T_CHOICE_A: |
| 1110 | case Type::T_SEQ_A: // also refd by T_EXTERNAL, T_EMBEDDED_PDV and T_UNRESTRICTEDSTRING |
| 1111 | case Type::T_SET_A: |
| 1112 | break; |
| 1113 | default: |
| 1114 | error("Multiple inner type constraint (WITH COMPONENTS) cannot be used on type `%s'", my_type->get_typename().c_str()); |
| 1115 | return; |
| 1116 | } |
| 1117 | Node *node = block->parse(KW_Block_MultipleTypeConstraints); |
| 1118 | constraint = dynamic_cast<MultipleInnerTypeConstraint*>(node); |
| 1119 | if (!constraint) { |
| 1120 | delete node; |
| 1121 | return; // parsing error was already reported |
| 1122 | } |
| 1123 | constraint->set_my_type(my_type); |
| 1124 | constraint->set_my_scope(get_my_scope()); |
| 1125 | constraint->set_my_parent(this); |
| 1126 | constraint->chk(); |
| 1127 | subtype = new SubtypeConstraint(my_type->get_subtype_type()); // ignored |
| 1128 | } |
| 1129 | |
| 1130 | void UnparsedMultipleInnerTypeConstraint::set_fullname(const string& p_fullname) |
| 1131 | { |
| 1132 | Node::set_fullname(p_fullname); |
| 1133 | block->set_fullname(p_fullname); |
| 1134 | if (constraint) constraint->set_fullname(p_fullname); |
| 1135 | } |
| 1136 | |
| 1137 | } // namespace Common |