62bb883bdb710bc198c79c0c5cc73237d21ed0cc
[com/asn1c.git] / libasn1fix / asn1fix_cws.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "asn1fix_internal.h"
4 #include "asn1fix_cws.h"
5
6 static int _asn1f_parse_class_object_data(arg_t *, asn1p_expr_t *eclass,
7                 struct asn1p_ioc_row_s *row, asn1p_wsyntx_t *syntax,
8                 const uint8_t *buf, const uint8_t *bend,
9                 int optional_mode, const uint8_t **newpos, int counter);
10 static int _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell, const uint8_t *buf, const uint8_t *bend, int counter);
11 static asn1p_wsyntx_chunk_t *asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, const uint8_t *buf);
12
13 int
14 asn1f_check_class_object(arg_t *arg) {
15         asn1p_expr_t *expr = arg->expr;
16         asn1p_expr_t *eclass;
17         asn1p_ioc_row_t *row;
18         int ret;
19
20         if(expr->meta_type != AMT_VALUESET
21         || expr->expr_type != A1TC_REFERENCE
22         || !expr->value
23         || expr->value->type != ATV_UNPARSED) {
24                 return 0;
25     }
26
27         eclass = asn1f_find_terminal_type(arg, expr);
28         if(!eclass
29         || eclass->meta_type != AMT_OBJECTCLASS
30         || eclass->expr_type != A1TC_CLASSDEF) {
31                 return 0;
32         }
33
34         if(!eclass->with_syntax) {
35                 DEBUG("Can't process classes without %s just yet",
36                         "WITH SYNTAX");
37                 return 0;
38         }
39
40         row = asn1p_ioc_row_new(eclass);
41         assert(row);
42
43         ret = _asn1f_parse_class_object_data(arg, eclass, row,
44                 eclass->with_syntax,
45                 expr->value->value.string.buf + 1,
46                 expr->value->value.string.buf
47                         + expr->value->value.string.size - 1,
48                 0, 0, 0);
49
50         asn1p_ioc_row_delete(row);
51
52         return ret;
53 }
54
55 static int
56 _asn1f_is_ioc_row_duplicate(asn1p_ioc_table_t *it, asn1p_ioc_row_t *row) {
57     if(!it) {
58         return 0;
59     }
60
61     for(size_t i = 0; i < it->rows; i++) {
62         switch(asn1p_ioc_row_match(it->row[i], row)) {
63         default:
64         case -1:
65             return -1;
66         case 1:
67             continue;
68         case 0:
69             return 1; /* Duplicate! */
70         }
71     }
72     return 0;
73 }
74
75 struct parse_object_key {
76     arg_t *arg;
77     asn1p_expr_t *expr;   /* InformationObjectSet */
78     asn1p_expr_t *eclass; /* CLASS */
79     int sequence;          /* Sequence counter */
80 };
81
82 /*
83  * Add to the IoC table if the row is unique.
84  */
85 static int
86 _asn1f_add_unique_row(arg_t *arg, asn1p_expr_t *expr, asn1p_ioc_row_t *row) {
87     assert(expr->ioc_table);
88
89     /* Look for duplicates */
90     switch(_asn1f_is_ioc_row_duplicate(expr->ioc_table, row)) {
91     case -1:
92         DEBUG("Found Information Object Duplicate in %s", expr->Identifier,
93               expr->_lineno);
94         return -1;
95     case 0:
96         /* Not a duplicate */
97         break;
98     case 1:
99         /* Proper duplicate detected; ignore */
100         asn1p_ioc_row_delete(row);
101         return 0;
102         }
103
104     asn1p_ioc_table_add(expr->ioc_table, row);
105
106     return 0;
107 }
108
109 /*
110  * Given a single blob of unparsed Information Object specification, parse it
111  * into a given InformationObjectSet.
112  */
113 static int
114 _asn1f_parse_object_cb(const uint8_t *buf, size_t size, void *keyp) {
115     struct parse_object_key *key = keyp;
116     arg_t *arg = key->arg;
117     asn1p_expr_t *expr = key->expr;
118     asn1p_expr_t *eclass = key->eclass;
119         asn1p_ioc_row_t *row;
120     int ret;
121
122     key->sequence++;
123
124         row = asn1p_ioc_row_new(eclass);
125         assert(row);
126
127     ret = _asn1f_parse_class_object_data(arg, eclass, row, eclass->with_syntax,
128                                          buf, buf + size, 0, 0, key->sequence);
129     if(ret) {
130         LOG(ret, "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_unique_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, key->sequence);
147     assert(ret == 0);
148
149     if(_asn1f_add_unique_row(arg, expr, row) != 0)
150         return -1;
151
152     return 0;
153 }
154
155 static 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
179 static int
180 _asn1f_foreach_unparsed(arg_t *arg, const asn1p_constraint_t *ct,
181                         int (*process)(const uint8_t *buf, size_t size,
182                                        void *key),
183                         void *keyp) {
184     struct parse_object_key *key = keyp;
185     if(!ct) return -1;
186
187     switch(ct->type) {
188     default:
189         DEBUG("Constraint is of unknown type %d for CWS", ct->type);
190         return -1;
191     case ACT_EL_EXT:    /* ... */
192         if(key) {
193             key->expr->ioc_table->extensible = 1;
194         }
195         return 0;
196     case ACT_CA_UNI:    /* | */
197         return _asn1f_foreach_unparsed_union(ct, process, keyp);
198     case ACT_CA_CSV:    /* , */
199         break;
200     case ACT_EL_VALUE:
201         if(ct->value->type == ATV_UNPARSED) {
202             if(process
203                && process(ct->value->value.string.buf + 1,
204                           ct->value->value.string.size - 2, key)
205                       != 0) {
206                 return -1;
207             }
208         }
209         return 0;
210     }
211
212     for(size_t i = 0; i < ct->el_count; i++) {
213         const asn1p_constraint_t *ct1 = ct->elements[i];
214         if(_asn1f_foreach_unparsed(arg, ct1, process, keyp) != 0) {
215             return -1;
216         }
217     }
218
219     return 0;
220 }
221
222 static int
223 _asn1f_constraint_looks_like_object_set(arg_t *arg,
224                                         const asn1p_constraint_t *ct) {
225     return 0 == _asn1f_foreach_unparsed(arg, ct, NULL, NULL);
226 }
227
228 int
229 asn1f_parse_class_object(arg_t *arg) {
230         asn1p_expr_t *expr = arg->expr;
231         asn1p_expr_t *eclass;
232     enum {
233         FROM_VALUE,
234         FROM_CONSTRAINT,
235     } source = FROM_VALUE;
236
237         if(expr->meta_type == AMT_VALUE
238         && expr->expr_type == A1TC_REFERENCE
239         && expr->value && expr->value->type == ATV_UNPARSED) {
240         source = FROM_VALUE;
241     } else if(expr->meta_type != AMT_VALUESET
242         || expr->expr_type != A1TC_REFERENCE) {
243         return 0;
244     } else if(expr->value && expr->value->type == ATV_UNPARSED) {
245         source = FROM_VALUE;
246     } else if(!expr->value) {
247         if(_asn1f_constraint_looks_like_object_set(arg, expr->constraints)) {
248             source = FROM_CONSTRAINT;
249         } else {
250             return 0;
251         }
252     } else {
253         return 0;
254     }
255
256         /*
257          * Find the governing class.
258          */
259         eclass = asn1f_find_terminal_type(arg, expr);
260         if(!eclass
261         || eclass->meta_type != AMT_OBJECTCLASS
262         || eclass->expr_type != A1TC_CLASSDEF) {
263                 return 0;
264         }
265
266         DEBUG("Value %s of CLASS %s found at line %d",
267                 expr->Identifier, eclass->Identifier, expr->_lineno);
268
269         if(!eclass->with_syntax) {
270                 DEBUG("Can't process classes without %s just yet",
271                         "WITH SYNTAX");
272                 return 0;
273         }
274
275     struct parse_object_key key = {
276         .arg = arg,
277         .expr = expr,
278         .eclass = eclass,
279         .sequence = eclass->_type_unique_index
280     };
281
282     if(!expr->ioc_table) {
283         expr->ioc_table = asn1p_ioc_table_new();
284     }
285
286     if(!eclass->ioc_table) {
287         eclass->ioc_table = asn1p_ioc_table_new();
288     }
289
290     switch(source) {
291     case FROM_VALUE:
292         if(_asn1f_parse_object_cb(expr->value->value.string.buf + 1,
293                            expr->value->value.string.size - 2, &key)
294            != 0) {
295             return -1;
296         }
297         break;
298     case FROM_CONSTRAINT:
299         if(_asn1f_foreach_unparsed(arg, expr->constraints,
300                                    _asn1f_parse_object_cb, &key)
301            != 0) {
302             return -1;
303         }
304     }
305
306     eclass->_type_unique_index = key.sequence;
307
308         return 0;
309 }
310
311 #define SKIPSPACES      for(; buf < bend && isspace(*buf); buf++)
312
313 static int
314 _asn1f_parse_class_object_data(arg_t *arg, asn1p_expr_t *eclass,
315                 struct asn1p_ioc_row_s *row, asn1p_wsyntx_t *syntax,
316                 const uint8_t *buf, const uint8_t *bend,
317                 int optional_mode, const uint8_t **newpos, int counter) {
318         struct asn1p_wsyntx_chunk_s *chunk;
319         int ret;
320
321         TQ_FOR(chunk, (&syntax->chunks), next) {
322                 switch(chunk->type) {
323                 case WC_LITERAL: {
324                         int token_len = strlen(chunk->content.token);
325                         SKIPSPACES;
326                         if(bend - buf < token_len
327                         || memcmp(buf, chunk->content.token, token_len)) {
328                                 if(!optional_mode) {
329                                         FATAL("While parsing object class value %s at line %d: Expected: \"%s\", found: \"%s\"",
330                                         arg->expr->Identifier, arg->expr->_lineno, chunk->content.token, buf);
331                                 }
332                                 if(newpos) *newpos = buf;
333                                 return -1;
334                         }
335                         buf += token_len;
336                     } break;
337                 case WC_WHITESPACE: break;      /* Ignore whitespace */
338                 case WC_FIELD: {
339                         struct asn1p_ioc_cell_s *cell;
340                         asn1p_wsyntx_chunk_t *next_literal;
341                         const uint8_t *buf_old = buf;
342                         const uint8_t *p = 0;
343
344                         SKIPSPACES;
345
346                         next_literal = asn1f_next_literal_chunk(syntax, chunk, buf);
347                         if(!next_literal) {
348                                 p += (bend - p);
349                         } else {
350                                 p = (uint8_t *)strstr((const char *)buf, (const char *)next_literal->content.token);
351                                 if(!p) {
352                                         if (!optional_mode)
353                                                 FATAL("Next literal \"%s\" not found !", next_literal->content.token);
354
355                                         if(newpos) *newpos = buf_old;
356                                         return -1;
357                                 }
358                         }
359                         cell = asn1p_ioc_row_cell_fetch(row,
360                                         chunk->content.token);
361                         if(cell == NULL) {
362                                 FATAL("Field reference %s found in WITH SYNAX {} clause does not match actual field in Object Class %s",
363                                         chunk->content.token,
364                                         eclass->Identifier, eclass->_lineno);
365                                 if(newpos) *newpos = buf;
366                                 return -1;
367                         }
368                         DEBUG("Reference %s satisfied by %s (%d)",
369                                 chunk->content.token,
370                                 buf, p - buf);
371                         ret = _asn1f_assign_cell_value(arg, cell, buf, p, counter);
372                         if(ret) return ret;
373                         buf = p;
374                         if(newpos) *newpos = buf;
375                     } break;
376                 case WC_OPTIONALGROUP: {
377                         const uint8_t *np = 0;
378                         SKIPSPACES;
379                         ret = _asn1f_parse_class_object_data(arg, eclass, row,
380                                 chunk->content.syntax, buf, bend, 1, &np, counter);
381                         if(newpos) *newpos = np;
382                         if(ret && np != buf)
383                                 return ret;
384                         buf = np;
385                     } break;
386                 }
387         }
388
389
390         if(newpos) *newpos = buf;
391         return 0;
392 }
393
394
395 static int
396 _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_cell_s *cell,
397                          const uint8_t *buf, const uint8_t *bend, int counter) {
398     asn1p_expr_t *expr = (asn1p_expr_t *)NULL;
399         char *mivr; /* Most Immediate Value Representation */
400         int new_ref = 1;
401         asn1p_t *asn;
402         asn1p_expr_t *type_expr = (asn1p_expr_t *)NULL;
403         int i, ret = 0, psize;
404         char *pp;
405
406         if((bend - buf) <= 0) {
407                 FATAL("Assignment warning: empty string is being assigned into %s for %s at line %d",
408                         cell->field->Identifier,
409                         arg->expr->Identifier, arg->expr->_lineno);
410                 return -1;
411         }
412
413         mivr = malloc(bend - buf + 1);
414         assert(mivr);
415         memcpy(mivr, buf, bend - buf);
416         mivr[bend - buf] = '\0';
417         /* remove trailing space */
418         for (i = bend - buf - 1; (i > 0) && isspace(mivr[i]); i--)
419                 mivr[i] = '\0';
420
421         /* This value 100 should be larger than following formatting string */
422         psize = bend - buf + 100;
423         pp = calloc(1, psize);
424         if(pp == NULL) {
425                 free(mivr);
426                 return -1;
427         }
428
429         if(cell->field->expr_type == A1TC_CLASSFIELD_TFS) {
430                 ret = snprintf(pp, psize,
431                         "M DEFINITIONS ::=\nBEGIN\n"
432                         "V ::= %s\n"
433                         "END\n",
434                         mivr
435                 );
436         } else if(cell->field->expr_type == A1TC_CLASSFIELD_FTVFS) {
437                 type_expr = TQ_FIRST(&(cell->field->members));
438                 ret = snprintf(pp, psize,
439                                 "M DEFINITIONS ::=\nBEGIN\n"
440                                 "v %s ::= %s\n"
441                                 "END\n",
442                                 type_expr->reference ? 
443                                         type_expr->reference->components[0].name : 
444                                         _asn1p_expr_type2string(type_expr->expr_type),
445                                 mivr
446                         );
447         } else {
448                 WARNING("asn1c only be able to parse TypeFieldSpec and FixedTypeValueFieldSpec. Failed when parsing %s at line %d\n", mivr, arg->expr->_lineno);
449                 free(mivr);
450                 free(pp);
451                 return -1;
452         }
453         DEBUG("ASN.1:\n\n%s\n", pp);
454
455         assert(ret < psize);
456         psize = ret;
457
458         asn = asn1p_parse_buffer(pp, psize,
459                 arg->expr->module->source_file_name, arg->expr->_lineno, A1P_NOFLAGS);
460         free(pp);
461         if(asn == NULL) {
462                 FATAL("Cannot parse Setting token %s "
463                         "at line %d",
464                         mivr,
465                         arg->expr->_lineno
466                 );
467                 free(mivr);
468                 return -1;
469         } else {
470         asn1p_module_t *mod = TQ_FIRST(&(asn->modules));
471         assert(mod);
472
473         /* This member removal is safe with respect to members hash since the
474          * entire asn module will be deleted down below.
475          */
476         expr = TQ_REMOVE(&(mod->members), next);
477                 assert(expr);
478
479         expr->parent_expr = NULL;
480         asn1p_expr_set_source(expr, arg->expr->module, arg->expr->_lineno);
481         expr->_type_unique_index = counter;
482         DEBUG("Parsed identifier %s, mivr [%s], reference [%s] value [%s]",
483               expr->Identifier, mivr, asn1p_ref_string(expr->reference),
484               asn1f_printable_value(expr->value));
485         free(expr->Identifier);
486         if(expr->value) {
487                         expr->Identifier = strdup(asn1f_printable_value(expr->value));
488         } else if (expr->reference) {
489                         expr->Identifier = strdup(expr->reference->components[expr->reference->comp_count - 1].name);
490                 } else {
491                         expr->Identifier = mivr;
492                 }
493                 asn1p_delete(asn);
494         }
495
496         if(expr->reference &&
497                 !asn1f_lookup_symbol(arg, expr->rhs_pspecs, expr->reference)) {
498
499                 asn1p_ref_free(expr->reference);
500                 new_ref = 0;
501                 expr->reference = type_expr->reference;
502                 if (asn1f_value_resolve(arg, expr, 0)) {
503                         expr->reference = 0;
504                         asn1p_expr_free(expr);
505                         FATAL("Cannot find %s referenced by %s at line %d",
506                                 mivr, arg->expr->Identifier,
507                                 arg->expr->_lineno);
508                         free(mivr);
509                         return -1;
510                 }
511         }
512
513         DEBUG("Field %s assignment of %s got %s",
514                 cell->field->Identifier, mivr, expr->Identifier);
515
516         cell->value = expr;
517         cell->new_ref = new_ref;
518
519         if(expr->Identifier != mivr) {
520                 free(mivr);
521     }
522
523         return 0;
524 }
525
526 static asn1p_wsyntx_chunk_t *
527 asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, const uint8_t *buf)
528 {
529         asn1p_wsyntx_chunk_t *next_chunk;
530
531         next_chunk = TQ_NEXT(chunk, next);
532         do {
533                 if(next_chunk == (struct asn1p_wsyntx_chunk_s *)0) {
534                         if(!syntax->parent)
535                                 break;
536                         next_chunk = TQ_NEXT(syntax->parent, next);
537                 } else if(next_chunk->type == WC_LITERAL) {
538                         if(strstr((const char *)buf, (char *)next_chunk->content.token))
539                                 break;
540                         if(!syntax->parent)
541                                 break;
542                         next_chunk = TQ_NEXT(syntax->parent, next);
543                 } else if(next_chunk->type == WC_WHITESPACE) {
544                         next_chunk = TQ_NEXT(next_chunk, next);
545                 } else if(next_chunk->type == WC_OPTIONALGROUP) {
546                         syntax = next_chunk->content.syntax;
547                         next_chunk = TQ_FIRST(((&next_chunk->content.syntax->chunks)));
548                 } else 
549                         break;
550         } while (next_chunk);
551
552         return next_chunk;
553 }