asn1cnst_range_t * asn1constraint_compute_constraint_range( const char *dbg_name, asn1p_expr_type_e expr_type, const asn1p_constraint_t *ct, enum asn1p_constraint_type_e requested_ct_type, const asn1cnst_range_t *minmax, int *exmet, enum cpr_flags cpr_flags) { asn1cnst_range_t *range; asn1cnst_range_t *tmp; asn1p_value_t *vmin; asn1p_value_t *vmax; int expectation_met; unsigned int i; int ret; if(!exmet) { exmet = &expectation_met; *exmet = 0; } /* * Check if the requested constraint is theoretically compatible * with the given expression type. */ if(asn1constraint_compatible(expr_type, requested_ct_type, cpr_flags & CPR_simulate_fbless_SIZE) != 1) { errno = EINVAL; return 0; } /* * Check arguments' validity. */ switch(requested_ct_type) { case ACT_EL_RANGE: if(exmet == &expectation_met) *exmet = 1; break; case ACT_CT_FROM: if(cpr_flags & CPR_strict_OER_visibility) { errno = EINVAL; return 0; } if(!minmax) { minmax = asn1constraint_default_alphabet(expr_type); if(minmax) { break; } } /* Fall through */ case ACT_CT_SIZE: if(!minmax) { static asn1cnst_range_t mm; mm.left.type = ARE_VALUE; mm.left.value = 0; mm.right.type = ARE_MAX; minmax = &mm; } break; default: errno = EINVAL; return 0; } if(minmax) { range = _range_clone(minmax); } else { range = _range_new(); } /* * X.691, #9.3.6 * Constraints on restricted character string types * which are not known-multiplier are not PER-visible. */ if((expr_type & ASN_STRING_NKM_MASK)) range->not_PER_visible = 1; if(!ct || (range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility))) return range; /* * X.696 (08/2015), #8.2.2 * SIZE constraints on restricted character string types * which are not known-multiplier are not OER-visible. */ if(requested_ct_type == ACT_CT_SIZE && (expr_type & ASN_STRING_NKM_MASK)) range->not_OER_visible = 1; if(!ct || (range->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility))) { return range; } switch(ct->type) { case ACT_EL_VALUE: vmin = vmax = ct->value; break; case ACT_EL_RANGE: case ACT_EL_LLRANGE: case ACT_EL_RLRANGE: case ACT_EL_ULRANGE: vmin = ct->range_start; vmax = ct->range_stop; break; case ACT_EL_EXT: if(!*exmet) { range->extensible = 1; range->not_OER_visible = 1; } else { _range_free(range); errno = ERANGE; range = 0; } return range; case ACT_CT_SIZE: case ACT_CT_FROM: if(requested_ct_type == ct->type) { /* * Specifically requested to process SIZE() or FROM() constraint. */ *exmet = 1; } else { range->incompatible = 1; return range; } assert(ct->el_count == 1); tmp = asn1constraint_compute_constraint_range( dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags); if(tmp) { _range_free(range); } else { if(errno == ERANGE) { range->empty_constraint = 1; range->extensible = 1; if(range->extensible) range->not_OER_visible = 1; tmp = range; } else { _range_free(range); } } return tmp; case ACT_CA_SET: /* (10..20)(15..17) */ case ACT_CA_INT: /* SIZE(1..2) ^ FROM("ABCD") */ /* AND constraints, one after another. */ for(i = 0; i < ct->el_count; i++) { tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type, ct->elements[i], requested_ct_type, ct->type==ACT_CA_SET?range:minmax, exmet, cpr_flags); if(!tmp) { if(errno == ERANGE) { range->extensible = 1; if(range->extensible) range->not_OER_visible = 1; continue; } else { _range_free(range); return NULL; } } if(tmp->incompatible) { /* * Ignore constraints * incompatible with arguments: * SIZE(1..2) ^ FROM("ABCD") * either SIZE or FROM will be ignored. */ _range_free(tmp); continue; } if(tmp->not_OER_visible && (cpr_flags & CPR_strict_OER_visibility)) { /* * Ignore not OER-visible */ _range_free(tmp); continue; } if(tmp->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)) { if(ct->type == ACT_CA_SET) { /* * X.691, #9.3.18: * Ignore this separate component. */ } else { /* * X.691, #9.3.19: * Ignore not PER-visible INTERSECTION */ } _range_free(tmp); continue; } ret = _range_intersection(range, tmp, ct->type == ACT_CA_SET, cpr_flags & CPR_strict_OER_visibility); _range_free(tmp); if(ret) { _range_free(range); errno = EPERM; return NULL; } _range_canonicalize(range); } return range; case ACT_CA_CSV: /* SIZE(1..2, 3..4) */ case ACT_CA_UNI: /* SIZE(1..2) | FROM("ABCD") */ /* * Grab the first valid constraint. */ tmp = 0; for(i = 0; i < ct->el_count; i++) { tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type, ct->elements[i], requested_ct_type, minmax, exmet, cpr_flags); if(!tmp) { if(errno == ERANGE) { range->extensible = 1; range->not_OER_visible = 1; continue; } else { _range_free(range); return NULL; } } if(tmp->incompatible) { _range_free(tmp); tmp = 0; } break; } if(tmp) { tmp->extensible |= range->extensible; tmp->not_OER_visible |= range->not_OER_visible; tmp->empty_constraint |= range->empty_constraint; _range_free(range); range = tmp; } else { range->incompatible = 1; return range; } /* * Merge with the rest of them. * Canonicalizator will do the union magic. */ for(; i < ct->el_count; i++) { tmp = asn1constraint_compute_constraint_range(dbg_name, expr_type, ct->elements[i], requested_ct_type, minmax, exmet, cpr_flags); if(!tmp) { if(errno == ERANGE) { range->extensible = 1; range->not_OER_visible = 1; continue; } else { _range_free(range); return NULL; } } if(tmp->incompatible) { _range_free(tmp); _range_canonicalize(range); range->incompatible = 1; return range; } if(tmp->empty_constraint) { /* * Ignore empty constraints in OR logic. */ range->extensible |= tmp->extensible; range->not_OER_visible |= tmp->not_OER_visible; _range_free(tmp); continue; } _range_merge_in(range, tmp); } _range_canonicalize(range); if(requested_ct_type == ACT_CT_FROM) { /* * X.696 permitted alphabet constraints are not OER-visible. */ range->not_OER_visible = 1; if(range->extensible) { /* * X.691, #9.3.10: * Extensible permitted alphabet constraints * are not PER-visible. */ range->not_PER_visible = 1; } } if(range->not_PER_visible && (cpr_flags & CPR_strict_PER_visibility)) { /* * X.691, #9.3.19: * If not PER-visible constraint is part of UNION, * the whole resulting constraint is not PER-visible. */ _range_free(range); if(minmax) range = _range_clone(minmax); else range = _range_new(); range->not_PER_visible = 1; range->incompatible = 1; } return range; case ACT_CA_EXC: /* FROM("ABCD") EXCEPT FROM("AB") */ /* * X.691 (PER), #9.3.19: * EXCEPT and the following value set is completely ignored. * X.696 (OER), #8.2.6: * EXCEPT keyword and the following value set is completely ignored. */ assert(ct->el_count >= 1); _range_free(range); range = asn1constraint_compute_constraint_range(dbg_name, expr_type, ct->elements[0], requested_ct_type, minmax, exmet, cpr_flags); return range; case ACT_CT_WCOMPS: if(expr_type == ASN_BASIC_REAL) { return asn1f_real_range_from_WCOMPS(dbg_name, ct); } range->incompatible = 1; return range; default: range->incompatible = 1; return range; } if(!*exmet) { /* * Expectation is not met. Return the default range. */ range->incompatible = 1; return range; } if(expr_type == ASN_BASIC_REAL && (vmin->type == ATV_REAL || vmax->type == ATV_REAL)) { range->incompatible = 1; return range; } _range_free(range); range = _range_new(); enum range_fill_result rfr; rfr = _range_fill(vmin, minmax, &range->left, range, requested_ct_type, ct->_lineno); if(rfr == RFR_OK) { rfr = _range_fill(vmax, minmax, &range->right, range, requested_ct_type, ct->_lineno); } switch(rfr) { case RFR_OK: break; case RFR_FAIL: _range_free(range); errno = EPERM; return NULL; case RFR_INCOMPATIBLE: range->incompatible = 1; return range; } if(minmax) { asn1cnst_range_t *clone; clone = _range_clone(minmax); /* Constrain parent type with given data. */ ret = _range_intersection(clone, range, 1, cpr_flags & CPR_strict_OER_visibility); _range_free(range); if(ret) { _range_free(clone); errno = EPERM; return NULL; } range = clone; } /* * Recompute elements's min/max, remove duplicates, etc. */ _range_canonicalize(range); return range; }
int asn1f_value_resolve(arg_t *arg, asn1p_expr_t *expr, const enum asn1p_constraint_type_e *opt_constr_type) { asn1p_expr_t *val_type_expr; asn1p_expr_t *value_expr; asn1p_expr_t *type_expr; int ret; /* Make sure this IS a value assignment */ assert(expr->meta_type == AMT_VALUE); assert(expr->value); if(expr->value->type != ATV_REFERENCED) return 0; DEBUG("(=\"%s\", %x%s%s)", asn1f_printable_value(expr->value), expr->expr_type, opt_constr_type ? ", " : "", opt_constr_type ? asn1p_constraint_type2str(*opt_constr_type) : "" ); /* * 1. Find the terminal type for this assignment. */ type_expr = asn1f_find_terminal_type(arg, expr); if(type_expr == 0) { if(errno == EEXIST) { DEBUG("External type for %s at line %d", expr->Identifier, expr->_lineno); return 0; } else { FATAL("Terminal type for %s at line %d not found", expr->Identifier, expr->_lineno); return -1; } } if(asn1f_look_value_in_type(arg, type_expr, expr) == -1) { FATAL("Value not found in type for %s at line %d", expr->Identifier, expr->_lineno); return -1; } /* * 2. Find the terminal value also. */ value_expr = asn1f_find_terminal_value(arg, expr); if(value_expr) { DEBUG("Terminal value for %s->%s is %s at line %d", expr->Identifier, asn1f_printable_value(expr->value), value_expr->Identifier, value_expr->_lineno); } else { FATAL("Terminal value for %s->%s not found", expr->Identifier, asn1f_printable_value(expr->value)); return -1; } /* * 3. Find the _type_ of a _terminal value_. */ WITH_MODULE(value_expr->module, val_type_expr = asn1f_find_terminal_type(arg, value_expr)); if(val_type_expr) { DEBUG("Terminal type of value %s->%s is %s at line %d", expr->Identifier, asn1f_printable_value(expr->value), val_type_expr->Identifier, val_type_expr->_lineno); } else { FATAL("Terminal type of value %s->%s not found", expr->Identifier, asn1f_printable_value(expr->value)); return -1; } /* * 4. Check compatibility between the type of the current expression * and the type of the discovered value. */ if(opt_constr_type) ret = asn1constraint_compatible(val_type_expr->expr_type, *opt_constr_type, 0 /* must not matter here */); else ret = asn1f_check_type_compatibility(arg, type_expr, val_type_expr); if(ret == -1) { switch(type_expr->expr_type) { default: if(!(type_expr->expr_type & ASN_STRING_MASK)) break; /* Compatibility rules are not defined */ /* Fall through */ case ASN_BASIC_INTEGER: case ASN_BASIC_ENUMERATED: FATAL("Incompatible type of \"%s\" (%s) at line %d " "with \"%s\" (%s) at line %d", type_expr->Identifier, ASN_EXPR_TYPE2STR(type_expr->expr_type), type_expr->_lineno, val_type_expr->Identifier, ASN_EXPR_TYPE2STR(val_type_expr->expr_type), val_type_expr->_lineno); return -1; case ASN_BASIC_OBJECT_IDENTIFIER: /* * Ignore this for now. * We can't deal with OIDs inheritance properly yet. */ return 0; } WARNING("Possibly incompatible type of \"%s\" (%s) at line %d " "with \"%s\" (%s) at line %d", type_expr->Identifier, ASN_EXPR_TYPE2STR(type_expr->expr_type), type_expr->_lineno, val_type_expr->Identifier, ASN_EXPR_TYPE2STR(val_type_expr->expr_type), val_type_expr->_lineno); return 1; } if(asn1f_look_value_in_type(arg, val_type_expr, expr) == -1) return -1; /* * 5. Copy value from the terminal value into the current expression. */ ret = _asn1f_copy_value(arg, expr, value_expr); if(ret == -1) { FATAL("Value %s cannot be copied from line %d to line %d", asn1f_printable_value(value_expr->value), value_expr->_lineno, expr->_lineno); return -1; } DEBUG("Final value for \"%s\" at line %d is %s", expr->Identifier, expr->_lineno, asn1f_printable_value(expr->value)); return 0; }