mirror of https://gerrit.osmocom.org/asn1c
150 lines
3.5 KiB
C
150 lines
3.5 KiB
C
#include "asn1fix_internal.h"
|
|
|
|
static int asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b);
|
|
|
|
/*
|
|
* Check that the expressions given are compatible in their type.
|
|
* ORDER DOES MATTER! (See .h).
|
|
*/
|
|
int
|
|
asn1f_check_type_compatibility(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
|
|
asn1p_expr_type_e atype, btype;
|
|
|
|
atype = a->expr_type;
|
|
btype = b->expr_type;
|
|
|
|
DEBUG("(%s:%x@%d, %s:%x@%d)",
|
|
a->Identifier, atype, a->_lineno,
|
|
b->Identifier, btype, b->_lineno);
|
|
|
|
/*
|
|
* Expected terminal type!
|
|
*/
|
|
assert(atype != A1TC_REFERENCE);
|
|
assert(btype != A1TC_REFERENCE);
|
|
|
|
if(a == b)
|
|
return 0; /* Fairly obviously */
|
|
|
|
if(atype != btype) {
|
|
/*
|
|
* Limited cross-compatibility of integer types.
|
|
*/
|
|
if((atype == A1TC_UNIVERVAL && btype == ASN_BASIC_INTEGER)
|
|
|| (atype == A1TC_UNIVERVAL && btype == ASN_BASIC_ENUMERATED)
|
|
)
|
|
return 0;
|
|
|
|
/* Limited cross-compatibility of string types */
|
|
if((atype & ASN_STRING_MASK)
|
|
&& (btype & ASN_STRING_MASK)) {
|
|
/* X.680, B.5 */
|
|
int akm = (atype & ASN_STRING_KM_MASK)
|
|
|| atype == ASN_STRING_UTF8String;
|
|
int bkm = (btype & ASN_STRING_KM_MASK)
|
|
|| btype == ASN_STRING_UTF8String;
|
|
return (akm == bkm) ? 0 : -1;
|
|
}
|
|
|
|
DEBUG("\t%s and %s are not compatible",
|
|
a->Identifier, b->Identifier);
|
|
return -1; /* Fairly obviously */
|
|
}
|
|
|
|
switch(atype) {
|
|
case ASN_BASIC_INTEGER:
|
|
/* All integers are compatible, X.680, B.4.5 */
|
|
return 0;
|
|
case ASN_BASIC_ENUMERATED:
|
|
/*
|
|
* Enumerations are not compatible
|
|
* unless their definitions are the same.
|
|
*/
|
|
if(asn1f_check_same_children(arg, a, b)) {
|
|
DEBUG("\tEnumerations are different %s and %s",
|
|
a->Identifier, b->Identifier);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
default:
|
|
if((atype & ASN_STRING_MASK)
|
|
&& (btype & ASN_STRING_MASK)) {
|
|
/* String type is compatible with the same type */
|
|
return 0;
|
|
}
|
|
/* Compatibility is not defined yet */
|
|
DEBUG("\tCompatibility rule is not defined for %s and %s",
|
|
a->Identifier, b->Identifier);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Check that the children are exactly same.
|
|
*/
|
|
static int
|
|
asn1f_check_same_children(arg_t *arg, asn1p_expr_t *a, asn1p_expr_t *b) {
|
|
asn1p_expr_t *achild;
|
|
asn1p_expr_t *bchild;
|
|
|
|
achild = TQ_FIRST(&(a->members));
|
|
bchild = TQ_FIRST(&(b->members));
|
|
|
|
while(1) {
|
|
if(achild->expr_type != bchild->expr_type)
|
|
return -1;
|
|
|
|
if(achild->Identifier && bchild->Identifier) {
|
|
if(strcmp(achild->Identifier, bchild->Identifier))
|
|
return -1;
|
|
} else if(!(!achild->Identifier && !bchild->Identifier)) {
|
|
return -1;
|
|
}
|
|
|
|
if(achild->value && bchild->value) {
|
|
if(achild->value->type != bchild->value->type)
|
|
return -1;
|
|
switch(achild->value->type) {
|
|
case ATV_INTEGER:
|
|
if(achild->value->value.v_integer
|
|
!= bchild->value->value.v_integer)
|
|
return -1;
|
|
break;
|
|
case ATV_REFERENCED:
|
|
default:
|
|
DEBUG("Value %s at lines %d and "
|
|
"%d cannot be used in "
|
|
"semantical equality check",
|
|
asn1f_printable_value(achild->value),
|
|
achild->value->value.reference->_lineno,
|
|
bchild->value->value.reference->_lineno
|
|
);
|
|
return -1;
|
|
}
|
|
} else if(!(!achild->value && !bchild->value)) {
|
|
/* One of values is defined, and another is not */
|
|
return -1;
|
|
}
|
|
|
|
achild = TQ_NEXT(achild, next);
|
|
bchild = TQ_NEXT(bchild, next);
|
|
|
|
if(achild && bchild)
|
|
continue;
|
|
else if(!achild && !bchild)
|
|
break;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
DEBUG("\t%s:%x@%d and %s:%x@%d are semantically equivalent",
|
|
a->Identifier, a->expr_type, a->_lineno,
|
|
b->Identifier, b->expr_type, b->_lineno);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|