| #include "asn1fix_internal.h" |
| |
| int asn1f_fix_bit_string_value(arg_t *arg, asn1p_expr_t *ttype); |
| static void asn1f_BS_remove_trailing_zero_bits(asn1p_value_t *value); |
| static int asn1f_BS_unparsed_convert(arg_t *arg, asn1p_value_t *value, asn1p_expr_t *ttype); |
| |
| int |
| asn1f_fix_bit_string(arg_t *arg) { |
| asn1p_expr_t *expr = arg->expr; |
| int r_value = 0; |
| int ret; |
| |
| if(expr->meta_type == AMT_VALUE) { |
| asn1p_expr_t *ttype; |
| |
| DEBUG("%s(%s) for line %d", __func__, |
| expr->Identifier, expr->_lineno); |
| |
| ttype = asn1f_find_terminal_type(arg, expr); |
| if(ttype && ttype->expr_type == ASN_BASIC_BIT_STRING) { |
| ret = asn1f_fix_bit_string_value(arg, ttype); |
| RET2RVAL(ret, r_value); |
| } |
| } |
| |
| return r_value; |
| } |
| |
| int |
| asn1f_fix_bit_string_value(arg_t *arg, asn1p_expr_t *ttype) { |
| asn1p_expr_t *expr = arg->expr; |
| int r_value = 0; |
| |
| DEBUG("%s(%s) for line %d", __func__, |
| expr->Identifier, expr->_lineno); |
| |
| switch(expr->value->type) { |
| case ATV_UNPARSED: |
| /* |
| * Most definitely we have something like |
| * value BitStringType1 ::= { a, b, c } |
| * which could not be parsed by the LALR parser, mostly |
| * because it requires knowledge about BitStringType1 |
| * during the parsing. So, here's a little hack: we create |
| * a buffer containing the full specification of a module, |
| * which contains some pre-defined INTEGER type with the |
| * opaque definition "{ a, b, c }" from the bit string. |
| */ |
| if(asn1f_BS_unparsed_convert(arg, expr->value, ttype)) { |
| r_value = -1; |
| break; |
| } |
| /* Fall through: remove trailing zero bits */ |
| case ATV_BITVECTOR: |
| asn1f_BS_remove_trailing_zero_bits(expr->value); |
| break; |
| default: |
| break; |
| } |
| |
| return r_value; |
| } |
| |
| static void |
| asn1f_BS_remove_trailing_zero_bits(asn1p_value_t *value) { |
| int lmfb = -1; /* Last meaningful byte position */ |
| int bits; /* Number of bits in the BIT STRING value */ |
| int b; |
| |
| assert(value->type == ATV_BITVECTOR); |
| |
| bits = value->value.binary_vector.size_in_bits; |
| /* |
| * Figure out the rightmost meaningful byte. |
| */ |
| for(b = 0; b < ((bits + 7) >> 3); b++) { |
| uint8_t uc = value->value.binary_vector.bits[b]; |
| if(uc && b > lmfb) |
| lmfb = b; |
| } |
| if(lmfb == -1) { |
| bits = 0; |
| } else { |
| uint8_t uc; |
| uc = value->value.binary_vector.bits[lmfb]; |
| bits = (lmfb+1) * 8; |
| /* |
| * Squeeze the bit string width until the rightmost |
| * bit is set. |
| */ |
| for(; uc && (uc & 1) == 0; uc >>= 1) |
| bits--; |
| if(uc == 0) { |
| bits = lmfb * 8; |
| } |
| } |
| value->value.binary_vector.size_in_bits = bits; |
| } |
| |
| static int |
| asn1f_BS_unparsed_convert(arg_t *arg, asn1p_value_t *value, asn1p_expr_t *ttype) { |
| asn1p_t *asn; |
| asn1p_module_t *mod; |
| asn1p_expr_t *V; |
| asn1p_expr_t *bit; |
| asn1_integer_t aI; |
| uint8_t *bitbuf; |
| int bits; |
| int psize; |
| char *p; |
| int ret; |
| int r_value = 0; |
| |
| assert(value->type == ATV_UNPARSED); |
| |
| psize = value->value.string.size + 64; |
| p = malloc(psize); |
| if(p == NULL) |
| return -1; |
| |
| ret = snprintf(p, psize, |
| "M DEFINITIONS ::=\nBEGIN\n" |
| "V ::= INTEGER %s\n" |
| "END\n", |
| value->value.string.buf |
| ); |
| assert(ret < psize); |
| psize = ret; |
| |
| asn = asn1p_parse_buffer(p, psize, A1P_NOFLAGS); |
| free(p); |
| if(asn == NULL) { |
| FATAL("Cannot parse BIT STRING value %s " |
| "defined as %s at line %d", |
| arg->expr->Identifier, |
| value->value.string.buf, |
| arg->expr->_lineno |
| ); |
| return -1; |
| } |
| |
| mod = TQ_FIRST(&(asn->modules)); |
| assert(mod); |
| V = TQ_FIRST(&(mod->members)); |
| assert(V); |
| assert(strcmp(V->Identifier, "V") == 0); |
| assert(TQ_FIRST(&(V->members))); |
| |
| /* |
| * Simple loop just to fetch the maximal bit position |
| * out of the BIT STRING value defined as NamedBitList. |
| */ |
| aI = -1; |
| TQ_FOR(bit, &(V->members), next) { |
| asn1p_expr_t *bitdef; |
| bitdef = asn1f_lookup_child(ttype, bit->Identifier); |
| if(bitdef && bitdef->value |
| && bitdef->value->type == ATV_INTEGER) { |
| if(bitdef->value->value.v_integer > aI) |
| aI = bitdef->value->value.v_integer; |
| } |
| } |
| |
| if(aI > 1024 * 1024 * 8) { /* One megabyte */ |
| FATAL("Unsupportedly large BIT STRING value \"%s\" " |
| "defined at line %d " |
| "(larger than 1MByte)", |
| arg->expr->Identifier, |
| arg->expr->_lineno |
| ); |
| asn1p_free(asn); |
| return -1; |
| } |
| |
| bits = aI + 1; /* Number of bits is more than a last bit position */ |
| bitbuf = calloc(1, 1 + ((bits + 7) / 8)); |
| if(bitbuf == NULL) { |
| asn1p_free(asn); |
| return -1; |
| } |
| |
| TQ_FOR(bit, &(V->members), next) { |
| asn1p_expr_t *bitdef; |
| int set_bit_pos; |
| |
| if(bit->value) { |
| WARNING("Identifier \"%s\" at line %d " |
| "must not have a value", |
| bit->Identifier, bit->_lineno); |
| RET2RVAL(1, r_value); |
| } |
| bitdef = asn1f_lookup_child(ttype, bit->Identifier); |
| if(bitdef == NULL) { |
| FATAL("Identifier \"%s\" at line %d is not defined " |
| "in the \"%s\" type definition at line %d", |
| bit->Identifier, |
| bit->_lineno, |
| ttype->Identifier, |
| ttype->_lineno |
| ); |
| RET2RVAL(-1, r_value); |
| continue; |
| } |
| if(bitdef->value == NULL |
| || bitdef->value->type != ATV_INTEGER) { |
| FATAL("Broken identifier " |
| "\"%s\" at line %d " |
| "referenced by \"%s\" at line %d", |
| bitdef->Identifier, |
| bitdef->_lineno, |
| arg->expr->Identifier, |
| arg->expr->_lineno |
| ); |
| RET2RVAL(-1, r_value); |
| continue; |
| } |
| |
| assert(bitdef->value->value.v_integer < bits); |
| set_bit_pos = bitdef->value->value.v_integer; |
| bitbuf[set_bit_pos>>3] |= 1 << (7-(set_bit_pos % 8)); |
| } |
| |
| asn1p_free(asn); |
| free(value->value.string.buf); |
| value->type = ATV_BITVECTOR; |
| value->value.binary_vector.bits = bitbuf; |
| value->value.binary_vector.size_in_bits = bits; |
| |
| return r_value; |
| } |