diff options
Diffstat (limited to 'libasn1fix/asn1fix_cws.c')
-rw-r--r-- | libasn1fix/asn1fix_cws.c | 219 |
1 files changed, 215 insertions, 4 deletions
diff --git a/libasn1fix/asn1fix_cws.c b/libasn1fix/asn1fix_cws.c index a605c246..3d7b8aa7 100644 --- a/libasn1fix/asn1fix_cws.c +++ b/libasn1fix/asn1fix_cws.c @@ -1,15 +1,226 @@ #include "asn1fix_internal.h" #include "asn1fix_cws.h" +static int _asn1f_parse_class_object_data(arg_t *, asn1p_expr_t *eclass, + struct asn1p_ioc_row_s *row, asn1p_wsyntx_t *syntax, + uint8_t *buf, const uint8_t *bend, + int optional_mode, uint8_t **newpos); +static int _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell, uint8_t *buf, const uint8_t *bend); + int -asn1f_parse_class_with_syntax(arg_t *arg) { +asn1f_parse_class_object(arg_t *arg) { asn1p_expr_t *expr = arg->expr; + asn1p_expr_t *eclass; + asn1p_ioc_row_t *row; + void *new_rows_ptr; + int ret; + + if(expr->meta_type != AMT_VALUE + || expr->expr_type != A1TC_REFERENCE + || !expr->value + || expr->value->type != ATV_UNPARSED) + return 0; - if(expr->expr_type != A1TC_CLASSDEF - || expr->with_syntax == NULL) + /* + * Find the governing class. + */ + eclass = asn1f_find_terminal_type(arg, expr); + if(!eclass + || eclass->meta_type != AMT_OBJECTCLASS + || eclass->expr_type != A1TC_CLASSDEF) { return 0; + } + + DEBUG("Value %s of CLASS %s found at line %d", + expr->Identifier, eclass->Identifier, expr->_lineno); + + if(!eclass->with_syntax) { + DEBUG("Can't process classes without WITH SYNTAX just yet"); + return 0; + } + + row = asn1p_ioc_row_new(eclass); + assert(row); + + ret = _asn1f_parse_class_object_data(arg, eclass, row, + eclass->with_syntax, + expr->value->value.string.buf + 1, + expr->value->value.string.buf + + expr->value->value.string.size - 1, + 0, 0); + if(ret) { + LOG((ret < 0), + "Cannot parse %s of CLASS %s found at line %d", + expr->Identifier, eclass->Identifier, expr->_lineno); + asn1p_ioc_row_delete(row); + return ret; + } + + new_rows_ptr = realloc(eclass->object_class_matrix.row, + (eclass->object_class_matrix.rows + 1) + * sizeof(eclass->object_class_matrix.row[0])); + assert(new_rows_ptr); + eclass->object_class_matrix.row = new_rows_ptr; + eclass->object_class_matrix.row[eclass->object_class_matrix.rows] = row; + eclass->object_class_matrix.rows++; + /* Propagate max identifier length */ + if(eclass->object_class_matrix.max_identifier_length + < row->max_identifier_length) + eclass->object_class_matrix.max_identifier_length + = row->max_identifier_length; + + return 0; +} + +#define SKIPSPACES for(; buf < bend && isspace(*buf); buf++) + +static int +_asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass, + struct asn1p_ioc_row_s *row, asn1p_wsyntx_t *syntax, + uint8_t *buf, const uint8_t *bend, + int optional_mode, uint8_t **newpos) { + struct asn1p_wsyntx_chunk_s *chunk; + int ret; - DEBUG("Class %s: checking WITH SYNTAX", expr->Identifier); + TQ_FOR(chunk, (&syntax->chunks), next) { + switch(chunk->type) { + case WC_LITERAL: { + int token_len = strlen(chunk->content.token); + SKIPSPACES; + if(bend - buf < token_len + || memcmp(buf, chunk->content.token, token_len)) { + if(!optional_mode) { + FATAL("While parsing object class value %s at line %d: Expected: \"%s\", found: \"%s\"", + arg->expr->Identifier, arg->expr->_lineno, chunk->content.token, buf); + } + if(newpos) *newpos = buf; + return -1; + } + buf += token_len; + } break; + case WC_WHITESPACE: break; /* Ignore whitespace */ + case WC_FIELD: { + struct asn1p_ioc_cell_s *cell; + uint8_t *p; + SKIPSPACES; + int lbraces = 0; + p = buf; + if(p < bend && *p == '{') + lbraces = 1, p++; + for(; p < bend; p++) { + if(lbraces) { + /* Search the terminating brace */ + switch(*p) { + case '}': lbraces--; break; + case '{': lbraces++; break; + } + } else if(isspace(*p)) { + break; + } + } + if(lbraces) { + FATAL("Field reference %s found in class value definition for %s at line %d can not be satisfied by broken value \"%s\"", + chunk->content.token, + arg->expr->Identifier, arg->expr->_lineno, buf); + if(newpos) *newpos = buf; + return -1; + } + cell = asn1p_ioc_row_cell_fetch(row, + chunk->content.token); + if(cell == NULL) { + FATAL("Field reference %s found in WITH SYNAX {} clause does not match actual field in Object Class %s", + chunk->content.token, + eclass->Identifier, eclass->_lineno); + if(newpos) *newpos = buf; + return -1; + } + DEBUG("Reference %s satisfied by %s (%d)", + chunk->content.token, + buf, p - buf); + ret = _asn1f_assign_cell_value(arg, row, cell, buf, p); + if(ret) { + if(newpos) *newpos = buf; + return ret; + } + buf = p; + } break; + case WC_OPTIONALGROUP: { + uint8_t *np = 0; + SKIPSPACES; + ret = _asn1f_parse_class_object_data(arg, eclass, row, + chunk->content.syntax, buf, bend, 1, &np); + if(newpos) *newpos = np; + if(ret && np != buf) + return ret; + } break; + } + } + + + if(newpos) *newpos = buf; + return 0; +} + + +static int +_asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell, + uint8_t *buf, const uint8_t *bend) { + asn1p_expr_t *expr; + asn1p_ref_t *ref; + char *p; + + if((bend - buf) <= 0) { + FATAL("Assignment warning: empty string is being assigned into %s for %s at line %d", + cell->field->Identifier, + arg->expr->Identifier, arg->expr->_lineno); + return -1; + } + + p = malloc(bend - buf + 1); + assert(p); + memcpy(p, buf, bend - buf); + p[bend - buf] = '\0'; + + if(!isalpha(*p)) { + + if(isdigit(*p)) { + asn1c_integer_t value; + if(asn1p_atoi(p, &value)) { + FATAL("Value %s at line %d is too large for this compiler! Please contact the asn1c author.\n", p, arg->expr->_lineno); + return -1; + } + expr = asn1p_expr_new(arg->expr->_lineno); + expr->Identifier = p; + expr->meta_type = AMT_VALUE; + expr->expr_type = ASN_BASIC_INTEGER; + expr->value = asn1p_value_fromint(value); + } else { + WARNING("asn1c is not yet able to parse arbitrary direct values; please convert %s at line %d to a reference.", p, arg->expr->_lineno); + free(p); + return 1; + } + } else { + ref = asn1p_ref_new(arg->expr->_lineno); + asn1p_ref_add_component(ref, p, RLT_UNKNOWN); + assert(ref); + + expr = asn1f_lookup_symbol(arg, arg->mod, ref); + if(!expr) { + FATAL("Cannot find %s referenced by %s at line %d", + p, arg->expr->Identifier, + arg->expr->_lineno); + return -1; + } + } + + DEBUG("Field %s assignment of %s got %s", + cell->field->Identifier, p, expr->Identifier); + + cell->value = expr; + + if(row->max_identifier_length < strlen(expr->Identifier)) + row->max_identifier_length = strlen(expr->Identifier); return 0; } + |