aboutsummaryrefslogtreecommitdiffstats
path: root/libasn1fix/asn1fix_bitstring.c
blob: 8cf6b95eb96a726d9f073080a5ce19b321883616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#include "asn1fix_internal.h"

static int asn1f_fix_bit_string_type(arg_t *arg);
static 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) for line %d", 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);
		}
	}

	if(expr->meta_type == AMT_TYPE
	&& expr->expr_type == ASN_BASIC_BIT_STRING) {
		ret = asn1f_fix_bit_string_type(arg);
		RET2RVAL(ret, r_value);
	}

	return r_value;
}

static int _compare_value(asn1p_expr_t *expr1, asn1p_expr_t *expr2) {
	return expr2->value->value.v_integer - expr1->value->value.v_integer;
}

static int
asn1f_fix_bit_string_type(arg_t *arg) {
	asn1p_expr_t *expr = arg->expr;
	asn1p_expr_t *v;
	int r_value = 0;
	int ret;

	TQ_FOR(v, &(expr->members), next) {
		if(v->expr_type == A1TC_EXTENSIBLE) {
			FATAL("Extension marker (...) is not allowed "
				"as a BIT STRING NamedBit at line %d ",
				v->_lineno);
			return -1;
		}
		if(v->expr_type != A1TC_UNIVERVAL) {
			FATAL("BIT STRING value at line %d "
				"is not an identifier", v->_lineno);
			return -1;
		}

		/* 21.1 */
		if(v->value == NULL) {
			FATAL("BIT STRING NamedBit value at line %d "
				"must be explicitly specified in braces",
				v->_lineno);
			return -1;
		} else if(v->value->type == ATV_REFERENCED) {
			/* Resolve the value */
			if(asn1f_value_resolve(arg, v, 0))
				return -1;
		}
		if(v->value->type != ATV_INTEGER
		|| v->value->value.v_integer < 0) {
			FATAL("BIT STRING NamedBit value at line %d: "
				"non-negative integer value expected",
				v->_lineno);
			return -1;
		}

		/* Check value uniqueness as per 21.4 */
		ret = asn1f_check_unique_expr_child(arg, v,
				_compare_value, "value");
		RET2RVAL(ret, r_value);
		/* Check identifier uniqueness as per 21.5 */
		ret = asn1f_check_unique_expr_child(arg, v, 0, "identifier");
		RET2RVAL(ret, r_value);
	}

	return r_value;
}

static 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) for line %d",
		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;
	asn1c_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_delete(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_delete(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_delete(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;
}