]>
Commit | Line | Data |
---|---|---|
bac41a7b A |
1 | /* |
2 | * compiler/core/err_chk.c - Check for semantic errors an ASN.1 module | |
3 | * | |
4 | * The following are checked: | |
5 | * | |
6 | * - Components of CHOICE and SET types must have distinct tags. x | |
7 | * | |
8 | * - CHOICE, ANY, and ANY DEFINED BY types cannot be implicitly tagged. x | |
9 | * | |
10 | * - Type and value names within the same scope must be unique. x | |
11 | * | |
12 | * - Field names in a SET, SEQUENCE or CHOICE must be distinct. If | |
13 | * a CHOICE with no field name is embedded in a SET, SEQUENCE or CHOICE, | |
14 | * then the embedded CHOICE's field names must be distinct from its | |
15 | * parents to avoid ambiguity in value notation. x | |
16 | * | |
17 | * - An APPLICATION tag can only be used once per module. x (done in asn1.yacc) | |
18 | * | |
19 | * - Each value in a named bit (BIT STRINGs) or named number x | |
20 | * (INTEGERs and ENUMERATED) list must be different. | |
21 | * | |
22 | * - Each identifier in a named bit or named number list must be different. x | |
23 | * | |
24 | * - The tags on a series of one or more consecutive OPTIONAL or DEFAULT | |
25 | * SEQUENCE elements and the following element must be distinct. x | |
26 | * | |
27 | * link_types.c does the following three checks | |
28 | * A COMPONENTS OF type in a SET must reference a SET | |
29 | * A COMPONENTS OF type in a SEQUENCE must reference a SEQUENCE | |
30 | * SELECTION types must reference a field of a CHOICE type. | |
31 | * | |
32 | * - gives a warning if an ANY DEFINED BY type appears in a SET or | |
33 | * if and ANY DEFINED BY appears in a SEQUENCE before its identifier. | |
34 | * these cases make decoding difficult. | |
35 | * | |
36 | * ******* following are not done yet - need improved value proc. first***** | |
37 | * | |
38 | * - Each identifier in a BIT STRING value must from that BIT | |
39 | * STRING's named bit list. | |
40 | * | |
41 | * - SET or SEQUENCE values can be empty {} only if the SET or | |
42 | * SEQUENCE type was defined as empty or all of its elements are marked | |
43 | * as OPTIONAL or DEFAULT. | |
44 | * | |
45 | * Mike Sample | |
46 | * 92/07/13 | |
47 | * | |
48 | * Copyright (C) 1991, 1992 Michael Sample | |
49 | * and the University of British Columbia | |
50 | * | |
51 | * This program is free software; you can redistribute it and/or modify | |
52 | * it under the terms of the GNU General Public License as published by | |
53 | * the Free Software Foundation; either version 2 of the License, or | |
54 | * (at your option) any later version. | |
55 | * | |
5a719ac8 | 56 | * $Header: /cvs/Darwin/src/live/Security/SecuritySNACCRuntime/compiler/core/err-chk.c,v 1.1 2001/06/20 21:27:56 dmitch Exp $ |
bac41a7b A |
57 | * $Log: err-chk.c,v $ |
58 | * Revision 1.1 2001/06/20 21:27:56 dmitch | |
59 | * Adding missing snacc compiler files. | |
60 | * | |
61 | * Revision 1.1.1.1 1999/03/16 18:06:47 aram | |
62 | * Originals from SMIME Free Library. | |
63 | * | |
64 | * Revision 1.4 1997/09/01 14:19:43 wan | |
65 | * Improved error output in certain cases. | |
66 | * | |
67 | * Revision 1.3 1995/07/25 19:41:25 rj | |
68 | * changed `_' to `-' in file names. | |
69 | * | |
70 | * Revision 1.2 1994/09/01 00:33:02 rj | |
71 | * snacc_config.h removed; err_chk.h includet. | |
72 | * | |
73 | * Revision 1.1 1994/08/28 09:49:05 rj | |
74 | * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog. | |
75 | * | |
76 | */ | |
77 | ||
78 | #include <ctype.h> | |
79 | #include <stdio.h> | |
80 | ||
81 | #include "asn-incl.h" | |
82 | #include "mem.h" | |
83 | #include "asn1module.h" | |
84 | #include "snacc-util.h" | |
85 | #include "tag-util.h" | |
86 | #include "define.h" | |
87 | #include "err-chk.h" | |
88 | ||
89 | typedef struct DefinedTag | |
90 | { | |
91 | Tag *tag; | |
92 | struct DefinedTag *next; | |
93 | } DefinedTag; | |
94 | ||
95 | ||
96 | typedef struct DefinedName | |
97 | { | |
98 | char *name; | |
99 | struct DefinedName *next; | |
100 | } DefinedName; | |
101 | ||
102 | ||
103 | static NamedType *badNamedType; | |
104 | static DefinedName *fieldNames = NULL; | |
105 | ||
106 | ||
107 | void ErrChkTypeDef PROTO ((Module *m, TypeDef *td)); | |
108 | ||
109 | void ErrChkType PROTO ((Module *m, TypeDef *td, Type *parent, NamedType *nt, Type *t)); | |
110 | ||
111 | void ErrChkElmtTypes PROTO ((Module *m, TypeDef *td, Type *parent, NamedTypeList *e)); | |
112 | ||
113 | void ErrChkBasicType PROTO ((Module *m, TypeDef *td, Type *parent, NamedType *nt, Type *type)); | |
114 | ||
115 | void ErrChkValueDef PROTO ((Module *m, ValueDef *vd)); | |
116 | ||
117 | void ErrChkValue PROTO ((Module *m, ValueDef *vd, Value *v)); | |
118 | ||
119 | int HasDistinctTags PROTO ((NamedTypeList *elmts)); | |
120 | ||
121 | int AddFirstTag PROTO ((DefinedObj **definedTags, Type *t)); | |
122 | ||
123 | void ChkFieldNames PROTO ((Module *m, TypeDef *td, Type *parent, NamedTypeList *elmts)); | |
124 | ||
125 | void ChkNamedNumbers PROTO ((Module *m, Type *t, NamedNumberList *n)); | |
126 | ||
127 | void ChkNamedBits PROTO ((Module *m, Type *t, NamedNumberList *n)); | |
128 | ||
129 | void ChkSeqTags PROTO ((Module *m, TypeDef *td, Type *t)); | |
130 | ||
131 | ||
132 | /* return TRUE if the Tag *t1 and t2 are the same in class and code */ | |
133 | int | |
134 | TagObjCmp PARAMS ((t1, t2), | |
135 | void *t1 _AND_ | |
136 | void *t2) | |
137 | { | |
138 | return (((Tag*) t1)->tclass == ((Tag*) t2)->tclass) && | |
139 | (((Tag*) t1)->code == ((Tag*) t2)->code); | |
140 | } | |
141 | ||
142 | ||
143 | /* | |
144 | * Checks for errors listed above. | |
145 | * sets module status to MOD_ERROR if any errors occured | |
146 | */ | |
147 | void | |
148 | ErrChkModule PARAMS ((m), | |
149 | Module *m) | |
150 | { | |
151 | TypeDef *td; | |
152 | ValueDef *vd; | |
153 | DefinedObj *typeNames; | |
154 | DefinedObj *valueNames; | |
155 | ImportModule *impList; | |
156 | ImportElmt *impElmt; | |
157 | ||
158 | /* | |
159 | * go through each type in typeList | |
160 | */ | |
161 | typeNames = NewObjList(); | |
162 | FOR_EACH_LIST_ELMT (td, m->typeDefs) | |
163 | { | |
164 | /* first check for name conflicts */ | |
165 | if (ObjIsDefined (typeNames, td->definedName, StrObjCmp)) | |
166 | { | |
167 | PrintErrLoc (m->asn1SrcFileName, td->type->lineNo); | |
168 | fprintf (stderr,"ERROR - type \"%s\" is multiply defined.\n", td->definedName); | |
169 | m->status = MOD_ERROR; | |
170 | } | |
171 | else | |
172 | DefineObj (&typeNames, td->definedName); | |
173 | ||
174 | /* now check type def internals */ | |
175 | ErrChkTypeDef (m, td); | |
176 | } | |
177 | ||
178 | /* now check for name conflicts with imported types */ | |
179 | FOR_EACH_LIST_ELMT (impList, m->imports) | |
180 | { | |
181 | FOR_EACH_LIST_ELMT (impElmt, impList->importElmts) | |
182 | { | |
183 | if ((!impElmt->privateScope) && (isupper (impElmt->name[0]))) | |
184 | { | |
185 | if (ObjIsDefined (typeNames, impElmt->name, StrObjCmp)) | |
186 | { | |
187 | PrintErrLoc (m->asn1SrcFileName, impElmt->lineNo); | |
188 | fprintf (stderr,"ERROR - type \"%s\" is multiply defined.\n", impElmt->name); | |
189 | m->status = MOD_ERROR; | |
190 | } | |
191 | else | |
192 | DefineObj (&typeNames, impElmt->name); | |
193 | } | |
194 | } | |
195 | } | |
196 | FreeDefinedObjs (&typeNames); | |
197 | ||
198 | ||
199 | /* | |
200 | * go through each value for types | |
201 | */ | |
202 | valueNames = NewObjList(); | |
203 | FOR_EACH_LIST_ELMT (vd, m->valueDefs) | |
204 | { | |
205 | /* check for name conflict */ | |
206 | if (ObjIsDefined (valueNames, vd->definedName, StrObjCmp)) | |
207 | { | |
208 | PrintErrLoc (m->asn1SrcFileName, vd->value->lineNo); | |
209 | fprintf (stderr,"ERROR - value \"%s\" is multiply defined.\n", vd->definedName); | |
210 | m->status = MOD_ERROR; | |
211 | } | |
212 | else | |
213 | DefineObj (&valueNames, vd->definedName); | |
214 | ||
215 | /* check value internal info */ | |
216 | ErrChkValueDef (m, vd); | |
217 | } | |
218 | /* now check for name conflicts with imported values */ | |
219 | FOR_EACH_LIST_ELMT (impList, m->imports) | |
220 | { | |
221 | FOR_EACH_LIST_ELMT (impElmt, impList->importElmts) | |
222 | { | |
223 | if ((!impElmt->privateScope) && (islower (impElmt->name[0]))) | |
224 | { | |
225 | if (ObjIsDefined (valueNames, impElmt->name, StrObjCmp)) | |
226 | { | |
227 | PrintErrLoc (m->asn1SrcFileName, impElmt->lineNo); | |
228 | fprintf (stderr,"ERROR - value \"%s\" is multiply defined.\n", vd->definedName); | |
229 | m->status = MOD_ERROR; | |
230 | } | |
231 | else | |
232 | DefineObj (&valueNames, impElmt->name); | |
233 | } | |
234 | } | |
235 | } | |
236 | ||
237 | ||
238 | FreeDefinedObjs (&valueNames); | |
239 | ||
240 | } /* ErrChkModule */ | |
241 | ||
242 | ||
243 | ||
244 | void | |
245 | ErrChkTypeDef PARAMS ((m, td), | |
246 | Module *m _AND_ | |
247 | TypeDef *td) | |
248 | { | |
249 | if (td == NULL) | |
250 | return; | |
251 | ||
252 | ErrChkType (m, td, NULL, NULL, td->type); | |
253 | ||
254 | } /* ErrChkTypeDef */ | |
255 | ||
256 | ||
257 | ||
258 | void | |
259 | ErrChkType PARAMS ((m, td, parent, nt, t), | |
260 | Module *m _AND_ | |
261 | TypeDef *td _AND_ | |
262 | Type *parent _AND_ | |
263 | NamedType *nt _AND_ | |
264 | Type *t) | |
265 | { | |
266 | if (t == NULL) | |
267 | return; | |
268 | ||
269 | ErrChkBasicType (m, td, parent, nt, t); | |
270 | ||
271 | } /* ErrChkType */ | |
272 | ||
273 | ||
274 | ||
275 | void | |
276 | ErrChkElmtTypes PARAMS ((m, td, parent, e), | |
277 | Module *m _AND_ | |
278 | TypeDef *td _AND_ | |
279 | Type *parent _AND_ | |
280 | NamedTypeList *e) | |
281 | { | |
282 | NamedType *nt; | |
283 | ||
284 | /* | |
285 | * if starting new type aggregate type, | |
286 | * check that the field names are distinct | |
287 | * (goes 'through' un-named elements that are CHOICEs) | |
288 | */ | |
289 | if (td->type == parent) | |
290 | { | |
291 | ChkFieldNames (m, td, parent, e); | |
292 | } | |
293 | ||
294 | ||
295 | FOR_EACH_LIST_ELMT (nt, e) | |
296 | { | |
297 | ErrChkType (m, td, parent, nt, nt->type); | |
298 | } | |
299 | } /* ErrChkElmtTypes */ | |
300 | ||
301 | ||
302 | ||
303 | void | |
304 | ErrChkBasicType PARAMS ((m, td, parent, tnt, type), | |
305 | Module *m _AND_ | |
306 | TypeDef *td _AND_ | |
307 | Type *parent _AND_ | |
308 | NamedType *tnt _AND_ | |
309 | Type *type) | |
310 | { | |
311 | int i, numElmtsAdded; | |
312 | NamedType *newElmt; | |
313 | NamedType **newElmtHndl; | |
314 | NamedType *nt; | |
315 | NamedTypeList *elmts; | |
316 | NamedType *origNext; | |
317 | Type *refdType; | |
318 | enum BasicTypeChoiceId refdTypeId; | |
319 | TypeDef *newDef; | |
320 | ||
321 | if ((type == NULL) || (type->basicType == NULL)) | |
322 | return; | |
323 | ||
324 | switch (type->basicType->choiceId) | |
325 | { | |
326 | case BASICTYPE_LOCALTYPEREF: | |
327 | case BASICTYPE_IMPORTTYPEREF: | |
328 | /* | |
329 | * make sure that untagged CHOICE and ANY types | |
330 | * are not implicitly tagged | |
331 | */ | |
332 | refdTypeId = ParanoidGetBuiltinType (type); | |
333 | if ((type->implicit) && | |
334 | ((refdTypeId == BASICTYPE_CHOICE) || | |
335 | (refdTypeId == BASICTYPE_ANY) || | |
336 | (refdTypeId == BASICTYPE_ANYDEFINEDBY)) && | |
337 | (CountTags (type->basicType->a.localTypeRef->link->type) == 0)) | |
338 | { | |
339 | m->status = MOD_ERROR; | |
340 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
341 | fprintf (stderr,"ERROR - IMPLICITLY tagged CHOICE, ANY or ANY DEFINED BY type.\n"); | |
342 | } | |
343 | ||
344 | if ((parent != NULL) && | |
345 | ((refdTypeId == BASICTYPE_ANY) || | |
346 | (refdTypeId == BASICTYPE_ANYDEFINEDBY))) | |
347 | { | |
348 | ||
349 | /* | |
350 | * give a warning. It is stupid to have an ANY DEFINED | |
351 | * BY type in a SET since they are not ordered and hence | |
352 | * the ANY DEFINED BY type may need to be decoded before | |
353 | * its identifer which is very difficult | |
354 | */ | |
355 | if ((refdTypeId == BASICTYPE_ANYDEFINEDBY) && | |
356 | (parent->basicType->choiceId == BASICTYPE_SET)) | |
357 | { | |
358 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
359 | fprintf (stderr,"WARNING - ANY DEFINED BY in a SET needs to be decoded before its identifier. This is not guaranteed since SETs are not ordered. Use a SEQUENCE instead, if possible.\n"); | |
360 | } | |
361 | ||
362 | /* | |
363 | * give a warning. It is stupid to have an ANY DEFINED | |
364 | * BY type in a SEQUENCE before its identifier. | |
365 | * The ANY DEFINED BY type will need to be decoded before | |
366 | * its identifer which is very difficult. | |
367 | * tnt is the NamedType holding "type" | |
368 | */ | |
369 | if ((refdTypeId == BASICTYPE_ANYDEFINEDBY) && (tnt != NULL) && | |
370 | (parent->basicType->choiceId == BASICTYPE_SEQUENCE) && | |
371 | (GetAsnListElmtIndex (tnt, parent->basicType->a.sequence) < | |
372 | GetAsnListElmtIndex (type->basicType->a.anyDefinedBy->link, parent->basicType->a.sequence))) | |
373 | { | |
374 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
375 | fprintf (stderr,"WARNING - ANY DEFINED BY in SEQUENCE should appear before its identifier since the identifier must be decoded before the ANY DEFINED BY type.\n"); | |
376 | } | |
377 | ||
378 | ||
379 | if (parent->basicType->choiceId == BASICTYPE_SEQUENCE) | |
380 | nt = LAST_LIST_ELMT (parent->basicType->a.sequence); | |
381 | ||
382 | /* | |
383 | * untagged, optional ANYs are strange and will cause faulty | |
384 | * decoding code to be generated unless they are the last | |
385 | * elmt in a SEQUENCE. | |
386 | * (if they are the last elmt it is easy to check | |
387 | * for the presence of the ANY if definite lengths are used) | |
388 | * (must peek ahead for EOC otherwise) | |
389 | */ | |
390 | if (!((parent->basicType->choiceId == BASICTYPE_SEQUENCE) && | |
391 | (type == nt->type)) && | |
392 | (type->optional) && (CountTags (type) == 0)) | |
393 | { | |
394 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
395 | fprintf (stderr,"WARNING - untagged optional ANY encountered, the produced code will be wrong.\n"); | |
396 | } | |
397 | ||
398 | /* | |
399 | * if parent is SET or CHOICE then ANY or ANY DEFINED BY | |
400 | * should be tagged to help determine its presence | |
401 | * | |
402 | * NOTE: there are also probs with untagged ANYs in SEQs | |
403 | * where the ANY is preceeded by optional elmts | |
404 | * (err msg written in produced code) | |
405 | */ | |
406 | if (((parent->basicType->choiceId == BASICTYPE_SET) || | |
407 | (parent->basicType->choiceId == BASICTYPE_CHOICE)) && | |
408 | (CountTags == 0)) | |
409 | { | |
410 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
411 | fprintf (stderr,"WARNING - untagged ANY in a SET or CHOICE, the produced code will be wrong.\n"); | |
412 | } | |
413 | } | |
414 | ||
415 | break; | |
416 | ||
417 | ||
418 | case BASICTYPE_INTEGER: | |
419 | case BASICTYPE_ENUMERATED: | |
420 | ChkNamedNumbers (m, type, type->basicType->a.integer); | |
421 | break; | |
422 | ||
423 | case BASICTYPE_BITSTRING: | |
424 | ChkNamedBits (m, type, type->basicType->a.bitString); | |
425 | break; | |
426 | ||
427 | ||
428 | case BASICTYPE_SEQUENCEOF: | |
429 | case BASICTYPE_SETOF: | |
430 | ErrChkType (m, td, type, NULL, type->basicType->a.setOf); | |
431 | break; | |
432 | ||
433 | case BASICTYPE_SEQUENCE: | |
434 | ErrChkElmtTypes (m, td, type, type->basicType->a.sequence); | |
435 | ||
436 | /* | |
437 | * check that tags on one or more consecutive optional elmts | |
438 | * and following (if any) non-optional elmt are distinct | |
439 | */ | |
440 | ChkSeqTags (m, td, type); | |
441 | break; | |
442 | ||
443 | ||
444 | case BASICTYPE_CHOICE: | |
445 | /* CHOICE elements must have distinct tags */ | |
446 | if (!HasDistinctTags (type->basicType->a.choice)) | |
447 | { | |
448 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
449 | fprintf (stderr,"ERROR - tag conflict among "); | |
450 | PrintType (stderr, NULL, badNamedType->type); | |
451 | fprintf (stderr," and the other CHOICE elements.\n"); | |
452 | m->status = MOD_ERROR; | |
453 | } | |
454 | ||
455 | /* | |
456 | * untagged choices cannot be implicitily tagged | |
457 | * (this would make it impossible/difficult to figure out which | |
458 | * elmt of the choice was present when decoding) | |
459 | */ | |
460 | if (((type->tags == NULL) || LIST_EMPTY (type->tags)) && | |
461 | (type->implicit)) | |
462 | { | |
463 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
464 | fprintf (stderr,"ERROR - IMPLICITLy tagged CHOICE type.\n"); | |
465 | m->status = MOD_ERROR; | |
466 | } | |
467 | ||
468 | /* Check out each of the components */ | |
469 | ErrChkElmtTypes (m, td, type, type->basicType->a.choice); | |
470 | ||
471 | ||
472 | break; | |
473 | ||
474 | case BASICTYPE_ANYDEFINEDBY: | |
475 | /* for ANY DEFINED BY make sure id field is int or oid */ | |
476 | refdType = GetType (type->basicType->a.anyDefinedBy->link->type); | |
477 | if ((refdType->basicType->choiceId != BASICTYPE_INTEGER) && | |
478 | (refdType->basicType->choiceId != BASICTYPE_ENUMERATED) && | |
479 | (refdType->basicType->choiceId != BASICTYPE_OID)) | |
480 | { | |
481 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
482 | fprintf (stderr,"ERROR - Field referenced by ANY DEFINED BY type must be of INTEGER or OBJECT IDENTIFIER type.\n"); | |
483 | m->status = MOD_ERROR; | |
484 | } | |
485 | ||
486 | /* make sure id field is not optional */ | |
487 | if (type->basicType->a.anyDefinedBy->link->type->optional) | |
488 | { | |
489 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
490 | fprintf (stderr,"ERROR - Field referenced by ANY DEFINED BY cannot be optional.\n"); | |
491 | m->status = MOD_ERROR; | |
492 | } | |
493 | ||
494 | /* | |
495 | * give a warning. It is stupid to have an ANY DEFINED | |
496 | * BY type in a SET since they are not ordered and hence | |
497 | * the ANY DEFINED BY type may need to be decoded before | |
498 | * its identifer which is very difficult | |
499 | */ | |
500 | if ((parent != NULL) && | |
501 | (parent->basicType->choiceId == BASICTYPE_SET)) | |
502 | { | |
503 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
504 | fprintf (stderr,"WARNING - ANY DEFINED BY in a SET needs to be decoded before its identifier. This is not guaranteed since SETs are not ordered. Use a SEQUENCE instead, if possible.\n"); | |
505 | } | |
506 | ||
507 | /* | |
508 | * give a warning. It is stupid to have an ANY DEFINED | |
509 | * BY type in a SEQUENCE before its identifier. | |
510 | * The ANY DEFINED BY type will need to be decoded before | |
511 | * its identifer which is very difficult. | |
512 | * tnt is the NamedType holding "type" | |
513 | */ | |
514 | if ((parent != NULL) && (tnt != NULL) && | |
515 | (parent->basicType->choiceId == BASICTYPE_SEQUENCE) && | |
516 | (GetAsnListElmtIndex (tnt, parent->basicType->a.sequence) < | |
517 | GetAsnListElmtIndex (type->basicType->a.anyDefinedBy->link, parent->basicType->a.sequence))) | |
518 | { | |
519 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
520 | fprintf (stderr,"WARNING - ANY DEFINED BY in SEQUENCE should appear before its identifier since the identifier must be decoded before the ANY DEFINED BY type.\n"); | |
521 | } | |
522 | ||
523 | ||
524 | /* fall through - arrrrrg! */ | |
525 | ||
526 | ||
527 | case BASICTYPE_ANY: | |
528 | /* ANY cannot be implicitily tagged */ | |
529 | if (((type->tags == NULL) || LIST_EMPTY (type->tags)) && | |
530 | (type->implicit)) | |
531 | { | |
532 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
533 | fprintf (stderr,"ERROR - IMPLICITLy tagged ANY type.\n"); | |
534 | m->status = MOD_ERROR; | |
535 | } | |
536 | ||
537 | ||
538 | if (parent != NULL) | |
539 | { | |
540 | if (parent->basicType->choiceId == BASICTYPE_SEQUENCE) | |
541 | nt = LAST_LIST_ELMT (parent->basicType->a.sequence); | |
542 | ||
543 | /* | |
544 | * untagged, optional ANYs are strange and will cause faulty | |
545 | * decoding code to be generated unless they are the last | |
546 | * elmt in a SEQUENCE | |
547 | */ | |
548 | if (!((parent->basicType->choiceId == BASICTYPE_SEQUENCE) && | |
549 | (type == nt->type)) && | |
550 | (type->optional) && (CountTags (type) == 0)) | |
551 | { | |
552 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
553 | fprintf (stderr,"WARNING - untagged optional ANY encountered, the produced code will be wrong.\n"); | |
554 | } | |
555 | ||
556 | /* | |
557 | * if parent is SET or CHOICE then ANY or ANY DEFINED BY | |
558 | * should be tagged to help determine its presence | |
559 | * | |
560 | * NOTE: there are also probs with untagged ANYs in SEQs | |
561 | * where the ANY is preceeded by optional elmts | |
562 | * (err msg written in produced code) | |
563 | */ | |
564 | if (((parent->basicType->choiceId == BASICTYPE_SET) || | |
565 | (parent->basicType->choiceId == BASICTYPE_CHOICE)) && | |
566 | (CountTags (type) == 0)) | |
567 | { | |
568 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
569 | fprintf (stderr,"WARNING - untagged ANY in a SET or CHOICE, the produced code will be wrong.\n"); | |
570 | } | |
571 | } | |
572 | ||
573 | ||
574 | break; | |
575 | ||
576 | ||
577 | ||
578 | case BASICTYPE_SET: | |
579 | /* SET elements must have distinct tags */ | |
580 | if (!HasDistinctTags (type->basicType->a.set)) | |
581 | { | |
582 | PrintErrLoc (m->asn1SrcFileName, type->lineNo); | |
583 | fprintf (stderr,"ERROR - tag conflict among "); | |
584 | PrintType (stderr, NULL, badNamedType->type); | |
585 | fprintf (stderr," and the other SET elements.\n"); | |
586 | m->status = MOD_ERROR; | |
587 | } | |
588 | ||
589 | /* Check out each of the components */ | |
590 | ErrChkElmtTypes (m, td, type, type->basicType->a.set); | |
591 | break; | |
592 | ||
593 | ||
594 | default: | |
595 | /* the rest do not need checking */ | |
596 | break; | |
597 | } | |
598 | } /* ErrChkBasicType */ | |
599 | ||
600 | ||
601 | void | |
602 | ErrChkValueDef PARAMS ((m, vd), | |
603 | Module *m _AND_ | |
604 | ValueDef *vd) | |
605 | { | |
606 | ErrChkValue (m, vd, vd->value); | |
607 | } | |
608 | ||
609 | void | |
610 | ErrChkValue PARAMS ((m, vd, v), | |
611 | Module *m _AND_ | |
612 | ValueDef *vd _AND_ | |
613 | Value *v) | |
614 | { | |
615 | } | |
616 | ||
617 | ||
618 | /* | |
619 | * returns non-zero if the first tags on the elements | |
620 | * are all different. Otherwise 0 is returned | |
621 | * | |
622 | * algorithm: add each tag to a list, adding only if | |
623 | * not already in list. if there, free list | |
624 | * and return FALSE. if finished adding tags | |
625 | * and no duplicates occurred then return TRUE; | |
626 | */ | |
627 | int | |
628 | HasDistinctTags PARAMS ((elmts), | |
629 | NamedTypeList *elmts) | |
630 | { | |
631 | DefinedObj *tL; | |
632 | NamedType *e; | |
633 | ||
634 | tL = NewObjList(); | |
635 | FOR_EACH_LIST_ELMT (e, elmts) | |
636 | { | |
637 | if (!AddFirstTag (&tL, e->type)) | |
638 | { | |
639 | FreeDefinedObjs (&tL); | |
640 | badNamedType = e; | |
641 | return FALSE; | |
642 | } | |
643 | } | |
644 | FreeDefinedObjs (&tL); | |
645 | badNamedType = NULL; | |
646 | return TRUE; | |
647 | } /* HasDistinctTags */ | |
648 | ||
649 | ||
650 | /* | |
651 | * puts first tag of the given type into the defined tags list | |
652 | * returns FALSE if the tag was already in the defined tags list. | |
653 | * return TRUE otherwise | |
654 | */ | |
655 | int | |
656 | AddFirstTag PARAMS ((definedTags, t), | |
657 | DefinedObj **definedTags _AND_ | |
658 | Type *t) | |
659 | { | |
660 | Tag *tag; | |
661 | TagList *tl; | |
662 | Tag *last; | |
663 | int implicitRef; | |
664 | NamedType *e; | |
665 | ||
666 | tl = t->tags; | |
667 | if (tl != NULL) | |
668 | AsnListFirst (tl); | |
669 | ||
670 | implicitRef = FALSE; | |
671 | ||
672 | for (;;) | |
673 | { | |
674 | /* | |
675 | * get first tag from tag list local to this type if any | |
676 | */ | |
677 | ||
678 | if ((tl != NULL) && (CURR_LIST_NODE (tl) != NULL) && | |
679 | (CURR_LIST_ELMT (tl) != NULL)) | |
680 | { | |
681 | tag = (Tag*) CURR_LIST_ELMT (tl); | |
682 | ||
683 | if (ObjIsDefined (*definedTags, tag, TagObjCmp)) | |
684 | return FALSE; | |
685 | else | |
686 | { | |
687 | DefineObj (definedTags, tag); | |
688 | return TRUE; | |
689 | } | |
690 | } | |
691 | ||
692 | /* | |
693 | * follow tags of referenced types if no tags on this type | |
694 | */ | |
695 | ||
696 | if ((t->basicType->choiceId == BASICTYPE_LOCALTYPEREF) || | |
697 | (t->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) | |
698 | { | |
699 | if (!implicitRef) | |
700 | implicitRef = t->implicit; | |
701 | ||
702 | ||
703 | if (t->basicType->a.localTypeRef->link == NULL) | |
704 | { | |
705 | /* this should be found in the type link stage */ | |
706 | fprintf (stderr,"ERROR - unresolved type ref, cannot get tags for decoding\n"); | |
707 | break; | |
708 | } | |
709 | t = t->basicType->a.localTypeRef->link->type; | |
710 | tl = t->tags; | |
711 | ||
712 | if (tl != NULL) | |
713 | { | |
714 | AsnListFirst (tl); /* set curr ptr to first node */ | |
715 | if ((!LIST_EMPTY (tl)) && implicitRef) | |
716 | { | |
717 | AsnListNext (tl); | |
718 | implicitRef = FALSE; | |
719 | } | |
720 | } | |
721 | ||
722 | } | |
723 | ||
724 | /* | |
725 | * if untagged choice and no tags found yet | |
726 | */ | |
727 | else if ((t->basicType->choiceId == BASICTYPE_CHOICE)) | |
728 | { | |
729 | /* | |
730 | * add top level tags from each choice elmt | |
731 | */ | |
732 | if (implicitRef) | |
733 | { | |
734 | fprintf (stderr,"ERROR - IMPLICITLY Tagged CHOICE\n"); | |
735 | } | |
736 | ||
737 | ||
738 | FOR_EACH_LIST_ELMT (e, t->basicType->a.choice) | |
739 | { | |
740 | if (!AddFirstTag (definedTags, e->type)) | |
741 | return FALSE; | |
742 | } | |
743 | ||
744 | return TRUE; | |
745 | } | |
746 | ||
747 | else /* could be ANY type - assume correct tagging */ | |
748 | return TRUE; | |
749 | ||
750 | } | |
751 | ||
752 | } /* AddFirstTag */ | |
753 | ||
754 | ||
755 | ||
756 | ||
757 | /* | |
758 | * Prints Errors if the field names of the elements are | |
759 | * not distinct. | |
760 | * currently an endless recursion problem here | |
761 | * for recursive types involving CHOICEs - Fixed MS | |
762 | */ | |
763 | void | |
764 | ChkFieldNamesRec PARAMS ((m, td, parent, elmts, fieldNames, followedTypeRefs), | |
765 | Module *m _AND_ | |
766 | TypeDef *td _AND_ | |
767 | Type *parent _AND_ | |
768 | NamedTypeList *elmts _AND_ | |
769 | DefinedObj **fieldNames _AND_ | |
770 | DefinedObj **followedTypeRefs) | |
771 | { | |
772 | NamedType *e; | |
773 | Type *definingType; | |
774 | ||
775 | FOR_EACH_LIST_ELMT (e, elmts) | |
776 | { | |
777 | definingType = ParanoidGetType (e->type); | |
778 | if (e->fieldName != NULL) | |
779 | { | |
780 | if (ObjIsDefined (*fieldNames, e->fieldName, StrObjCmp)) | |
781 | { | |
782 | if (parent->basicType->a.choice == elmts) | |
783 | { | |
784 | PrintErrLoc (m->asn1SrcFileName, e->type->lineNo); | |
785 | fprintf (stderr,"WARNING - field name \"%s\" is used more than once in same value notation scope.\n", e->fieldName); | |
786 | } | |
787 | else | |
788 | { | |
789 | PrintErrLoc (m->asn1SrcFileName, parent->lineNo); | |
790 | fprintf (stderr,"WARNING - field name \"%s\" in embedded CHOICE conflicts with field name in type \"%s\".", e->fieldName, td->definedName); | |
791 | fprintf (stderr," This may lead to ambiguous value notation.\n"); | |
792 | } | |
793 | /* m->status = MOD_ERROR; */ | |
794 | } | |
795 | else | |
796 | DefineObj (fieldNames, e->fieldName); | |
797 | } | |
798 | ||
799 | /* | |
800 | * must include embedded CHOICE's field names | |
801 | * if it has no field name (this case is a reference to | |
802 | * a CHOICE) (fieldName is NULL) | |
803 | */ | |
804 | else if (((e->type->basicType->choiceId == BASICTYPE_LOCALTYPEREF) || | |
805 | (e->type->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) && | |
806 | (definingType->basicType->choiceId == BASICTYPE_CHOICE)) | |
807 | { | |
808 | /* stop if this is a recursive ref we have already checked */ | |
809 | if (!ObjIsDefined (*followedTypeRefs, e->type->basicType->a.localTypeRef->typeName, StrObjCmp)) | |
810 | { | |
811 | /* push this type name so we don't go through it again */ | |
812 | DefineObj (followedTypeRefs, e->type->basicType->a.localTypeRef->typeName); | |
813 | /* pass in field type not defining type as parent for line no*/ | |
814 | ChkFieldNamesRec (m, td, e->type, definingType->basicType->a.choice, fieldNames, followedTypeRefs); | |
815 | ||
816 | /* pop this type name since we're done checking it */ | |
817 | UndefineObj (followedTypeRefs, e->type->basicType->a.localTypeRef->typeName, StrObjCmp); | |
818 | } | |
819 | } | |
820 | ||
821 | /* this is an embedded CHOICE definition (fieldName is NULL) */ | |
822 | else if (e->type->basicType->choiceId == BASICTYPE_CHOICE) | |
823 | { | |
824 | ChkFieldNamesRec (m, td, e->type, /* pass in field type for line */ | |
825 | definingType->basicType->a.choice, fieldNames, followedTypeRefs); | |
826 | } | |
827 | ||
828 | } | |
829 | } /* ChkFieldNamesRec */ | |
830 | ||
831 | ||
832 | ||
833 | /* | |
834 | * wrapper for ChkFieldNamesRec | |
835 | * Checks that the field names of an aggregate type (CHOICE/SET/SEQ) | |
836 | * are distinct. Violations are printed to stderr. | |
837 | */ | |
838 | void | |
839 | ChkFieldNames PARAMS ((m, td, parent, elmts), | |
840 | Module *m _AND_ | |
841 | TypeDef *td _AND_ | |
842 | Type *parent _AND_ | |
843 | NamedTypeList *elmts) | |
844 | { | |
845 | DefinedObj *fieldNames; | |
846 | DefinedObj *followedTypeRefs; | |
847 | ||
848 | fieldNames = NewObjList(); | |
849 | followedTypeRefs = NewObjList(); | |
850 | ||
851 | /* | |
852 | * first define the type itself as followed to prevent | |
853 | * infinintely checking it | |
854 | */ | |
855 | DefineObj (&followedTypeRefs, td->definedName); | |
856 | ||
857 | ChkFieldNamesRec (m, td, parent, elmts, &fieldNames, &followedTypeRefs); | |
858 | ||
859 | FreeDefinedObjs (&fieldNames); | |
860 | FreeDefinedObjs (&followedTypeRefs); | |
861 | ||
862 | } /* ChkFieldNames */ | |
863 | ||
864 | ||
865 | ||
866 | /* | |
867 | * make sure that the identifiers of the named numbers are unique | |
868 | * among themselves. | |
869 | * | |
870 | * also check that the values of the named numbers are unique | |
871 | * among themselves. | |
872 | */ | |
873 | void | |
874 | ChkNamedNumbers PARAMS ((m, t, n), | |
875 | Module *m _AND_ | |
876 | Type *t _AND_ | |
877 | NamedNumberList *n) | |
878 | { | |
879 | DefinedObj *ids; | |
880 | DefinedObj *nums; | |
881 | ValueDef *nn; | |
882 | Value *baseVal; | |
883 | ||
884 | ||
885 | if (n == NULL) | |
886 | return; | |
887 | ||
888 | ids = NewObjList(); | |
889 | nums = NewObjList(); | |
890 | FOR_EACH_LIST_ELMT (nn, n) | |
891 | { | |
892 | if (ObjIsDefined (ids, nn->definedName, StrObjCmp)) | |
893 | { | |
894 | PrintErrLoc (m->asn1SrcFileName, t->lineNo); | |
895 | fprintf (stderr,"ERROR - named numbers (%s) must have unique identifiers.\n", nn->definedName); | |
896 | } | |
897 | else | |
898 | DefineObj (&ids, nn->definedName); | |
899 | ||
900 | baseVal = GetValue (nn->value); | |
901 | if (baseVal->basicValue->choiceId != BASICVALUE_INTEGER) | |
902 | { | |
903 | PrintErrLoc (m->asn1SrcFileName, t->lineNo); | |
904 | fprintf (stderr,"ERROR - value format problem (%s)- named numbers must be integers.\n", nn->definedName); | |
905 | } | |
906 | else if (ObjIsDefined (nums, &baseVal->basicValue->a.integer, IntObjCmp)) | |
907 | { | |
908 | PrintErrLoc (m->asn1SrcFileName, t->lineNo); | |
909 | fprintf (stderr,"ERROR - named numbers (%s) must have unique values.\n", nn->definedName); | |
910 | } | |
911 | else | |
912 | DefineObj (&nums, &baseVal->basicValue->a.integer); | |
913 | ||
914 | } | |
915 | ||
916 | FreeDefinedObjs (&ids); | |
917 | FreeDefinedObjs (&nums); | |
918 | ||
919 | } /* ChkNamedNumbers */ | |
920 | ||
921 | ||
922 | ||
923 | /* | |
924 | * The same as ChkNamedNumbers except that the elmt values must be | |
925 | * > 0 (needed for BIT STRINGs) | |
926 | */ | |
927 | void | |
928 | ChkNamedBits PARAMS ((m, t, n), | |
929 | Module *m _AND_ | |
930 | Type *t _AND_ | |
931 | NamedNumberList *n) | |
932 | { | |
933 | ValueDef *vd; | |
934 | Value *baseVal; | |
935 | ||
936 | ChkNamedNumbers (m, t, n); | |
937 | ||
938 | FOR_EACH_LIST_ELMT (vd, n) | |
939 | { | |
940 | baseVal = GetValue (vd->value); | |
941 | if ((baseVal->basicValue->choiceId == BASICVALUE_INTEGER) && | |
942 | (baseVal->basicValue->a.integer < 0)) | |
943 | { | |
944 | PrintErrLoc (m->asn1SrcFileName, t->lineNo); | |
945 | fprintf (stderr,"ERROR - named bits (%s) must have positive values.\n", vd->definedName); | |
946 | } | |
947 | } | |
948 | ||
949 | } /* ChkNamedBits */ | |
950 | ||
951 | ||
952 | ||
953 | /* | |
954 | * check that tags on one or more consecutive optional elmts | |
955 | * and following (if any) non-optional elmt are distinct | |
956 | */ | |
957 | void | |
958 | ChkSeqTags PARAMS ((m, td, t), | |
959 | Module *m _AND_ | |
960 | TypeDef *td _AND_ | |
961 | Type *t) | |
962 | { | |
963 | DefinedObj *dO; | |
964 | NamedType *e; | |
965 | ||
966 | if (t->basicType->choiceId != BASICTYPE_SEQUENCE) | |
967 | return; | |
968 | ||
969 | dO = NewObjList(); | |
970 | FOR_EACH_LIST_ELMT (e, t->basicType->a.sequence) | |
971 | { | |
972 | /* if optional add tag */ | |
973 | if (e->type->optional || (e->type->defaultVal != NULL)) | |
974 | { | |
975 | if (!AddFirstTag (&dO, e->type)) | |
976 | { | |
977 | PrintErrLoc (m->asn1SrcFileName, e->type->lineNo); | |
978 | fprintf (stderr,"ERROR - one or more consecutive optional SEQUENCE elmements and the the following non-optional elmt (if any) must have distinct tags.\n"); | |
979 | m->status = MOD_ERROR; | |
980 | } | |
981 | } | |
982 | else if (dO != NULL) /* first non-opt after opt elmts */ | |
983 | { | |
984 | if (!AddFirstTag (&dO, e->type)) | |
985 | { | |
986 | PrintErrLoc (m->asn1SrcFileName, e->type->lineNo); | |
987 | fprintf (stderr,"ERROR - one or more consecutive optional SEQUENCE elmements and the the following non-optional elmt (if any) must have distinct tags.\n"); | |
988 | m->status = MOD_ERROR; | |
989 | } | |
990 | FreeDefinedObjs (&dO); | |
991 | dO = NewObjList(); | |
992 | } | |
993 | } | |
994 | FreeDefinedObjs (&dO); | |
995 | ||
996 | } /* ChkSeqTags */ |