#include <ctype.h>
#include <stdio.h>
#include "asn-incl.h"
#include "mem.h"
#include "asn1module.h"
#include "snacc-util.h"
#include "tag-util.h"
#include "define.h"
#include "err-chk.h"
typedef struct DefinedTag
{
Tag *tag;
struct DefinedTag *next;
} DefinedTag;
typedef struct DefinedName
{
char *name;
struct DefinedName *next;
} DefinedName;
static NamedType *badNamedType;
static DefinedName *fieldNames = NULL;
void ErrChkTypeDef PROTO ((Module *m, TypeDef *td));
void ErrChkType PROTO ((Module *m, TypeDef *td, Type *parent, NamedType *nt, Type *t));
void ErrChkElmtTypes PROTO ((Module *m, TypeDef *td, Type *parent, NamedTypeList *e));
void ErrChkBasicType PROTO ((Module *m, TypeDef *td, Type *parent, NamedType *nt, Type *type));
void ErrChkValueDef PROTO ((Module *m, ValueDef *vd));
void ErrChkValue PROTO ((Module *m, ValueDef *vd, Value *v));
int HasDistinctTags PROTO ((NamedTypeList *elmts));
int AddFirstTag PROTO ((DefinedObj **definedTags, Type *t));
void ChkFieldNames PROTO ((Module *m, TypeDef *td, Type *parent, NamedTypeList *elmts));
void ChkNamedNumbers PROTO ((Module *m, Type *t, NamedNumberList *n));
void ChkNamedBits PROTO ((Module *m, Type *t, NamedNumberList *n));
void ChkSeqTags PROTO ((Module *m, TypeDef *td, Type *t));
int
TagObjCmp PARAMS ((t1, t2),
void *t1 _AND_
void *t2)
{
return (((Tag*) t1)->tclass == ((Tag*) t2)->tclass) &&
(((Tag*) t1)->code == ((Tag*) t2)->code);
}
void
ErrChkModule PARAMS ((m),
Module *m)
{
TypeDef *td;
ValueDef *vd;
DefinedObj *typeNames;
DefinedObj *valueNames;
ImportModule *impList;
ImportElmt *impElmt;
typeNames = NewObjList();
FOR_EACH_LIST_ELMT (td, m->typeDefs)
{
if (ObjIsDefined (typeNames, td->definedName, StrObjCmp))
{
PrintErrLoc (m->asn1SrcFileName, td->type->lineNo);
fprintf (stderr,"ERROR - type \"%s\" is multiply defined.\n", td->definedName);
m->status = MOD_ERROR;
}
else
DefineObj (&typeNames, td->definedName);
ErrChkTypeDef (m, td);
}
FOR_EACH_LIST_ELMT (impList, m->imports)
{
FOR_EACH_LIST_ELMT (impElmt, impList->importElmts)
{
if ((!impElmt->privateScope) && (isupper (impElmt->name[0])))
{
if (ObjIsDefined (typeNames, impElmt->name, StrObjCmp))
{
PrintErrLoc (m->asn1SrcFileName, impElmt->lineNo);
fprintf (stderr,"ERROR - type \"%s\" is multiply defined.\n", impElmt->name);
m->status = MOD_ERROR;
}
else
DefineObj (&typeNames, impElmt->name);
}
}
}
FreeDefinedObjs (&typeNames);
valueNames = NewObjList();
FOR_EACH_LIST_ELMT (vd, m->valueDefs)
{
if (ObjIsDefined (valueNames, vd->definedName, StrObjCmp))
{
PrintErrLoc (m->asn1SrcFileName, vd->value->lineNo);
fprintf (stderr,"ERROR - value \"%s\" is multiply defined.\n", vd->definedName);
m->status = MOD_ERROR;
}
else
DefineObj (&valueNames, vd->definedName);
ErrChkValueDef (m, vd);
}
FOR_EACH_LIST_ELMT (impList, m->imports)
{
FOR_EACH_LIST_ELMT (impElmt, impList->importElmts)
{
if ((!impElmt->privateScope) && (islower (impElmt->name[0])))
{
if (ObjIsDefined (valueNames, impElmt->name, StrObjCmp))
{
PrintErrLoc (m->asn1SrcFileName, impElmt->lineNo);
fprintf (stderr,"ERROR - value \"%s\" is multiply defined.\n", vd->definedName);
m->status = MOD_ERROR;
}
else
DefineObj (&valueNames, impElmt->name);
}
}
}
FreeDefinedObjs (&valueNames);
}
void
ErrChkTypeDef PARAMS ((m, td),
Module *m _AND_
TypeDef *td)
{
if (td == NULL)
return;
ErrChkType (m, td, NULL, NULL, td->type);
}
void
ErrChkType PARAMS ((m, td, parent, nt, t),
Module *m _AND_
TypeDef *td _AND_
Type *parent _AND_
NamedType *nt _AND_
Type *t)
{
if (t == NULL)
return;
ErrChkBasicType (m, td, parent, nt, t);
}
void
ErrChkElmtTypes PARAMS ((m, td, parent, e),
Module *m _AND_
TypeDef *td _AND_
Type *parent _AND_
NamedTypeList *e)
{
NamedType *nt;
if (td->type == parent)
{
ChkFieldNames (m, td, parent, e);
}
FOR_EACH_LIST_ELMT (nt, e)
{
ErrChkType (m, td, parent, nt, nt->type);
}
}
void
ErrChkBasicType PARAMS ((m, td, parent, tnt, type),
Module *m _AND_
TypeDef *td _AND_
Type *parent _AND_
NamedType *tnt _AND_
Type *type)
{
int i, numElmtsAdded;
NamedType *newElmt;
NamedType **newElmtHndl;
NamedType *nt;
NamedTypeList *elmts;
NamedType *origNext;
Type *refdType;
enum BasicTypeChoiceId refdTypeId;
TypeDef *newDef;
if ((type == NULL) || (type->basicType == NULL))
return;
switch (type->basicType->choiceId)
{
case BASICTYPE_LOCALTYPEREF:
case BASICTYPE_IMPORTTYPEREF:
refdTypeId = ParanoidGetBuiltinType (type);
if ((type->implicit) &&
((refdTypeId == BASICTYPE_CHOICE) ||
(refdTypeId == BASICTYPE_ANY) ||
(refdTypeId == BASICTYPE_ANYDEFINEDBY)) &&
(CountTags (type->basicType->a.localTypeRef->link->type) == 0))
{
m->status = MOD_ERROR;
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - IMPLICITLY tagged CHOICE, ANY or ANY DEFINED BY type.\n");
}
if ((parent != NULL) &&
((refdTypeId == BASICTYPE_ANY) ||
(refdTypeId == BASICTYPE_ANYDEFINEDBY)))
{
if ((refdTypeId == BASICTYPE_ANYDEFINEDBY) &&
(parent->basicType->choiceId == BASICTYPE_SET))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
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");
}
if ((refdTypeId == BASICTYPE_ANYDEFINEDBY) && (tnt != NULL) &&
(parent->basicType->choiceId == BASICTYPE_SEQUENCE) &&
(GetAsnListElmtIndex (tnt, parent->basicType->a.sequence) <
GetAsnListElmtIndex (type->basicType->a.anyDefinedBy->link, parent->basicType->a.sequence)))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
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");
}
if (parent->basicType->choiceId == BASICTYPE_SEQUENCE)
nt = LAST_LIST_ELMT (parent->basicType->a.sequence);
if (!((parent->basicType->choiceId == BASICTYPE_SEQUENCE) &&
(type == nt->type)) &&
(type->optional) && (CountTags (type) == 0))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"WARNING - untagged optional ANY encountered, the produced code will be wrong.\n");
}
if (((parent->basicType->choiceId == BASICTYPE_SET) ||
(parent->basicType->choiceId == BASICTYPE_CHOICE)) &&
(CountTags == 0))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"WARNING - untagged ANY in a SET or CHOICE, the produced code will be wrong.\n");
}
}
break;
case BASICTYPE_INTEGER:
case BASICTYPE_ENUMERATED:
ChkNamedNumbers (m, type, type->basicType->a.integer);
break;
case BASICTYPE_BITSTRING:
ChkNamedBits (m, type, type->basicType->a.bitString);
break;
case BASICTYPE_SEQUENCEOF:
case BASICTYPE_SETOF:
ErrChkType (m, td, type, NULL, type->basicType->a.setOf);
break;
case BASICTYPE_SEQUENCE:
ErrChkElmtTypes (m, td, type, type->basicType->a.sequence);
ChkSeqTags (m, td, type);
break;
case BASICTYPE_CHOICE:
if (!HasDistinctTags (type->basicType->a.choice))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - tag conflict among ");
PrintType (stderr, NULL, badNamedType->type);
fprintf (stderr," and the other CHOICE elements.\n");
m->status = MOD_ERROR;
}
if (((type->tags == NULL) || LIST_EMPTY (type->tags)) &&
(type->implicit))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - IMPLICITLy tagged CHOICE type.\n");
m->status = MOD_ERROR;
}
ErrChkElmtTypes (m, td, type, type->basicType->a.choice);
break;
case BASICTYPE_ANYDEFINEDBY:
refdType = GetType (type->basicType->a.anyDefinedBy->link->type);
if ((refdType->basicType->choiceId != BASICTYPE_INTEGER) &&
(refdType->basicType->choiceId != BASICTYPE_ENUMERATED) &&
(refdType->basicType->choiceId != BASICTYPE_OID))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - Field referenced by ANY DEFINED BY type must be of INTEGER or OBJECT IDENTIFIER type.\n");
m->status = MOD_ERROR;
}
if (type->basicType->a.anyDefinedBy->link->type->optional)
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - Field referenced by ANY DEFINED BY cannot be optional.\n");
m->status = MOD_ERROR;
}
if ((parent != NULL) &&
(parent->basicType->choiceId == BASICTYPE_SET))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
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");
}
if ((parent != NULL) && (tnt != NULL) &&
(parent->basicType->choiceId == BASICTYPE_SEQUENCE) &&
(GetAsnListElmtIndex (tnt, parent->basicType->a.sequence) <
GetAsnListElmtIndex (type->basicType->a.anyDefinedBy->link, parent->basicType->a.sequence)))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
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");
}
case BASICTYPE_ANY:
if (((type->tags == NULL) || LIST_EMPTY (type->tags)) &&
(type->implicit))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - IMPLICITLy tagged ANY type.\n");
m->status = MOD_ERROR;
}
if (parent != NULL)
{
if (parent->basicType->choiceId == BASICTYPE_SEQUENCE)
nt = LAST_LIST_ELMT (parent->basicType->a.sequence);
if (!((parent->basicType->choiceId == BASICTYPE_SEQUENCE) &&
(type == nt->type)) &&
(type->optional) && (CountTags (type) == 0))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"WARNING - untagged optional ANY encountered, the produced code will be wrong.\n");
}
if (((parent->basicType->choiceId == BASICTYPE_SET) ||
(parent->basicType->choiceId == BASICTYPE_CHOICE)) &&
(CountTags (type) == 0))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"WARNING - untagged ANY in a SET or CHOICE, the produced code will be wrong.\n");
}
}
break;
case BASICTYPE_SET:
if (!HasDistinctTags (type->basicType->a.set))
{
PrintErrLoc (m->asn1SrcFileName, type->lineNo);
fprintf (stderr,"ERROR - tag conflict among ");
PrintType (stderr, NULL, badNamedType->type);
fprintf (stderr," and the other SET elements.\n");
m->status = MOD_ERROR;
}
ErrChkElmtTypes (m, td, type, type->basicType->a.set);
break;
default:
break;
}
}
void
ErrChkValueDef PARAMS ((m, vd),
Module *m _AND_
ValueDef *vd)
{
ErrChkValue (m, vd, vd->value);
}
void
ErrChkValue PARAMS ((m, vd, v),
Module *m _AND_
ValueDef *vd _AND_
Value *v)
{
}
int
HasDistinctTags PARAMS ((elmts),
NamedTypeList *elmts)
{
DefinedObj *tL;
NamedType *e;
tL = NewObjList();
FOR_EACH_LIST_ELMT (e, elmts)
{
if (!AddFirstTag (&tL, e->type))
{
FreeDefinedObjs (&tL);
badNamedType = e;
return FALSE;
}
}
FreeDefinedObjs (&tL);
badNamedType = NULL;
return TRUE;
}
int
AddFirstTag PARAMS ((definedTags, t),
DefinedObj **definedTags _AND_
Type *t)
{
Tag *tag;
TagList *tl;
Tag *last;
int implicitRef;
NamedType *e;
tl = t->tags;
if (tl != NULL)
AsnListFirst (tl);
implicitRef = FALSE;
for (;;)
{
if ((tl != NULL) && (CURR_LIST_NODE (tl) != NULL) &&
(CURR_LIST_ELMT (tl) != NULL))
{
tag = (Tag*) CURR_LIST_ELMT (tl);
if (ObjIsDefined (*definedTags, tag, TagObjCmp))
return FALSE;
else
{
DefineObj (definedTags, tag);
return TRUE;
}
}
if ((t->basicType->choiceId == BASICTYPE_LOCALTYPEREF) ||
(t->basicType->choiceId == BASICTYPE_IMPORTTYPEREF))
{
if (!implicitRef)
implicitRef = t->implicit;
if (t->basicType->a.localTypeRef->link == NULL)
{
fprintf (stderr,"ERROR - unresolved type ref, cannot get tags for decoding\n");
break;
}
t = t->basicType->a.localTypeRef->link->type;
tl = t->tags;
if (tl != NULL)
{
AsnListFirst (tl);
if ((!LIST_EMPTY (tl)) && implicitRef)
{
AsnListNext (tl);
implicitRef = FALSE;
}
}
}
else if ((t->basicType->choiceId == BASICTYPE_CHOICE))
{
if (implicitRef)
{
fprintf (stderr,"ERROR - IMPLICITLY Tagged CHOICE\n");
}
FOR_EACH_LIST_ELMT (e, t->basicType->a.choice)
{
if (!AddFirstTag (definedTags, e->type))
return FALSE;
}
return TRUE;
}
else
return TRUE;
}
}
void
ChkFieldNamesRec PARAMS ((m, td, parent, elmts, fieldNames, followedTypeRefs),
Module *m _AND_
TypeDef *td _AND_
Type *parent _AND_
NamedTypeList *elmts _AND_
DefinedObj **fieldNames _AND_
DefinedObj **followedTypeRefs)
{
NamedType *e;
Type *definingType;
FOR_EACH_LIST_ELMT (e, elmts)
{
definingType = ParanoidGetType (e->type);
if (e->fieldName != NULL)
{
if (ObjIsDefined (*fieldNames, e->fieldName, StrObjCmp))
{
if (parent->basicType->a.choice == elmts)
{
PrintErrLoc (m->asn1SrcFileName, e->type->lineNo);
fprintf (stderr,"WARNING - field name \"%s\" is used more than once in same value notation scope.\n", e->fieldName);
}
else
{
PrintErrLoc (m->asn1SrcFileName, parent->lineNo);
fprintf (stderr,"WARNING - field name \"%s\" in embedded CHOICE conflicts with field name in type \"%s\".", e->fieldName, td->definedName);
fprintf (stderr," This may lead to ambiguous value notation.\n");
}
}
else
DefineObj (fieldNames, e->fieldName);
}
else if (((e->type->basicType->choiceId == BASICTYPE_LOCALTYPEREF) ||
(e->type->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) &&
(definingType->basicType->choiceId == BASICTYPE_CHOICE))
{
if (!ObjIsDefined (*followedTypeRefs, e->type->basicType->a.localTypeRef->typeName, StrObjCmp))
{
DefineObj (followedTypeRefs, e->type->basicType->a.localTypeRef->typeName);
ChkFieldNamesRec (m, td, e->type, definingType->basicType->a.choice, fieldNames, followedTypeRefs);
UndefineObj (followedTypeRefs, e->type->basicType->a.localTypeRef->typeName, StrObjCmp);
}
}
else if (e->type->basicType->choiceId == BASICTYPE_CHOICE)
{
ChkFieldNamesRec (m, td, e->type,
definingType->basicType->a.choice, fieldNames, followedTypeRefs);
}
}
}
void
ChkFieldNames PARAMS ((m, td, parent, elmts),
Module *m _AND_
TypeDef *td _AND_
Type *parent _AND_
NamedTypeList *elmts)
{
DefinedObj *fieldNames;
DefinedObj *followedTypeRefs;
fieldNames = NewObjList();
followedTypeRefs = NewObjList();
DefineObj (&followedTypeRefs, td->definedName);
ChkFieldNamesRec (m, td, parent, elmts, &fieldNames, &followedTypeRefs);
FreeDefinedObjs (&fieldNames);
FreeDefinedObjs (&followedTypeRefs);
}
void
ChkNamedNumbers PARAMS ((m, t, n),
Module *m _AND_
Type *t _AND_
NamedNumberList *n)
{
DefinedObj *ids;
DefinedObj *nums;
ValueDef *nn;
Value *baseVal;
if (n == NULL)
return;
ids = NewObjList();
nums = NewObjList();
FOR_EACH_LIST_ELMT (nn, n)
{
if (ObjIsDefined (ids, nn->definedName, StrObjCmp))
{
PrintErrLoc (m->asn1SrcFileName, t->lineNo);
fprintf (stderr,"ERROR - named numbers (%s) must have unique identifiers.\n", nn->definedName);
}
else
DefineObj (&ids, nn->definedName);
baseVal = GetValue (nn->value);
if (baseVal->basicValue->choiceId != BASICVALUE_INTEGER)
{
PrintErrLoc (m->asn1SrcFileName, t->lineNo);
fprintf (stderr,"ERROR - value format problem (%s)- named numbers must be integers.\n", nn->definedName);
}
else if (ObjIsDefined (nums, &baseVal->basicValue->a.integer, IntObjCmp))
{
PrintErrLoc (m->asn1SrcFileName, t->lineNo);
fprintf (stderr,"ERROR - named numbers (%s) must have unique values.\n", nn->definedName);
}
else
DefineObj (&nums, &baseVal->basicValue->a.integer);
}
FreeDefinedObjs (&ids);
FreeDefinedObjs (&nums);
}
void
ChkNamedBits PARAMS ((m, t, n),
Module *m _AND_
Type *t _AND_
NamedNumberList *n)
{
ValueDef *vd;
Value *baseVal;
ChkNamedNumbers (m, t, n);
FOR_EACH_LIST_ELMT (vd, n)
{
baseVal = GetValue (vd->value);
if ((baseVal->basicValue->choiceId == BASICVALUE_INTEGER) &&
(baseVal->basicValue->a.integer < 0))
{
PrintErrLoc (m->asn1SrcFileName, t->lineNo);
fprintf (stderr,"ERROR - named bits (%s) must have positive values.\n", vd->definedName);
}
}
}
void
ChkSeqTags PARAMS ((m, td, t),
Module *m _AND_
TypeDef *td _AND_
Type *t)
{
DefinedObj *dO;
NamedType *e;
if (t->basicType->choiceId != BASICTYPE_SEQUENCE)
return;
dO = NewObjList();
FOR_EACH_LIST_ELMT (e, t->basicType->a.sequence)
{
if (e->type->optional || (e->type->defaultVal != NULL))
{
if (!AddFirstTag (&dO, e->type))
{
PrintErrLoc (m->asn1SrcFileName, e->type->lineNo);
fprintf (stderr,"ERROR - one or more consecutive optional SEQUENCE elmements and the the following non-optional elmt (if any) must have distinct tags.\n");
m->status = MOD_ERROR;
}
}
else if (dO != NULL)
{
if (!AddFirstTag (&dO, e->type))
{
PrintErrLoc (m->asn1SrcFileName, e->type->lineNo);
fprintf (stderr,"ERROR - one or more consecutive optional SEQUENCE elmements and the the following non-optional elmt (if any) must have distinct tags.\n");
m->status = MOD_ERROR;
}
FreeDefinedObjs (&dO);
dO = NewObjList();
}
}
FreeDefinedObjs (&dO);
}