005088d5203cc987a3db3597c3bbd2f550821c0f
[com/asn1c.git] / libasn1compiler / asn1c_ioc.c
1 #include "asn1c_internal.h"
2 #include "asn1c_ioc.h"
3 #include "asn1c_out.h"
4 #include "asn1c_misc.h"
5 #include <asn1fix_export.h>
6 #include <asn1print.h>
7
8 #define MKID(expr) asn1c_make_identifier(AMI_USE_PREFIX, (expr), 0)
9
10 /*
11  * Given the table constraint or component relation constraint
12  * ({ObjectSetName}{...}) returns "ObjectSetName" as a reference.
13  */
14 const asn1p_ref_t *
15 asn1c_get_information_object_set_reference_from_constraint(arg_t *arg,
16     const asn1p_constraint_t *ct) {
17
18     if(!ct) return NULL;
19     assert(ct->type == ACT_CA_CRC);
20     assert(ct->el_count >= 1);
21
22     DEBUG("Component Relation Constraint: %s", asn1p_constraint_string(ct));
23
24     assert(ct->elements[0]->type == ACT_EL_VALUE);
25
26     asn1p_value_t *val = ct->elements[0]->value;
27     if(val->type == ATV_VALUESET && val->value.constraint->type == ACT_EL_TYPE) {
28         asn1p_value_t *csub = val->value.constraint->containedSubtype;
29         if(!csub) {
30             /* Ignore */
31         } else if(csub->type == ATV_REFERENCED) {
32             return csub->value.reference;
33         } else if(csub->type == ATV_TYPE) {
34             if(csub->value.v_type->expr_type == A1TC_REFERENCE) {
35                 assert(csub->value.v_type->reference);
36                 return csub->value.v_type->reference;
37             }
38         }
39     }
40     if(val->type != ATV_REFERENCED) {
41         FATAL("Set reference: %s", asn1f_printable_value(val));
42         assert(val->type == ATV_REFERENCED);
43     }
44
45     return val->value.reference;
46 }
47
48 static asn1c_ioc_table_and_objset_t
49 asn1c_get_ioc_table_from_objset(arg_t *arg, const asn1p_ref_t *objset_ref, asn1p_expr_t *objset) {
50     asn1c_ioc_table_and_objset_t ioc_tao = { 0, 0, 1 };
51
52     (void)objset_ref;
53
54     if(objset->ioc_table) {
55         ioc_tao.ioct = objset->ioc_table;
56         ioc_tao.objset = objset;
57         ioc_tao.fatal_error = 0;
58     } else {
59         FATAL("Information Object Set %s contains no objects at line %d",
60               objset->Identifier, objset->_lineno);
61     }
62
63     return ioc_tao;
64 }
65
66 asn1c_ioc_table_and_objset_t
67 asn1c_get_ioc_table(arg_t *arg) {
68     asn1p_expr_t *expr = arg->expr;
69         asn1p_expr_t *memb;
70     asn1p_expr_t *objset = 0;
71     const asn1p_ref_t *objset_ref = NULL;
72     asn1c_ioc_table_and_objset_t safe_ioc_tao = {0, 0, 0};
73     asn1c_ioc_table_and_objset_t failed_ioc_tao = { 0, 0, 1 };
74
75     TQ_FOR(memb, &(expr->members), next) {
76         const asn1p_constraint_t *cr_ct =
77             asn1p_get_component_relation_constraint(memb->constraints);
78         const asn1p_ref_t *tmpref =
79             asn1c_get_information_object_set_reference_from_constraint(arg,
80                                                                        cr_ct);
81         if(tmpref) {
82             if(objset_ref && asn1p_ref_compare(objset_ref, tmpref) != 0) {
83                 FATAL(
84                     "Object set reference on line %d differs from object set "
85                     "reference on line %d",
86                     objset_ref->_lineno, tmpref->_lineno);
87                 return failed_ioc_tao;
88             }
89             objset_ref = tmpref;
90         }
91
92     }
93
94     if(!objset_ref) {
95         return safe_ioc_tao;
96     }
97
98     objset = WITH_MODULE_NAMESPACE(
99         arg->expr->module, expr_ns,
100         asn1f_lookup_symbol_ex(arg->asn, expr_ns, arg->expr, objset_ref));
101     if(!objset) {
102         FATAL("Cannot found %s", asn1p_ref_string(objset_ref));
103         return failed_ioc_tao;
104     }
105
106     return asn1c_get_ioc_table_from_objset(arg, objset_ref, objset);
107 }
108
109 static int
110 emit_ioc_value(arg_t *arg, struct asn1p_ioc_cell_s *cell) {
111
112     if(cell->value && cell->value->meta_type == AMT_VALUE) {
113         const char *prim_type = NULL;
114         int primitive_representation = 0;
115
116         asn1p_expr_t *cv_type =
117             asn1f_find_terminal_type_ex(arg->asn, arg->ns, cell->value);
118
119         switch(cv_type->expr_type) {
120         case ASN_BASIC_INTEGER:
121         case ASN_BASIC_ENUMERATED:
122             switch(asn1c_type_fits_long(arg, cell->value /* sic */)) {
123             case FL_NOTFIT:
124                 GEN_INCLUDE_STD("INTEGER");
125                 prim_type = "INTEGER_t";
126                 break;
127             case FL_PRESUMED:
128             case FL_FITS_SIGNED:
129                 primitive_representation = 1;
130                 prim_type = "long";
131                 break;
132             case FL_FITS_UNSIGN:
133                 prim_type = "unsigned long";
134                 primitive_representation = 1;
135                 break;
136             }
137             break;
138         case ASN_BASIC_OBJECT_IDENTIFIER:
139             prim_type = "OBJECT_IDENTIFIER_t";
140             break;
141         case ASN_BASIC_RELATIVE_OID:
142             prim_type = "RELATIVE_OID_t";
143             break;
144         default: {
145             char *p = strdup(MKID(cell->value));
146             FATAL("Unsupported type %s for value %s",
147                   asn1c_type_name(arg, cell->value, TNF_UNMODIFIED), p);
148             free(p);
149             return -1;
150         }
151         }
152         OUT("static const %s asn_VAL_%d_%s = ", prim_type,
153             cell->value->_type_unique_index, MKID(cell->value));
154
155         asn1p_expr_t *expr_value = cell->value;
156         while(expr_value->value->type == ATV_REFERENCED) {
157             expr_value = WITH_MODULE_NAMESPACE(
158                 expr_value->module, expr_ns,
159                 asn1f_lookup_symbol_ex(arg->asn, expr_ns, expr_value,
160                                        expr_value->value->value.reference));
161             if(!expr_value) {
162                 FATAL("Unrecognized value type for %s", MKID(cell->value));
163                 return -1;
164             }
165         }
166
167         if(!primitive_representation) OUT("{ ");
168
169         switch(expr_value->value->type) {
170         case ATV_INTEGER:
171             if(primitive_representation) {
172                 OUT("%s", asn1p_itoa(expr_value->value->value.v_integer));
173                 break;
174             } else {
175                 asn1c_integer_t v = expr_value->value->value.v_integer;
176                 if(v >= 0) {
177                     if(v <= 127) {
178                         OUT("\"\\x%02x\", 1", (int)v);
179                         break;
180                     } else if(v <= 32767) {
181                         OUT("\"\\x%02x\\x%02x\", 2", (int)(v >> 8), (int)(v & 0xff));
182                         break;
183                     }
184                 }
185                 FATAL("Unsupported value %s range for type %s",
186                       asn1f_printable_value(expr_value->value),
187                       MKID(cell->value));
188                 return -1;
189             }
190         case ATV_UNPARSED:
191             OUT("\"not supported\", 0 };\n");
192             FATAL("Inappropriate value %s for type %s",
193                   asn1f_printable_value(expr_value->value), MKID(cell->value));
194             return 0;   /* TEMPORARY FIXME FIXME */
195         default:
196             FATAL("Inappropriate value %s for type %s",
197                   asn1f_printable_value(expr_value->value), MKID(cell->value));
198             return -1;
199         }
200
201         if(primitive_representation) {
202             OUT(";\n");
203         } else {
204             OUT(" };");
205             OUT(" /* %s */\n", asn1f_printable_value(expr_value->value));
206         }
207     }
208
209     return 0;
210 }
211
212 static int
213 emit_ioc_cell(arg_t *arg, struct asn1p_ioc_cell_s *cell) {
214     OUT("{ \"%s\", ", cell->field->Identifier);
215
216     if(!cell->value) {
217         /* Ignore */
218     } else if(cell->value->meta_type == AMT_VALUE) {
219         GEN_INCLUDE(asn1c_type_name(arg, cell->value, TNF_INCLUDE));
220         OUT("aioc__value, ");
221         OUT("&asn_DEF_%s, ", asn1c_type_name(arg, cell->value, TNF_SAFE));
222         OUT("&asn_VAL_%d_%s", cell->value->_type_unique_index,
223             MKID(cell->value));
224
225     } else if(cell->value->meta_type == AMT_TYPEREF) {
226         GEN_INCLUDE(asn1c_type_name(arg, cell->value, TNF_INCLUDE));
227         OUT("aioc__type, &asn_DEF_%s", MKID(cell->value));
228     } else if(cell->value->meta_type == AMT_TYPE) {
229         GEN_INCLUDE(asn1c_type_name(arg, cell->value, TNF_INCLUDE));
230         OUT("aioc__type, &asn_DEF_%s", asn1c_type_name(arg, cell->value, TNF_SAFE));
231     } else {
232         return -1;
233     }
234
235     OUT(" }");
236
237     return 0;
238 }
239
240 /*
241  * Refer to skeletons/asn_ioc.h
242  */
243 int
244 emit_ioc_table(arg_t *arg, asn1p_expr_t *context, asn1c_ioc_table_and_objset_t ioc_tao) {
245     size_t columns = 0;
246
247     (void)context;
248     GEN_INCLUDE_STD("asn_ioc");
249
250     REDIR(OT_IOC_TABLES);
251
252     /* Emit values that are used in the Information Object Set table first */
253     for(size_t rn = 0; rn < ioc_tao.ioct->rows; rn++) {
254         asn1p_ioc_row_t *row = ioc_tao.ioct->row[rn];
255         for(size_t cn = 0; cn < row->columns; cn++) {
256             if(emit_ioc_value(arg, &row->column[cn])) {
257                 return -1;
258             }
259         }
260     }
261
262     if(ioc_tao.ioct->rows == 0)
263         return 0;
264
265     /* Emit the Information Object Set */
266     OUT("static const asn_ioc_cell_t asn_IOS_%s_%d_rows[] = {\n",
267         MKID(ioc_tao.objset), ioc_tao.objset->_type_unique_index);
268     INDENT(+1);
269
270     for(size_t rn = 0; rn < ioc_tao.ioct->rows; rn++) {
271         asn1p_ioc_row_t *row = ioc_tao.ioct->row[rn];
272         columns = columns ? columns : row->columns;
273         if(columns != row->columns) {
274             FATAL("Information Object Set %s row column mismatch on line %d",
275                   ioc_tao.objset->Identifier, ioc_tao.objset->_lineno);
276             return -1;
277         }
278         for(size_t cn = 0; cn < row->columns; cn++) {
279             if(rn || cn) OUT(",\n");
280             emit_ioc_cell(arg, &row->column[cn]);
281         }
282     }
283     OUT("\n");
284
285     INDENT(-1);
286     OUT("};\n");
287
288     OUT("static const asn_ioc_set_t asn_IOS_%s_%d[] = {\n",
289         MKID(ioc_tao.objset), ioc_tao.objset->_type_unique_index);
290     INDENT(+1);
291     OUT("{ %zu, %zu, asn_IOS_%s_%d_rows }\n", ioc_tao.ioct->rows, columns,
292         MKID(ioc_tao.objset), ioc_tao.objset->_type_unique_index);
293     INDENT(-1);
294     OUT("};\n");
295
296     return 0;
297 }
298