Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <string.h> |
| 4 | #include <errno.h> |
| 5 | #include <assert.h> |
| 6 | |
| 7 | #include "asn1parser.h" |
| 8 | |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 9 | static asn1p_expr_t *asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*)(asn1p_expr_t *, void *), void *); |
| 10 | static asn1p_value_t *value_resolver(asn1p_value_t *, void *arg); |
| 11 | |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 12 | /* |
| 13 | * Construct a new empty types collection. |
| 14 | */ |
| 15 | asn1p_expr_t * |
Lev Walkin | a9532f4 | 2006-09-17 04:52:50 +0000 | [diff] [blame] | 16 | asn1p_expr_new(int _lineno, asn1p_module_t *mod) { |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 17 | asn1p_expr_t *expr; |
| 18 | |
| 19 | expr = calloc(1, sizeof *expr); |
| 20 | if(expr) { |
| 21 | TQ_INIT(&(expr->members)); |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 22 | expr->spec_index = -1; |
Lev Walkin | a9532f4 | 2006-09-17 04:52:50 +0000 | [diff] [blame] | 23 | expr->module = mod; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 24 | expr->_lineno = _lineno; |
Bi-Ruei, Chiu | b9adfc5 | 2016-11-09 00:17:25 +0800 | [diff] [blame] | 25 | expr->ref_cnt = 0; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 26 | } |
| 27 | |
| 28 | return expr; |
| 29 | } |
| 30 | |
| 31 | asn1p_expr_t * |
Lev Walkin | 070a52d | 2004-08-22 03:19:54 +0000 | [diff] [blame] | 32 | asn1p_expr_clone(asn1p_expr_t *expr, int skip_extensions) { |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 33 | return asn1p_expr_clone_impl(expr, skip_extensions, 0, 0); |
| 34 | } |
| 35 | |
| 36 | asn1p_expr_t * |
| 37 | asn1p_expr_clone_with_resolver(asn1p_expr_t *expr, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) { |
| 38 | return asn1p_expr_clone_impl(expr, 0, r, rarg); |
| 39 | } |
| 40 | |
| 41 | static asn1p_expr_t * |
| 42 | asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) { |
| 43 | asn1p_value_t *(*vr)(asn1p_value_t *, void *) = 0; |
| 44 | asn1p_expr_t *clone = 0; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 45 | asn1p_expr_t *tcmemb; /* Child of tc */ |
Lev Walkin | 070a52d | 2004-08-22 03:19:54 +0000 | [diff] [blame] | 46 | int hit_ext = 0; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 47 | |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 48 | #define CLCOPY(field) do { clone->field = expr->field; } while(0) |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 49 | #define CLCLONE(field, func) do { if(expr->field) { \ |
| 50 | clone->field = func(expr->field); \ |
| 51 | if(clone->field == NULL) { \ |
| 52 | asn1p_expr_free(clone); \ |
| 53 | return NULL; \ |
| 54 | } \ |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 55 | } } while(0) |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 56 | #define CLVRCLONE(field, func) do { if(expr->field) { \ |
| 57 | clone->field = func(expr->field, vr, rarg); \ |
| 58 | if(clone->field == NULL) { \ |
| 59 | asn1p_expr_free(clone); \ |
| 60 | return NULL; \ |
| 61 | } \ |
| 62 | } } while(0) |
| 63 | |
| 64 | if(r) { |
| 65 | vr = value_resolver; |
| 66 | clone = r(expr, rarg); |
| 67 | if(clone) { |
| 68 | /* Merge constraints */ |
| 69 | if(expr->constraints) { |
| 70 | asn1p_constraint_t *tmpct = asn1p_constraint_clone_with_resolver(expr->constraints, vr, rarg); |
| 71 | if(clone->constraints) { |
| 72 | if(asn1p_constraint_insert(clone->constraints, tmpct)) { |
| 73 | asn1p_constraint_free(tmpct); |
| 74 | asn1p_expr_free(clone); |
| 75 | return NULL; |
| 76 | } |
| 77 | } else { |
| 78 | clone->constraints = tmpct; |
| 79 | } |
Lev Walkin | 0c0bca6 | 2006-03-21 04:48:15 +0000 | [diff] [blame] | 80 | assert(expr->combined_constraints == 0); |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 81 | } |
Lev Walkin | 0c0bca6 | 2006-03-21 04:48:15 +0000 | [diff] [blame] | 82 | /* Merge defaults */ |
| 83 | CLCOPY(marker.flags); |
| 84 | CLVRCLONE(marker.default_value, |
| 85 | asn1p_value_clone_with_resolver); |
| 86 | if(clone->tag.tag_class == TC_NOCLASS) { |
| 87 | CLCOPY(tag); |
| 88 | } else if(expr->tag.tag_class != TC_NOCLASS) { |
| 89 | fprintf(stderr, "asn1c does not support " |
| 90 | "nested tagging in parameterization, " |
| 91 | "necessary at line %d\n", |
| 92 | expr->_lineno); |
| 93 | asn1p_expr_free(clone); |
| 94 | return NULL; |
| 95 | } |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 96 | return clone; |
| 97 | } else if(errno != ESRCH) { |
| 98 | return NULL; /* Hard error */ |
| 99 | } |
| 100 | } |
Lev Walkin | a9532f4 | 2006-09-17 04:52:50 +0000 | [diff] [blame] | 101 | if(!clone) clone = asn1p_expr_new(expr->_lineno, expr->module); |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 102 | if(!clone) return NULL; |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 103 | |
| 104 | /* |
| 105 | * Copy simple fields. |
| 106 | */ |
| 107 | CLCOPY(meta_type); |
| 108 | CLCOPY(expr_type); |
| 109 | CLCOPY(tag); |
Lev Walkin | 5498f2d | 2004-09-15 11:59:30 +0000 | [diff] [blame] | 110 | CLCOPY(marker.flags); /* OPTIONAL/DEFAULT */ |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 111 | CLCOPY(_mark); |
| 112 | |
| 113 | clone->data = 0; /* Do not clone this */ |
| 114 | clone->data_free = 0; /* Do not clone this */ |
| 115 | |
| 116 | /* |
| 117 | * Clone complex fields. |
| 118 | */ |
| 119 | CLCLONE(Identifier, strdup); |
| 120 | CLCLONE(reference, asn1p_ref_clone); |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 121 | CLVRCLONE(constraints, asn1p_constraint_clone_with_resolver); |
| 122 | CLVRCLONE(combined_constraints, asn1p_constraint_clone_with_resolver); |
| 123 | CLCLONE(lhs_params, asn1p_paramlist_clone); |
| 124 | CLVRCLONE(value, asn1p_value_clone_with_resolver); |
Lev Walkin | 0c0bca6 | 2006-03-21 04:48:15 +0000 | [diff] [blame] | 125 | CLVRCLONE(marker.default_value, asn1p_value_clone_with_resolver); |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 126 | CLCLONE(with_syntax, asn1p_wsyntx_clone); |
| 127 | |
| 128 | /* |
| 129 | * Copy all the children of this expr. |
| 130 | */ |
| 131 | TQ_FOR(tcmemb, &(expr->members), next) { |
Lev Walkin | 070a52d | 2004-08-22 03:19:54 +0000 | [diff] [blame] | 132 | asn1p_expr_t *cmemb; |
| 133 | |
| 134 | if(skip_extensions |
| 135 | && tcmemb->expr_type == A1TC_EXTENSIBLE) { |
| 136 | hit_ext++; /* Even if hit_ext wraps around, we're OK. */ |
| 137 | continue; |
| 138 | } |
| 139 | if(hit_ext == 1) continue; /* Skip between ...'s */ |
| 140 | |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 141 | cmemb = asn1p_expr_clone_impl(tcmemb, skip_extensions, r, rarg); |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 142 | if(cmemb == NULL) { |
| 143 | asn1p_expr_free(clone); |
| 144 | return NULL; |
| 145 | } |
Lev Walkin | 1004aa9 | 2004-09-08 00:28:11 +0000 | [diff] [blame] | 146 | asn1p_expr_add(clone, cmemb); |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | return clone; |
| 150 | } |
| 151 | |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 152 | |
| 153 | static asn1p_value_t * |
| 154 | value_resolver(asn1p_value_t *value, void *rarg) { |
| 155 | asn1p_value_t *cval; |
| 156 | asn1p_expr_t *tmpexpr; |
| 157 | asn1p_expr_t *target; |
| 158 | asn1p_ref_t *ref; |
| 159 | struct { |
| 160 | asn1p_expr_t *(*expr_resolve)(asn1p_expr_t *, void *arg); |
| 161 | } *varg = rarg; |
| 162 | |
| 163 | if(!value || value->type != ATV_REFERENCED) { |
| 164 | errno = ESRCH; |
| 165 | return NULL; |
| 166 | } |
| 167 | |
| 168 | ref = value->value.reference; |
Lev Walkin | a9532f4 | 2006-09-17 04:52:50 +0000 | [diff] [blame] | 169 | tmpexpr = asn1p_expr_new(ref->_lineno, 0); |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 170 | tmpexpr->meta_type = AMT_TYPEREF; |
| 171 | tmpexpr->expr_type = A1TC_REFERENCE; |
| 172 | tmpexpr->reference = ref; |
| 173 | target = varg->expr_resolve(tmpexpr, rarg); |
| 174 | tmpexpr->reference = 0; |
| 175 | asn1p_expr_free(tmpexpr); |
| 176 | |
| 177 | if(!target) |
| 178 | return NULL; /* errno's are compatible */ |
| 179 | |
Lev Walkin | 5045dfa | 2006-03-21 09:41:28 +0000 | [diff] [blame] | 180 | if(target->meta_type == AMT_VALUE) { |
| 181 | if(!target->value) { |
| 182 | fprintf(stderr, |
| 183 | "FATAL: Parameterization did not resolve " |
| 184 | "value reference at line %d\n", ref->_lineno); |
| 185 | asn1p_expr_free(target); |
| 186 | errno = EPERM; |
| 187 | return NULL; |
| 188 | } |
| 189 | cval = asn1p_value_clone(target->value); |
| 190 | } else if(target->meta_type == AMT_VALUESET) { |
| 191 | if(!target->constraints) { |
| 192 | fprintf(stderr, |
| 193 | "FATAL: Parameterization did not resolve " |
| 194 | "value set reference at line %d\n", ref->_lineno); |
| 195 | asn1p_expr_free(target); |
| 196 | errno = EPERM; |
| 197 | return NULL; |
| 198 | } |
| 199 | cval = asn1p_value_fromconstr(target->constraints, 1); |
| 200 | } else { |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 201 | errno = EPERM; |
Lev Walkin | 5045dfa | 2006-03-21 09:41:28 +0000 | [diff] [blame] | 202 | cval = NULL; |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 203 | } |
| 204 | |
Lev Walkin | a00d6b3 | 2006-03-21 03:40:38 +0000 | [diff] [blame] | 205 | asn1p_expr_free(target); |
| 206 | return cval; |
| 207 | } |
| 208 | |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 209 | /* |
Lev Walkin | 1004aa9 | 2004-09-08 00:28:11 +0000 | [diff] [blame] | 210 | * Add expression as a member of another. |
| 211 | */ |
| 212 | void |
| 213 | asn1p_expr_add(asn1p_expr_t *to, asn1p_expr_t *what) { |
| 214 | TQ_ADD(&(to->members), what, next); |
| 215 | what->parent_expr = to; |
| 216 | } |
| 217 | |
Lev Walkin | 0e90aa0 | 2013-03-19 16:17:13 -0700 | [diff] [blame] | 218 | /* |
| 219 | * Add inner expressions as members of another. |
| 220 | */ |
| 221 | void |
| 222 | asn1p_expr_add_many(asn1p_expr_t *to, asn1p_expr_t *from_what) { |
| 223 | asn1p_expr_t *expr; |
| 224 | TQ_FOR(expr, &(from_what->members), next) { |
Bi-Ruei, Chiu | 3dcf05b | 2017-05-04 21:45:05 +0800 | [diff] [blame] | 225 | expr->parent_expr = to; |
| 226 | } |
Lev Walkin | 0e90aa0 | 2013-03-19 16:17:13 -0700 | [diff] [blame] | 227 | TQ_CONCAT(&(to->members), &(from_what->members), next); |
| 228 | } |
| 229 | |
Lev Walkin | 1004aa9 | 2004-09-08 00:28:11 +0000 | [diff] [blame] | 230 | |
| 231 | /* |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 232 | * Destruct the types collection structure. |
| 233 | */ |
| 234 | void |
| 235 | asn1p_expr_free(asn1p_expr_t *expr) { |
| 236 | if(expr) { |
| 237 | asn1p_expr_t *tm; |
| 238 | |
Bi-Ruei, Chiu | b9adfc5 | 2016-11-09 00:17:25 +0800 | [diff] [blame] | 239 | if (expr->ref_cnt) { |
| 240 | /* Decrease reference count only */ |
| 241 | expr->ref_cnt--; |
| 242 | return; |
| 243 | } |
| 244 | |
Lev Walkin | 1004aa9 | 2004-09-08 00:28:11 +0000 | [diff] [blame] | 245 | /* Remove all children */ |
| 246 | while((tm = TQ_REMOVE(&(expr->members), next))) { |
| 247 | if(tm->parent_expr != expr) |
| 248 | printf("<%s:%p !-> %s:%p>\n", |
| 249 | tm->Identifier, tm->parent_expr, |
| 250 | expr->Identifier, expr); |
| 251 | assert(tm->parent_expr == expr); |
| 252 | asn1p_expr_free(tm); |
| 253 | } |
| 254 | |
Lev Walkin | d8b8364 | 2016-03-14 02:00:27 -0700 | [diff] [blame] | 255 | free(expr->Identifier); |
Markus Elfring | 671eb9a | 2016-03-14 17:07:26 +0100 | [diff] [blame] | 256 | asn1p_ref_free(expr->reference); |
| 257 | asn1p_constraint_free(expr->constraints); |
| 258 | asn1p_constraint_free(expr->combined_constraints); |
| 259 | asn1p_paramlist_free(expr->lhs_params); |
Bi-Ruei, Chiu | 3dcf05b | 2017-05-04 21:45:05 +0800 | [diff] [blame] | 260 | asn1p_expr_free(expr->rhs_pspecs); |
Markus Elfring | 671eb9a | 2016-03-14 17:07:26 +0100 | [diff] [blame] | 261 | asn1p_value_free(expr->value); |
| 262 | asn1p_value_free(expr->marker.default_value); |
| 263 | asn1p_wsyntx_free(expr->with_syntax); |
Bi-Ruei, Chiu | 3dcf05b | 2017-05-04 21:45:05 +0800 | [diff] [blame] | 264 | if(expr->specializations.pspec) { |
| 265 | int pspec; |
| 266 | for(pspec = 0; pspec < expr->specializations.pspecs_count; pspec++) { |
| 267 | asn1p_expr_free(expr->specializations.pspec[pspec].rhs_pspecs); |
| 268 | asn1p_expr_free(expr->specializations.pspec[pspec].my_clone); |
| 269 | } |
| 270 | free(expr->specializations.pspec); |
| 271 | } |
| 272 | if(expr->object_class_matrix.row) { |
| 273 | int row; |
| 274 | for(row = 0; row < expr->object_class_matrix.rows; row++) { |
| 275 | asn1p_ioc_row_delete(expr->object_class_matrix.row[row]); |
| 276 | } |
| 277 | free(expr->object_class_matrix.row); |
| 278 | } |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 279 | |
Lev Walkin | f15320b | 2004-06-03 03:38:44 +0000 | [diff] [blame] | 280 | if(expr->data && expr->data_free) |
| 281 | expr->data_free(expr->data); |
| 282 | |
| 283 | memset(expr, 0, sizeof(*expr)); |
| 284 | free(expr); |
| 285 | } |
| 286 | } |
| 287 | |
Lev Walkin | 7116096 | 2005-06-02 05:21:53 +0000 | [diff] [blame] | 288 | |
| 289 | char *asn1p_tag2string(struct asn1p_type_tag_s *tag, char *buf) { |
Lev Walkin | 8f294e0 | 2005-06-06 08:28:58 +0000 | [diff] [blame] | 290 | static char buf_stat[TAG2STRING_BUFFER_SIZE]; |
Lev Walkin | 7116096 | 2005-06-02 05:21:53 +0000 | [diff] [blame] | 291 | char *start; |
| 292 | char *end; |
| 293 | |
| 294 | if(!buf) buf = buf_stat; |
| 295 | start = buf; |
| 296 | end = buf + TAG2STRING_BUFFER_SIZE; |
| 297 | |
| 298 | if(tag->tag_class == TC_NOCLASS) { |
| 299 | *buf = 0; |
| 300 | return buf; |
| 301 | } |
| 302 | |
| 303 | strcpy(buf, "["); |
| 304 | switch(tag->tag_class) { |
| 305 | case TC_NOCLASS: |
| 306 | assert(tag->tag_class != TC_NOCLASS); |
| 307 | break; |
| 308 | case TC_UNIVERSAL: strcat(buf, "UNIVERSAL "); break; |
| 309 | case TC_PRIVATE: strcat(buf, "PRIVATE "); break; |
| 310 | case TC_APPLICATION: strcat(buf, "APPLICATION "); break; |
| 311 | case TC_CONTEXT_SPECIFIC: |
| 312 | break; |
| 313 | } |
| 314 | buf += snprintf(buf + strlen(buf), end - buf, |
| 315 | "%" PRIdASN "]", tag->tag_value); |
Lev Walkin | 8f294e0 | 2005-06-06 08:28:58 +0000 | [diff] [blame] | 316 | assert((unsigned int)(buf - end) > sizeof(" IMPLICIT ")); |
Lev Walkin | 7116096 | 2005-06-02 05:21:53 +0000 | [diff] [blame] | 317 | |
| 318 | switch(tag->tag_mode) { |
| 319 | case TM_DEFAULT: break; |
| 320 | case TM_IMPLICIT: strcat(buf, " IMPLICIT"); break; |
| 321 | case TM_EXPLICIT: strcat(buf, " EXPLICIT"); break; |
| 322 | } |
| 323 | |
| 324 | return start; |
| 325 | } |