blob: de2d2406a04ed8f9797763596317f9a7715eca34 [file] [log] [blame]
Lev Walkincb4cd5b2006-03-14 15:23:06 +00001#include "asn1fix_internal.h"
Lev Walkinaa7f5302006-03-14 15:53:59 +00002#include "asn1fix_cws.h"
Lev Walkin9d542d22006-03-14 16:31:37 +00003
Lev Walkind370e9f2006-03-16 10:03:35 +00004static int _asn1f_parse_class_object_data(arg_t *, asn1p_expr_t *eclass,
5 struct asn1p_ioc_row_s *row, asn1p_wsyntx_t *syntax,
Lev Walkinea6635b2017-08-06 23:23:04 -07006 const uint8_t *buf, const uint8_t *bend,
7 int optional_mode, const uint8_t **newpos);
8static int _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell, const uint8_t *buf, const uint8_t *bend);
9static asn1p_wsyntx_chunk_t *asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, const uint8_t *buf);
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080010
11int
12asn1f_check_class_object(arg_t *arg) {
13 asn1p_expr_t *expr = arg->expr;
14 asn1p_expr_t *eclass;
15 asn1p_ioc_row_t *row;
16 int ret;
17
Lev Walkinea6635b2017-08-06 23:23:04 -070018 if(expr->meta_type != AMT_VALUESET
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080019 || expr->expr_type != A1TC_REFERENCE
20 || !expr->value
Lev Walkinea6635b2017-08-06 23:23:04 -070021 || expr->value->type != ATV_UNPARSED) {
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080022 return 0;
Lev Walkinea6635b2017-08-06 23:23:04 -070023 }
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +080024
25 eclass = asn1f_find_terminal_type(arg, expr);
26 if(!eclass
27 || eclass->meta_type != AMT_OBJECTCLASS
28 || eclass->expr_type != A1TC_CLASSDEF) {
29 return 0;
30 }
31
32 if(!eclass->with_syntax) {
33 DEBUG("Can't process classes without %s just yet",
34 "WITH SYNTAX");
35 return 0;
36 }
37
38 row = asn1p_ioc_row_new(eclass);
39 assert(row);
40
41 ret = _asn1f_parse_class_object_data(arg, eclass, row,
42 eclass->with_syntax,
43 expr->value->value.string.buf + 1,
44 expr->value->value.string.buf
45 + expr->value->value.string.size - 1,
46 0, 0);
47
48 asn1p_ioc_row_delete(row);
49
50 return ret;
51}
Lev Walkin9d542d22006-03-14 16:31:37 +000052
Lev Walkinea6635b2017-08-06 23:23:04 -070053static int
54_asn1f_is_ioc_row_duplicate(asn1p_ioc_row_t **rows, size_t count, asn1p_ioc_row_t *row) {
55 for(size_t i = 0; i < count; i++) {
56 switch(asn1p_ioc_row_match(rows[i], row)) {
57 default:
58 case -1:
59 return -1;
60 case 1:
61 continue;
62 case 0:
63 return 1; /* Duplicate! */
64 }
65 }
66 return 0;
67}
68
69struct parse_object_key {
70 arg_t *arg;
71 asn1p_expr_t *expr; /* InformationObjectSet */
72 asn1p_expr_t *eclass; /* CLASS */
73};
74
75static int
76_asn1f_add_row(arg_t *arg, asn1p_expr_t *expr, asn1p_ioc_row_t *row) {
77 void *new_rows_ptr;
78
79 switch(_asn1f_is_ioc_row_duplicate(expr->object_class_matrix.row,
80 expr->object_class_matrix.rows, row)) {
81 case -1:
82 DEBUG("Found Information Object Duplicate in %s", expr->Identifier,
83 expr->_lineno);
84 return -1;
85 case 0:
86 /* Not a duplicate */
87 break;
88 case 1:
89 /* Proper duplicate detected; ignore */
90 asn1p_ioc_row_delete(row);
91 return 0;
92 }
93
94 new_rows_ptr = realloc(expr->object_class_matrix.row,
95 (expr->object_class_matrix.rows + 1)
96 * sizeof(expr->object_class_matrix.row[0]));
97 assert(new_rows_ptr);
98 expr->object_class_matrix.row = new_rows_ptr;
99 expr->object_class_matrix.row[expr->object_class_matrix.rows] = row;
100 expr->object_class_matrix.rows++;
101 /* Propagate max identifier length */
102 if(expr->object_class_matrix.max_identifier_length
103 < row->max_identifier_length)
104 expr->object_class_matrix.max_identifier_length
105 = row->max_identifier_length;
106
107 return 0;
108}
109
110/*
111 * Given a single blob of unparsed Information Object specification, parse it
112 * into a given InformationObjectSet.
113 */
114static int
115_asn1f_parse_object_cb(const uint8_t *buf, size_t size, void *keyp) {
116 struct parse_object_key *key = keyp;
117 arg_t *arg = key->arg;
118 asn1p_expr_t *expr = key->expr;
119 asn1p_expr_t *eclass = key->eclass;
120 asn1p_ioc_row_t *row;
121 int ret;
122
123 row = asn1p_ioc_row_new(eclass);
124 assert(row);
125
126 ret = _asn1f_parse_class_object_data(arg, eclass, row, eclass->with_syntax,
127 buf, buf + size, 0, 0);
128 if(ret) {
129 LOG((int)(ret < 0),
130 "Cannot parse %s of CLASS %s found at line %d",
131 expr->Identifier, eclass->Identifier, expr->_lineno);
132 asn1p_ioc_row_delete(row);
133 return ret;
134 }
135
136 /* Add object to a CLASS. */
137 if(_asn1f_add_row(arg, eclass, row) != 0)
138 return -1;
139
140 /*
141 * Add a copy of the object to the Information Object Set.
142 */
143 row = asn1p_ioc_row_new(eclass);
144 assert(row);
145 ret = _asn1f_parse_class_object_data(arg, eclass, row, eclass->with_syntax,
146 buf, buf + size, 0, 0);
147 assert(ret == 0);
148
149 if(_asn1f_add_row(arg, expr, row) != 0)
150 return -1;
151
152 return 0;
153}
154
155static int
156_asn1f_foreach_unparsed_union(const asn1p_constraint_t *ct_union,
157 int (*process)(const uint8_t *buf, size_t size,
158 void *key),
159 void *key) {
160 assert(ct_union->type == ACT_CA_UNI);
161
162 for(size_t j = 0; j < ct_union->el_count; j++) {
163 const asn1p_constraint_t *ct2 = ct_union->elements[j];
164 if(ct2->type == ACT_EL_VALUE && ct2->value->type == ATV_UNPARSED) {
165 if(process
166 && process(ct2->value->value.string.buf + 1,
167 ct2->value->value.string.size - 2, key)
168 != 0) {
169 return -1;
170 }
171 continue;
172 }
173 return -1;
174 }
175
176 return 0;
177}
178
179static int
180_asn1f_foreach_unparsed(const asn1p_constraint_t *ct,
181 int (*process)(const uint8_t *buf, size_t size,
182 void *key),
183 void *key) {
184 if(!ct) return -1;
185 if(ct->type == ACT_CA_UNI) {
186 return _asn1f_foreach_unparsed_union(ct, process, key);
187 }
188 if(ct->type != ACT_CA_CSV) return -1;
189
190 for(size_t i = 0; i < ct->el_count; i++) {
191 const asn1p_constraint_t *ct1 = ct->elements[i];
192 switch(ct1->type) {
193 case ACT_EL_EXT:
194 break;
195 case ACT_CA_UNI:
196 if(_asn1f_foreach_unparsed_union(ct1, process, key) != 0) {
197 return -1;
198 }
199 break;
200 default:
201 return -1;
202 }
203 }
204
205 return 0;
206}
207
208static int
209_asn1f_constraint_looks_like_object_set(const asn1p_constraint_t *ct) {
210 return 0 == _asn1f_foreach_unparsed(ct, NULL, NULL);
211}
212
Lev Walkind370e9f2006-03-16 10:03:35 +0000213int
214asn1f_parse_class_object(arg_t *arg) {
215 asn1p_expr_t *expr = arg->expr;
216 asn1p_expr_t *eclass;
Lev Walkinea6635b2017-08-06 23:23:04 -0700217 enum {
218 FROM_VALUE,
219 FROM_CONSTRAINT,
220 } source = FROM_VALUE;
Lev Walkind370e9f2006-03-16 10:03:35 +0000221
Lev Walkinea6635b2017-08-06 23:23:04 -0700222 if(expr->meta_type == AMT_VALUE
223 && expr->expr_type == A1TC_REFERENCE
224 && expr->value && expr->value->type == ATV_UNPARSED) {
225 source = FROM_VALUE;
226 } else if(expr->meta_type != AMT_VALUESET
227 || expr->expr_type != A1TC_REFERENCE) {
228 return 0;
229 } else if(expr->value && expr->value->type == ATV_UNPARSED) {
230 source = FROM_VALUE;
231 } else if(!expr->value) {
232 if(_asn1f_constraint_looks_like_object_set(expr->constraints)) {
233 source = FROM_CONSTRAINT;
234 } else {
235 return 0;
236 }
237 } else {
238 return 0;
239 }
Lev Walkin9d542d22006-03-14 16:31:37 +0000240
Lev Walkind370e9f2006-03-16 10:03:35 +0000241 /*
242 * Find the governing class.
243 */
244 eclass = asn1f_find_terminal_type(arg, expr);
245 if(!eclass
246 || eclass->meta_type != AMT_OBJECTCLASS
247 || eclass->expr_type != A1TC_CLASSDEF) {
248 return 0;
249 }
250
251 DEBUG("Value %s of CLASS %s found at line %d",
252 expr->Identifier, eclass->Identifier, expr->_lineno);
253
254 if(!eclass->with_syntax) {
Lev Walkinfaf35a82006-03-16 13:37:03 +0000255 DEBUG("Can't process classes without %s just yet",
256 "WITH SYNTAX");
Lev Walkind370e9f2006-03-16 10:03:35 +0000257 return 0;
258 }
259
Lev Walkinea6635b2017-08-06 23:23:04 -0700260 struct parse_object_key key = {
261 .arg = arg,
262 .expr = expr,
263 .eclass = eclass,
264 };
Lev Walkind370e9f2006-03-16 10:03:35 +0000265
Lev Walkinea6635b2017-08-06 23:23:04 -0700266 switch(source) {
267 case FROM_VALUE:
268 if(_asn1f_parse_object_cb(expr->value->value.string.buf + 1,
269 expr->value->value.string.size - 2, &key)
270 != 0) {
271 return -1;
272 }
273 break;
274 case FROM_CONSTRAINT:
275 if(_asn1f_foreach_unparsed(expr->constraints, _asn1f_parse_object_cb,
276 &key)
277 != 0) {
278 return -1;
279 }
280 }
Lev Walkin9d542d22006-03-14 16:31:37 +0000281
282 return 0;
283}
Lev Walkind370e9f2006-03-16 10:03:35 +0000284
285#define SKIPSPACES for(; buf < bend && isspace(*buf); buf++)
286
287static int
288_asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass,
289 struct asn1p_ioc_row_s *row, asn1p_wsyntx_t *syntax,
Lev Walkinea6635b2017-08-06 23:23:04 -0700290 const uint8_t *buf, const uint8_t *bend,
291 int optional_mode, const uint8_t **newpos) {
Lev Walkind370e9f2006-03-16 10:03:35 +0000292 struct asn1p_wsyntx_chunk_s *chunk;
293 int ret;
294
295 TQ_FOR(chunk, (&syntax->chunks), next) {
296 switch(chunk->type) {
297 case WC_LITERAL: {
298 int token_len = strlen(chunk->content.token);
299 SKIPSPACES;
300 if(bend - buf < token_len
301 || memcmp(buf, chunk->content.token, token_len)) {
302 if(!optional_mode) {
303 FATAL("While parsing object class value %s at line %d: Expected: \"%s\", found: \"%s\"",
304 arg->expr->Identifier, arg->expr->_lineno, chunk->content.token, buf);
305 }
306 if(newpos) *newpos = buf;
307 return -1;
308 }
309 buf += token_len;
310 } break;
311 case WC_WHITESPACE: break; /* Ignore whitespace */
312 case WC_FIELD: {
313 struct asn1p_ioc_cell_s *cell;
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800314 asn1p_wsyntx_chunk_t *next_literal;
Lev Walkinea6635b2017-08-06 23:23:04 -0700315 const uint8_t *buf_old = buf;
316 const uint8_t *p = 0;
Lev Walkinfaf35a82006-03-16 13:37:03 +0000317
318 SKIPSPACES;
319
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800320 next_literal = asn1f_next_literal_chunk(syntax, chunk, buf);
321 if(!next_literal) {
322 p += (bend - p);
323 } else {
Lev Walkinea6635b2017-08-06 23:23:04 -0700324 p = (uint8_t *)strstr((const char *)buf, (const char *)next_literal->content.token);
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800325 if(!p) {
326 if (!optional_mode)
327 FATAL("Next literal \"%s\" not found !", next_literal->content.token);
328
329 if(newpos) *newpos = buf_old;
330 return -1;
Lev Walkind370e9f2006-03-16 10:03:35 +0000331 }
332 }
Lev Walkind370e9f2006-03-16 10:03:35 +0000333 cell = asn1p_ioc_row_cell_fetch(row,
334 chunk->content.token);
335 if(cell == NULL) {
336 FATAL("Field reference %s found in WITH SYNAX {} clause does not match actual field in Object Class %s",
337 chunk->content.token,
338 eclass->Identifier, eclass->_lineno);
339 if(newpos) *newpos = buf;
340 return -1;
341 }
342 DEBUG("Reference %s satisfied by %s (%d)",
343 chunk->content.token,
344 buf, p - buf);
345 ret = _asn1f_assign_cell_value(arg, row, cell, buf, p);
Lev Walkindc4376d2006-03-16 11:04:55 +0000346 if(ret) return ret;
Lev Walkind370e9f2006-03-16 10:03:35 +0000347 buf = p;
Lev Walkindc4376d2006-03-16 11:04:55 +0000348 if(newpos) *newpos = buf;
Lev Walkind370e9f2006-03-16 10:03:35 +0000349 } break;
350 case WC_OPTIONALGROUP: {
Lev Walkinea6635b2017-08-06 23:23:04 -0700351 const uint8_t *np = 0;
Lev Walkind370e9f2006-03-16 10:03:35 +0000352 SKIPSPACES;
353 ret = _asn1f_parse_class_object_data(arg, eclass, row,
354 chunk->content.syntax, buf, bend, 1, &np);
355 if(newpos) *newpos = np;
356 if(ret && np != buf)
357 return ret;
Lev Walkindc4376d2006-03-16 11:04:55 +0000358 buf = np;
Lev Walkind370e9f2006-03-16 10:03:35 +0000359 } break;
360 }
361 }
362
363
364 if(newpos) *newpos = buf;
365 return 0;
366}
367
368
369static int
Lev Walkinea6635b2017-08-06 23:23:04 -0700370_asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row,
371 struct asn1p_ioc_cell_s *cell, const uint8_t *buf,
372 const uint8_t *bend) {
373 asn1p_expr_t *expr = (asn1p_expr_t *)NULL;
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000374 int idLength;
Lev Walkind370e9f2006-03-16 10:03:35 +0000375 char *p;
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800376 int new_ref = 1;
377 asn1p_t *asn;
378 asn1p_module_t *mod;
379 asn1p_expr_t *type_expr = (asn1p_expr_t *)NULL;
380 int i, ret = 0, psize;
381 char *pp;
Lev Walkind370e9f2006-03-16 10:03:35 +0000382
383 if((bend - buf) <= 0) {
384 FATAL("Assignment warning: empty string is being assigned into %s for %s at line %d",
385 cell->field->Identifier,
386 arg->expr->Identifier, arg->expr->_lineno);
387 return -1;
388 }
389
390 p = malloc(bend - buf + 1);
391 assert(p);
392 memcpy(p, buf, bend - buf);
393 p[bend - buf] = '\0';
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800394 /* remove trailing space */
395 for (i = bend - buf - 1; (i > 0) && isspace(p[i]); i--)
396 p[i] = '\0';
Lev Walkind370e9f2006-03-16 10:03:35 +0000397
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800398 /* This value 100 should be larger than following formatting string */
399 psize = bend - buf + 100;
400 pp = malloc(psize);
401 if(pp == NULL) {
402 free(p);
403 return -1;
404 }
Lev Walkind370e9f2006-03-16 10:03:35 +0000405
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800406 if(cell->field->expr_type == A1TC_CLASSFIELD_TFS) {
407 ret = snprintf(pp, psize,
408 "M DEFINITIONS ::=\nBEGIN\n"
409 "V ::= %s\n"
410 "END\n",
411 p
412 );
413 } else if(cell->field->expr_type == A1TC_CLASSFIELD_FTVFS) {
414 type_expr = TQ_FIRST(&(cell->field->members));
415 ret = snprintf(pp, psize,
416 "M DEFINITIONS ::=\nBEGIN\n"
417 "v %s ::= %s\n"
418 "END\n",
419 type_expr->reference ?
420 type_expr->reference->components[0].name :
421 _asn1p_expr_type2string(type_expr->expr_type),
422 p
423 );
Lev Walkind370e9f2006-03-16 10:03:35 +0000424 } else {
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800425 WARNING("asn1c only be able to parse TypeFieldSpec and FixedTypeValueFieldSpec. Failed when parsing %s at line %d\n", p, arg->expr->_lineno);
Lev Walkinaf8595a2017-06-27 08:22:30 -0700426 free(p);
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800427 free(pp);
428 return -1;
429 }
Lev Walkinea6635b2017-08-06 23:23:04 -0700430 DEBUG("ASN.1:\n\n%s\n", pp);
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800431
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800432 assert(ret < psize);
433 psize = ret;
434
435 asn = asn1p_parse_buffer(pp, psize, A1P_NOFLAGS);
436 free(pp);
437 if(asn == NULL) {
438 FATAL("Cannot parse Setting token %s "
439 "at line %d",
440 p,
441 arg->expr->_lineno
442 );
443 free(p);
444 return -1;
445 } else {
446 mod = TQ_FIRST(&(asn->modules));
447 assert(mod);
448 expr = TQ_REMOVE(&(mod->members), next);
449 assert(expr);
450
451 free(expr->Identifier);
Lev Walkinea6635b2017-08-06 23:23:04 -0700452 expr->parent_expr = NULL;
453 asn1p_expr_set_source(expr, arg->expr->module, arg->expr->_lineno);
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800454 if (expr->reference) {
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800455 expr->Identifier = strdup(expr->reference->components[expr->reference->comp_count - 1].name);
456 } else {
457 expr->Identifier = p;
458 }
459 asn1p_delete(asn);
460 }
461
462 if(expr->reference &&
463 !asn1f_lookup_symbol(arg, arg->mod, expr->rhs_pspecs, expr->reference)) {
464
465 asn1p_ref_free(expr->reference);
466 new_ref = 0;
467 expr->reference = type_expr->reference;
468 if (asn1f_value_resolve(arg, expr, 0)) {
469 expr->reference = 0;
470 asn1p_expr_free(expr);
Lev Walkind370e9f2006-03-16 10:03:35 +0000471 FATAL("Cannot find %s referenced by %s at line %d",
472 p, arg->expr->Identifier,
473 arg->expr->_lineno);
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800474 free(p); /* freeing must happen *after* p was used in FATAL() */
Lev Walkind370e9f2006-03-16 10:03:35 +0000475 return -1;
476 }
477 }
478
479 DEBUG("Field %s assignment of %s got %s",
480 cell->field->Identifier, p, expr->Identifier);
481
482 cell->value = expr;
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800483 cell->new_ref = new_ref;
Lev Walkind370e9f2006-03-16 10:03:35 +0000484
Lev Walkinc46b7cb2006-08-18 02:27:55 +0000485 idLength = strlen(expr->Identifier);
486 if(row->max_identifier_length < idLength)
487 row->max_identifier_length = idLength;
Lev Walkind370e9f2006-03-16 10:03:35 +0000488
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800489 if(expr->Identifier != p)
490 free(p);
491
Lev Walkind370e9f2006-03-16 10:03:35 +0000492 return 0;
493}
494
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800495static asn1p_wsyntx_chunk_t *
Lev Walkinea6635b2017-08-06 23:23:04 -0700496asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, const uint8_t *buf)
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800497{
498 asn1p_wsyntx_chunk_t *next_chunk;
499
500 next_chunk = TQ_NEXT(chunk, next);
501 do {
502 if(next_chunk == (struct asn1p_wsyntx_chunk_s *)0) {
503 if(!syntax->parent)
504 break;
505 next_chunk = TQ_NEXT(syntax->parent, next);
506 } else if(next_chunk->type == WC_LITERAL) {
Lev Walkinea6635b2017-08-06 23:23:04 -0700507 if(strstr((const char *)buf, (char *)next_chunk->content.token))
Bi-Ruei, Chiu80fd3062017-05-07 21:00:51 +0800508 break;
509 if(!syntax->parent)
510 break;
511 next_chunk = TQ_NEXT(syntax->parent, next);
512 } else if(next_chunk->type == WC_WHITESPACE) {
513 next_chunk = TQ_NEXT(next_chunk, next);
514 } else if(next_chunk->type == WC_OPTIONALGROUP) {
515 syntax = next_chunk->content.syntax;
516 next_chunk = TQ_FIRST(((&next_chunk->content.syntax->chunks)));
517 } else
518 break;
519 } while (next_chunk);
520
521 return next_chunk;
522}