aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1fix/asn1fix_class.c
diff options
context:
space:
mode:
Diffstat (limited to 'libasn1fix/asn1fix_class.c')
-rw-r--r--libasn1fix/asn1fix_class.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/libasn1fix/asn1fix_class.c b/libasn1fix/asn1fix_class.c
new file mode 100644
index 00000000..c541fd62
--- /dev/null
+++ b/libasn1fix/asn1fix_class.c
@@ -0,0 +1,237 @@
+#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;
+}