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