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