<commit_before>#include "asn1c_internal.h"
#include "asn1c_constraint.h"
#include "asn1c_misc.h"
#include "asn1c_out.h"

#include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
#include <asn1fix_export.h>	/* other exportable stuff from libasn1fix */

static int asn1c_emit_constraint_tables(arg_t *arg, int got_size);
static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value);
static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop);

int
asn1c_emit_constraint_checking_code(arg_t *arg) {
	asn1cnst_range_t *r_size;
	asn1cnst_range_t *r_value;
	asn1p_expr_t *expr = arg->expr;
	asn1p_expr_type_e etype;
	asn1p_constraint_t *ct;
	int got_something = 0;
	int alphabet_table_compiled;
	int produce_st = 0;

	ct = expr->combined_constraints;
	if(ct == NULL)
		return 1;	/* No additional constraints defined */

	etype = _find_terminal_type(arg);

	r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
	r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE,0,0,0);
	if(r_value) {
		if(r_value->incompatible
		|| r_value->empty_constraint
		|| (r_value->left.type == ARE_MIN
			&& r_value->right.type == ARE_MAX)
		|| (etype == ASN_BASIC_BOOLEAN
			&& r_value->left.value == 0
			&& r_value->right.value == 1)
		) {
			asn1constraint_range_free(r_value);
			r_value = 0;
		}
	}
	if(r_size) {
		if(r_size->incompatible
		|| r_size->empty_constraint
		|| (r_size->left.value == 0	/* or .type == MIN */
			&& r_size->right.type == ARE_MAX)
		) {
			asn1constraint_range_free(r_size);
			r_size = 0;
		}
	}

	/*
	 * Do we really need an "*st = sptr" pointer?
	 */
	switch(etype) {
	case ASN_BASIC_INTEGER:
	case ASN_BASIC_ENUMERATED:
	case ASN_BASIC_REAL:
		if(!(arg->flags & A1C_USE_NATIVE_TYPES))
			produce_st = 1;
		break;
	case ASN_BASIC_BIT_STRING:
	case ASN_BASIC_OCTET_STRING:
		produce_st = 1;
			break;
	default:
		if(etype & ASN_STRING_MASK)
			produce_st = 1;
		break;
	}
	if(produce_st) {
		char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
		OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
	}

	if(r_size || r_value) {
		if(r_size) {
			OUT("size_t size;\n");
		}
		if(r_value)
			switch(etype) {
			case ASN_BASIC_INTEGER:
			case ASN_BASIC_ENUMERATED:
				OUT("long value;\n");
				break;
			case ASN_BASIC_REAL:
				OUT("double value;\n");
				break;
			case ASN_BASIC_BOOLEAN:
				OUT("BOOLEAN_t value;\n");
				break;
			default:
				break;
		}
	}

	OUT("\n");

	/*
	 * Protection against null input.
	 */
	OUT("if(!sptr) {\n");
		INDENT(+1);
		OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
		OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
		OUT("\ttd->name, __FILE__, __LINE__);\n");
		OUT("return -1;\n");
		INDENT(-1);
	OUT("}\n");
	OUT("\n");

	if(r_value)
		emit_value_determination_code(arg, etype, r_value);
	if(r_size)
		emit_size_determination_code(arg, etype);

	INDENT(-1);
	REDIR(OT_CTABLES);
	/* Emit FROM() tables */
	alphabet_table_compiled =
		(asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
	REDIR(OT_CODE);
	INDENT(+1);

	/*
	 * Here is an if() {} else {} constaint checking code.
	 */
	OUT("\n");
	OUT("if(");
	INDENT(+1);
		if(r_size) {
			if(got_something++) { OUT("\n"); OUT(" && "); }
			OUT("(");
			emit_range_comparison_code(arg, r_size, "size", 0, -1);
			OUT(")");
		}
		if(r_value) {
			if(got_something++) { OUT("\n"); OUT(" && "); }
			OUT("(");
			if(etype == ASN_BASIC_BOOLEAN)
				emit_range_comparison_code(arg, r_value,
					"value", 0, 1);
			else
				emit_range_comparison_code(arg, r_value,
					"value", -1, -1);
			OUT(")");
		}
		if(alphabet_table_compiled) {
			if(got_something++) { OUT("\n"); OUT(" && "); }
			OUT("!check_permitted_alphabet_%d(%s)",
				arg->expr->_type_unique_index,
				produce_st ? "st" : "sptr");
		}
		if(!got_something) {
			OUT("1 /* No applicable constraints whatsoever */");
			OUT(") {\n");
			INDENT(-1);
			INDENTED(OUT("/* Nothing is here. See below */\n"));
			OUT("}\n");
			OUT("\n");
			return 1;
		}
	INDENT(-1);
	OUT(") {\n");
		INDENT(+1);
		switch(etype) {
		case ASN_CONSTR_SEQUENCE_OF:
			OUT("/* SEQUENCE validation code is the same as SET */\n");
		case ASN_CONSTR_SET_OF:
			OUT("/* Perform validation of the inner elements */\n");
			OUT("return SET_OF_constraint(td, list, app_errlog, app_key);\n");
			break;
		default:
			OUT("/* Constraint check succeeded */\n");
			OUT("return 0;\n");
		}
		INDENT(-1);
	OUT("} else {\n");
		INDENT(+1);
			OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
			OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
			OUT("\ttd->name, __FILE__, __LINE__);\n");
			OUT("return -1;\n");
		INDENT(-1);
	OUT("}\n");

	return 0;
}

static int
asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
	asn1c_integer_t range_start;
	asn1c_integer_t range_stop;
	asn1p_expr_type_e etype;
	asn1cnst_range_t *range;
	asn1p_constraint_t *ct;<commit_msg>sptr<commit_after>#include "asn1c_internal.h"
#include "asn1c_constraint.h"
#include "asn1c_misc.h"
#include "asn1c_out.h"

#include <asn1fix_crange.h>	/* constraint groker from libasn1fix */
#include <asn1fix_export.h>	/* other exportable stuff from libasn1fix */

static int asn1c_emit_constraint_tables(arg_t *arg, int got_size);
static int emit_alphabet_check_loop(arg_t *arg, asn1cnst_range_t *range);
static int emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_range_t *r_value);
static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop);

int
asn1c_emit_constraint_checking_code(arg_t *arg) {
	asn1cnst_range_t *r_size;
	asn1cnst_range_t *r_value;
	asn1p_expr_t *expr = arg->expr;
	asn1p_expr_type_e etype;
	asn1p_constraint_t *ct;
	int got_something = 0;
	int alphabet_table_compiled;
	int produce_st = 0;

	ct = expr->combined_constraints;
	if(ct == NULL)
		return 1;	/* No additional constraints defined */

	etype = _find_terminal_type(arg);

	r_value=asn1constraint_compute_PER_range(etype, ct, ACT_EL_RANGE,0,0,0);
	r_size = asn1constraint_compute_PER_range(etype, ct, ACT_CT_SIZE,0,0,0);
	if(r_value) {
		if(r_value->incompatible
		|| r_value->empty_constraint
		|| (r_value->left.type == ARE_MIN
			&& r_value->right.type == ARE_MAX)
		|| (etype == ASN_BASIC_BOOLEAN
			&& r_value->left.value == 0
			&& r_value->right.value == 1)
		) {
			asn1constraint_range_free(r_value);
			r_value = 0;
		}
	}
	if(r_size) {
		if(r_size->incompatible
		|| r_size->empty_constraint
		|| (r_size->left.value == 0	/* or .type == MIN */
			&& r_size->right.type == ARE_MAX)
		) {
			asn1constraint_range_free(r_size);
			r_size = 0;
		}
	}

	/*
	 * Do we really need an "*st = sptr" pointer?
	 */
	switch(etype) {
	case ASN_BASIC_INTEGER:
	case ASN_BASIC_ENUMERATED:
	case ASN_BASIC_REAL:
		if(!(arg->flags & A1C_USE_NATIVE_TYPES))
			produce_st = 1;
		break;
	case ASN_BASIC_BIT_STRING:
	case ASN_BASIC_OCTET_STRING:
		produce_st = 1;
			break;
	default:
		if(etype & ASN_STRING_MASK)
			produce_st = 1;
		break;
	}
	if(produce_st) {
		char *tname = asn1c_type_name(arg, arg->expr, TNF_SAFE);
		OUT("const %s_t *st = (const %s_t *)sptr;\n", tname, tname);
	}

	if(r_size || r_value) {
		if(r_size) {
			OUT("size_t size;\n");
		}
		if(r_value)
			switch(etype) {
			case ASN_BASIC_INTEGER:
			case ASN_BASIC_ENUMERATED:
				OUT("long value;\n");
				break;
			case ASN_BASIC_REAL:
				OUT("double value;\n");
				break;
			case ASN_BASIC_BOOLEAN:
				OUT("BOOLEAN_t value;\n");
				break;
			default:
				break;
		}
	}

	OUT("\n");

	/*
	 * Protection against null input.
	 */
	OUT("if(!sptr) {\n");
		INDENT(+1);
		OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
		OUT("\t\"%%s: value not given (%%s:%%d)\",\n");
		OUT("\ttd->name, __FILE__, __LINE__);\n");
		OUT("return -1;\n");
		INDENT(-1);
	OUT("}\n");
	OUT("\n");

	if(r_value)
		emit_value_determination_code(arg, etype, r_value);
	if(r_size)
		emit_size_determination_code(arg, etype);

	INDENT(-1);
	REDIR(OT_CTABLES);
	/* Emit FROM() tables */
	alphabet_table_compiled =
		(asn1c_emit_constraint_tables(arg, r_size?1:0) == 1);
	REDIR(OT_CODE);
	INDENT(+1);

	/*
	 * Here is an if() {} else {} constaint checking code.
	 */
	OUT("\n");
	OUT("if(");
	INDENT(+1);
		if(r_size) {
			if(got_something++) { OUT("\n"); OUT(" && "); }
			OUT("(");
			emit_range_comparison_code(arg, r_size, "size", 0, -1);
			OUT(")");
		}
		if(r_value) {
			if(got_something++) { OUT("\n"); OUT(" && "); }
			OUT("(");
			if(etype == ASN_BASIC_BOOLEAN)
				emit_range_comparison_code(arg, r_value,
					"value", 0, 1);
			else
				emit_range_comparison_code(arg, r_value,
					"value", -1, -1);
			OUT(")");
		}
		if(alphabet_table_compiled) {
			if(got_something++) { OUT("\n"); OUT(" && "); }
			OUT("!check_permitted_alphabet_%d(%s)",
				arg->expr->_type_unique_index,
				produce_st ? "st" : "sptr");
		}
		if(!got_something) {
			OUT("1 /* No applicable constraints whatsoever */");
			OUT(") {\n");
			INDENT(-1);
			INDENTED(OUT("/* Nothing is here. See below */\n"));
			OUT("}\n");
			OUT("\n");
			return 1;
		}
	INDENT(-1);
	OUT(") {\n");
		INDENT(+1);
		switch(etype) {
		case ASN_CONSTR_SEQUENCE_OF:
			OUT("/* SEQUENCE validation code is the same as SET */\n");
		case ASN_CONSTR_SET_OF:
			OUT("/* Perform validation of the inner elements */\n");
			OUT("return SET_OF_constraint(td, sptr, app_errlog, app_key);\n");
			break;
		default:
			OUT("/* Constraint check succeeded */\n");
			OUT("return 0;\n");
		}
		INDENT(-1);
	OUT("} else {\n");
		INDENT(+1);
			OUT("_ASN_ERRLOG(app_errlog, app_key,\n");
			OUT("\t\"%%s: constraint failed (%%s:%%d)\",\n");
			OUT("\ttd->name, __FILE__, __LINE__);\n");
			OUT("return -1;\n");
		INDENT(-1);
	OUT("}\n");

	return 0;
}

static int
asn1c_emit_constraint_tables(arg_t *arg, int got_size) {
	asn1c_integer_t range_start;
	asn1c_integer_t range_stop;
	asn1p_expr_type_e etype;
	asn1cnst_range_t *range;
	asn1p_constraint_t *ct;
{'fraction_non_alphanumeric': 0.16999132697311362, 'fraction_numerical': 0.015225980533872988, 'mean_word_length': 4.249367728882144, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '650531', 'n_tokens_mistral': 4921, 'n_tokens_neox': 4401, 'n_words': 789}