blob: e9d156cec887c31c25482d0930f19e52151c0efd [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
Lev Walkin97bdee22004-06-28 21:21:24 +00002#include "asn1fix.h"
Lev Walkinf15320b2004-06-03 03:38:44 +00003
4char const *
5asn1f_printable_reference(asn1p_ref_t *ref) {
6 if(ref) {
7 asn1p_value_t v;
8
9 v.type = ATV_REFERENCED;
10 v.value.reference = ref;
11
12 return asn1f_printable_value(&v);
13 } else {
14 return "<no ref>";
15 }
16}
17
18char const *
19asn1f_printable_value(asn1p_value_t *v) {
20 static char buf[128];
21 static char *managedptr;
22 static int managedptr_len;
23 int ret;
24
25#define ENSURE(len) do { \
Lev Walkincaaf7a52004-09-15 11:46:28 +000026 int __len = (len); \
27 if(__len >= managedptr_len) { \
Lev Walkinf15320b2004-06-03 03:38:44 +000028 if(managedptr) \
29 free(managedptr); \
Lev Walkincaaf7a52004-09-15 11:46:28 +000030 managedptr = malloc(__len + 1); \
Lev Walkinf15320b2004-06-03 03:38:44 +000031 if(managedptr) { \
Lev Walkincaaf7a52004-09-15 11:46:28 +000032 managedptr_len = __len; \
Lev Walkinf15320b2004-06-03 03:38:44 +000033 } else { \
34 managedptr_len = 0; \
35 return "<memory allocation error>"; \
36 } \
37 } \
38 } while(0)
39
40 if(v == NULL)
41 return "<no value>";
42
43 switch(v->type) {
44 case ATV_NOVALUE:
45 return "<NO VALUE>";
Lev Walkincaaf7a52004-09-15 11:46:28 +000046 case ATV_NULL:
47 return "NULL";
Lev Walkinf15320b2004-06-03 03:38:44 +000048 case ATV_REAL:
49 ret = snprintf(buf, sizeof(buf), "%f", v->value.v_double);
Lev Walkind9bd7752004-06-05 08:17:50 +000050 if(ret >= (ssize_t)sizeof(buf))
Lev Walkinf15320b2004-06-03 03:38:44 +000051 memcpy(buf + sizeof(buf) - 4, "...", 4);
52 return buf;
53 case ATV_INTEGER:
Lev Walkin33c16ba2004-09-24 21:01:43 +000054 ret = snprintf(buf, sizeof(buf), "%" PRIdASN,
55 v->value.v_integer);
Lev Walkind9bd7752004-06-05 08:17:50 +000056 if(ret >= (ssize_t)sizeof(buf))
Lev Walkinf15320b2004-06-03 03:38:44 +000057 memcpy(buf + sizeof(buf) - 4, "...", 4);
58 return buf;
59 case ATV_MIN: return "MIN";
60 case ATV_MAX: return "MAX";
61 case ATV_FALSE: return "FALSE";
62 case ATV_TRUE: return "TRUE";
63 case ATV_STRING:
64 case ATV_UNPARSED:
65 /* Buffer is guaranteed to be null-terminated */
66 assert(v->value.string.buf[v->value.string.size] == '\0');
67 return v->value.string.buf;
68 case ATV_BITVECTOR:
69 {
70 uint8_t *bitvector;
71 char *ptr;
72 int len;
73 int i;
74 /*
75 * Compute number of bytes necessary
76 * to represend the binary value.
77 */
78 int bits = v->value.binary_vector.size_in_bits;
79 len = ((bits%8)?bits:(bits >> 2)) + sizeof("''H");
80 /*
81 * Reallocate managed buffer
82 */
83 ENSURE(len);
84
85 /*
86 * Fill the buffer.
87 */
88 ptr = managedptr;
89 bitvector = v->value.binary_vector.bits;
90 *ptr++ = '\'';
91 if(bits%8) {
92 /*
93 * Dump bit by bit.
94 */
95 for(i = 0; i < bits; i++) {
96 uint8_t uc;
97 uc = bitvector[i>>3];
98 *ptr++ = ((uc >> (7-(i%8)))&1)?'1':'0';
99 }
100 } else {
Lev Walkind9bd7752004-06-05 08:17:50 +0000101 static const char *hextable="0123456789ABCDEF";
Lev Walkinf15320b2004-06-03 03:38:44 +0000102 /*
103 * Dump byte by byte.
104 */
105 for(i = 0; i < (bits >> 3); i++) {
106 *ptr++ = hextable[bitvector[i] >> 4];
107 *ptr++ = hextable[bitvector[i] & 0x0f];
108 }
109 }
110 *ptr++ = '\'';
111 *ptr++ = (bits%8)?'B':'H';
112 *ptr++ = 'H';
113 assert((ptr - managedptr) == len);
114 return managedptr;
115 }
Lev Walkincaaf7a52004-09-15 11:46:28 +0000116 case ATV_REFERENCED:
117 {
118 asn1p_ref_t *ref;
119 char reflen;
120 char *ptr;
121 int i;
122
123 assert(v->value.reference);
124 ref = v->value.reference;
125 reflen = ref->comp_count; /* Number of dots */
126 for(i = 0; i < ref->comp_count; i++)
127 reflen += strlen(ref->components[i].name);
128 /*
129 * Make sure we have a buffer of this size.
130 */
131 ENSURE(reflen);
132
133 /*
134 * Fill-up the buffer.
135 */
136 ptr = managedptr;
137 for(i = 0; i < ref->comp_count; i++) {
138 char *nc;
139 if(i) *ptr++ = '.';
140 for(nc = ref->components[i].name; *nc; nc++)
141 *ptr++ = *nc;
142 }
143 *ptr++ = '\0';
144 assert(reflen == (ptr - managedptr));
145 return managedptr;
146 }
147 case ATV_CHOICE_IDENTIFIER:
148 {
149 char *cid = v->value.choice_identifier.identifier;
150 char const *vptr = asn1f_printable_value(
151 v->value.choice_identifier.value);
152 char *val;
153
154 val = strdup(vptr);
155 if(!val) return "<memory allocation error>";
156
157 ENSURE(strlen(cid) + sizeof(": ") + strlen(val));
158
159 ret = snprintf(managedptr, managedptr_len + 1,
160 "%s: %s", cid, val);
161 assert(ret >= 0 && ret <= managedptr_len);
162 free(val);
163 return managedptr;
164 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000165 }
166
167 return "<some complex value>";
168}
169
170
171/*
172 * Recursively invoke a given function over the given expr and all its
173 * children.
174 */
175int
176asn1f_recurse_expr(arg_t *arg, int (*callback)(arg_t *arg)) {
177 asn1p_expr_t *expr = arg->expr;
178 int rvalue = 0;
179 int ret;
180
181 assert(expr);
182
183 /*
184 * Invoke the callback at this very level.
185 */
186 ret = callback(arg);
187 RET2RVAL(ret, rvalue);
188
189 /*
190 * Recursively invoke myself
191 * to iterate over each element in the tree.
192 */
193 TQ_FOR(arg->expr, &(expr->members), next) {
194 assert(arg->expr->expr_type != A1TC_INVALID);
Lev Walkin1004aa92004-09-08 00:28:11 +0000195 assert(arg->expr->parent_expr == expr);
Lev Walkinf15320b2004-06-03 03:38:44 +0000196 ret = asn1f_recurse_expr(arg, callback);
197 RET2RVAL(ret, rvalue);
198 }
199
200 arg->expr = expr; /* Restore original position */
201
202 return rvalue;
203}
204
205
206/*
207 * Check that every child of a given expr has unique name or does not have any.
208 */
209int
210asn1f_check_unique_expr(arg_t *arg,
211 int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
212 asn1p_expr_t *expr;
213 int rvalue = 0;
214
215 TQ_FOR(expr, &(arg->expr->members), next) {
216 if(expr->Identifier) {
217 int ret = asn1f_check_unique_expr_child(arg, expr,
218 opt_compare);
219 if(ret) rvalue = -1;
220 } else {
221 /*
222 * No point of comparing this child with any other:
223 * this one does not have a name.
224 */
225 }
226 }
227
228 return rvalue;
229}
230
231/*
232 * Check that every preceeding child of the given expr is not
233 * having the name of the given one.
234 */
235int
236asn1f_check_unique_expr_child(arg_t *arg, asn1p_expr_t *child,
237 int (*opt_compare)(asn1p_expr_t *a, asn1p_expr_t *b)) {
238 asn1p_expr_t *expr;
239 int rvalue = 0;
240
241 assert(child);
242 assert(opt_compare || child->Identifier);
243
244 TQ_FOR(expr, &(arg->expr->members), next) {
245 int ret;
246
247 if(expr == child)
248 break;
249
250 /*
251 * Compare according to the custom rule or default
252 * names comparisons.
253 */
254 if(opt_compare) {
255 ret = opt_compare(expr, child);
256 } else {
257 if(expr->Identifier == NULL
258 || expr->expr_type == A1TC_EXTENSIBLE)
259 continue;
260 ret = strcasecmp(expr->Identifier, child->Identifier);
261 }
262
263 if(ret == 0) {
264 char *msg;
265 msg = opt_compare
266 ?"Expressions clash"
267 :"Identifiers name clash";
268 arg->eh(1,
269 "%s: "
270 "\"%s\" at line %d has similar %s with "
271 "\"%s\" at line %d",
272 msg,
273 expr->Identifier,
274 expr->_lineno,
275 opt_compare?"property":"name",
276 child->Identifier,
277 child->_lineno
278 );
279
280 rvalue = -1;
281 }
282 }
283
284 return rvalue;
285}
286
287int
288asn1f_count_children(asn1p_expr_t *expr) {
289 asn1p_expr_t *child;
290 int count = 0;
291
292 TQ_FOR(child, &(expr->members), next) {
293 count++;
294 }
295
296 return count;
297}
298
Lev Walkin97bdee22004-06-28 21:21:24 +0000299
300static char **known_types;
301static int known_types_count;
302static int known_types_size;
303
304static int _known_types_cmp(const void *ap, const void *bp) {
305 const char *a = *(const char * const *)ap;
306 const char *b = *(const char * const *)bp;
307 return strcmp(a, b);
308}
309
310int
311asn1f_make_known_external_type(const char *type_name) {
312 char *tname;
313
314 /* Check for duplicates */
315 if(asn1f_check_known_external_type(type_name) == 0) {
316 errno = EEXIST;
317 return -1;
318 }
319
320 /* Ensure enough space */
321 if(known_types_count <= known_types_size) {
322 int n = known_types_size ? known_types_size << 1 : 4;
323 void *p;
324 p = realloc(known_types, n * sizeof(known_types[0]));
325 if(!p) return -1;
326 known_types = p;
327 known_types_size = n;
328 }
329
330 tname = strdup(type_name);
331 if(!tname) return -1;
332
333 known_types[known_types_count++] = tname;
334
335#ifdef HAVE_MERGESORT
336 mergesort
337#else
338 qsort
339#endif
340 (known_types, known_types_count, sizeof(known_types[0]),
341 _known_types_cmp);
342
343 return 0;
344}
345
346int
347asn1f_check_known_external_type(const char *type_name) {
Lev Walkina460ba32004-10-20 15:40:04 +0000348 if(known_types_count) {
349 void *p = bsearch(&type_name, known_types, known_types_count,
350 sizeof(known_types[0]), _known_types_cmp);
351 if(p) return 0;
352 }
Lev Walkin97bdee22004-06-28 21:21:24 +0000353 errno = ESRCH;
354 return -1;
355}
356