mirror of https://gerrit.osmocom.org/asn1c
238 lines
5.3 KiB
C
238 lines
5.3 KiB
C
#include "asn1fix_internal.h"
|
|
|
|
typedef enum field_category {
|
|
OFC_INVALID, /* Invalid object field category */
|
|
OFC_TYPE,
|
|
OFC_FIXED_TYPE_VALUE,
|
|
OFC_VARIABLE_TYPE_VALUE,
|
|
OFC_FIXED_TYPE_VALUE_SET,
|
|
OFC_VARIABLE_TYPE_VALUE_SET,
|
|
OFC_INFORMATION_OBJECT,
|
|
OFC_INFORMATION_OBJECT_SET,
|
|
} field_category_e;
|
|
|
|
typedef enum object_category {
|
|
OC_INVALID,
|
|
OC_OBJECT,
|
|
OC_OBJECTSET,
|
|
} object_category_e;
|
|
|
|
static field_category_e asn1f_class_field_category(asn1p_expr_t *ofield);
|
|
static object_category_e asn1f_class_object_category(asn1p_expr_t *expr);
|
|
static asn1p_expr_t *
|
|
asn1f_class_dot_lookup(arg_t *arg, asn1p_expr_t *obj, asn1p_ref_t *ref);
|
|
|
|
asn1p_expr_t *
|
|
asn1f_class_access(arg_t *arg, asn1p_ref_t *ref, asn1p_module_t **mod_r) {
|
|
asn1p_expr_t *obj; /* Information Object or Object Set */
|
|
object_category_e obj_cat; /* Object category */
|
|
//field_category_e field_cat; /* Field category */
|
|
asn1p_expr_t *result;
|
|
asn1p_ref_t tmpref;
|
|
|
|
assert(ref->comp_count > 1);
|
|
|
|
DEBUG("%s(%s) for line %d", __func__,
|
|
asn1f_printable_reference(ref),
|
|
ref->_lineno);
|
|
|
|
/*
|
|
* Fetch the first part of the reference (OBJECT or ObjectSet).
|
|
* OBJECT.&<something>...
|
|
* ObjectSet.&<something>...
|
|
*/
|
|
assert(isupper(ref->components[0].name[0]));
|
|
|
|
tmpref = *ref;
|
|
tmpref.comp_count = 1;
|
|
obj = asn1f_lookup_symbol(arg, &tmpref, 0);
|
|
if(obj == NULL) {
|
|
errno = ESRCH;
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Make sure the symbol lexical property (upper-case, lower-case)
|
|
* corresponds to the type of the expression returned by
|
|
* lookup_symbol().
|
|
*/
|
|
obj_cat = asn1f_class_object_category(obj);
|
|
switch(obj_cat) {
|
|
case OC_OBJECT:
|
|
case OC_OBJECTSET:
|
|
if(ref->components[0].lex_type
|
|
== (obj_cat==OC_OBJECT)
|
|
? RLT_CAPITALS
|
|
: RLT_Uppercase)
|
|
break;
|
|
/* Fall through */
|
|
case OC_INVALID:
|
|
WARNING("Symbol \"%s\" is not compatible "
|
|
"with referenced expression \"%s\" at line %d",
|
|
ref->components[0].name,
|
|
obj->Identifier, obj->_lineno);
|
|
errno = EPERM;
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Find the specified field within the object.
|
|
*/
|
|
result = asn1f_class_dot_lookup(arg, obj, ref);
|
|
if(result == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
//field_cat = asn1f_class_field_category(result);
|
|
|
|
DEBUG("FILLME: %s", result->Identifier);
|
|
|
|
return result;
|
|
}
|
|
|
|
static object_category_e
|
|
asn1f_class_object_category(asn1p_expr_t *expr) {
|
|
|
|
switch(expr->meta_type) {
|
|
case AMT_OBJECT:
|
|
return OC_OBJECT;
|
|
case AMT_OBJECTSET:
|
|
return OC_OBJECTSET;
|
|
case AMT_VALUESET:
|
|
if(expr->expr_type == A1TC_REFERENCE
|
|
&& expr->reference
|
|
&& expr->reference->comp_count == 1
|
|
&& expr->reference->components[0].lex_type == RLT_CAPITALS)
|
|
{
|
|
/* FIXME: use find_terminal_type instead! */
|
|
return OC_OBJECTSET;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return OC_INVALID;
|
|
}
|
|
|
|
static field_category_e
|
|
asn1f_class_field_category(asn1p_expr_t *ofield) {
|
|
if(ofield->Identifier[0] != '&') {
|
|
assert(ofield->Identifier[0] == '&');
|
|
return OFC_INVALID;
|
|
}
|
|
|
|
if(isupper(ofield->Identifier[1])) {
|
|
if(ofield->reference) {
|
|
enum asn1p_ref_lex_type_e lex_type
|
|
= ofield->reference->components[0].lex_type;
|
|
|
|
switch(lex_type) {
|
|
case RLT_CAPITALS:
|
|
return OFC_INFORMATION_OBJECT_SET;
|
|
case RLT_Uppercase:
|
|
return OFC_FIXED_TYPE_VALUE_SET;
|
|
case RLT_AmpUppercase:
|
|
return OFC_VARIABLE_TYPE_VALUE_SET;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
if(ofield->expr_type == A1TC_CLASSFIELD)
|
|
return OFC_TYPE;
|
|
|
|
switch(ofield->meta_type) {
|
|
case AMT_TYPE:
|
|
case AMT_TYPEREF:
|
|
return OFC_FIXED_TYPE_VALUE_SET;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
} else {
|
|
if(ofield->reference) {
|
|
enum asn1p_ref_lex_type_e lex_type
|
|
= ofield->reference->components[0].lex_type;
|
|
|
|
switch(lex_type) {
|
|
case RLT_CAPITALS:
|
|
return OFC_INFORMATION_OBJECT;
|
|
case RLT_Uppercase:
|
|
return OFC_FIXED_TYPE_VALUE;
|
|
case RLT_AmpUppercase:
|
|
return OFC_VARIABLE_TYPE_VALUE;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
switch(ofield->meta_type) {
|
|
case AMT_TYPE:
|
|
case AMT_TYPEREF:
|
|
return OFC_FIXED_TYPE_VALUE;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return OFC_INVALID;
|
|
}
|
|
|
|
|
|
static asn1p_expr_t *
|
|
asn1f_class_dot_lookup(arg_t *arg, asn1p_expr_t *obj, asn1p_ref_t *ref) {
|
|
asn1p_expr_t *ofield = NULL; /* Information Object's Field */
|
|
field_category_e field_cat; /* Field category */
|
|
int comp;
|
|
|
|
assert(ref->comp_count >= 2);
|
|
|
|
for(comp = 1 /* sic! */; comp < ref->comp_count; comp++) {
|
|
int is_last_component = (comp + 1 == ref->comp_count);
|
|
char *comp_name = ref->components[comp].name;
|
|
|
|
ofield = asn1f_lookup_child(obj, comp_name);
|
|
if(ofield == NULL) {
|
|
DEBUG("Cannot find field \"%s\" in \"%s\" at line %d",
|
|
ref->components[1].name,
|
|
obj->Identifier,
|
|
obj->_lineno);
|
|
}
|
|
|
|
/*
|
|
* Compute the category of the field of
|
|
* the information object class.
|
|
*/
|
|
field_cat = asn1f_class_field_category(ofield);
|
|
|
|
switch(field_cat) {
|
|
case OFC_INVALID:
|
|
WARNING("Invalid field category of \"%s\" at line %d",
|
|
ofield->Identifier, ofield->_lineno);
|
|
errno = EPERM;
|
|
return NULL;
|
|
case OFC_TYPE:
|
|
case OFC_FIXED_TYPE_VALUE:
|
|
case OFC_VARIABLE_TYPE_VALUE:
|
|
case OFC_FIXED_TYPE_VALUE_SET:
|
|
case OFC_VARIABLE_TYPE_VALUE_SET:
|
|
if(!is_last_component) {
|
|
FATAL("Field name component \"%s\" at line %d "
|
|
"specifies non-dereferenceable thing",
|
|
comp_name, ref->_lineno);
|
|
errno = EPERM;
|
|
return NULL;
|
|
}
|
|
break;
|
|
case OFC_INFORMATION_OBJECT:
|
|
case OFC_INFORMATION_OBJECT_SET:
|
|
obj = ofield;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(ofield);
|
|
return ofield;
|
|
}
|