Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}