| #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_module_t *mod, asn1p_ref_t *ref) { |
| 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, mod, &tmpref); |
| 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; |
| } |