3562 lines
125 KiB
C
3562 lines
125 KiB
C
/* Copyright (C) Boris Nikolaus, Germany, 1996-1997. All rights reserved. */
|
|
/* Copyright (C) Microsoft Corporation, 1997-1998. All rights reserved. */
|
|
|
|
#include "precomp.h"
|
|
#include "optcase.h"
|
|
|
|
void GenPERFuncSimpleType(AssignmentList_t ass, PERTypeInfo_t *info, char *valref, TypeFunc_e et, char *encref);
|
|
void GenPERStringTableSimpleType(AssignmentList_t ass, PERTypeInfo_t *info);
|
|
|
|
void GenPEREncSimpleType(AssignmentList_t ass, PERTypeInfo_t *info, char *valref, char *encref);
|
|
void GenPEREncGenericUnextended(
|
|
AssignmentList_t ass,
|
|
PERTypeInfo_t *info,
|
|
PERSimpleTypeInfo_t *sinfo,
|
|
char *valref,
|
|
char *lenref,
|
|
char *encref);
|
|
void GenPERFuncSequenceSetType(AssignmentList_t ass, char *module, Assignment_t *at, char *valref, char *encref, TypeFunc_e et);
|
|
void GenPERFuncChoiceType(AssignmentList_t ass, char *module, Assignment_t *at, char *valref, char *encref, TypeFunc_e et);
|
|
|
|
void GenPERDecSimpleType(AssignmentList_t ass, PERTypeInfo_t *info, char *valref, char *encref);
|
|
void GenPERDecGenericUnextended(
|
|
AssignmentList_t ass,
|
|
PERTypeInfo_t *info,
|
|
PERSimpleTypeInfo_t *sinfo,
|
|
char *valref,
|
|
char *lenref,
|
|
char *encref);
|
|
|
|
int IsUnconstrainedInteger(PERSimpleTypeInfo_t *sinfo);
|
|
|
|
extern int g_fDecZeroMemory;
|
|
extern int g_nDbgModuleName;
|
|
extern unsigned g_cPDUs;
|
|
extern int g_fCaseBasedOptimizer;
|
|
extern int g_fNoAssert;
|
|
|
|
|
|
/* write header needed for PER encodings */
|
|
void
|
|
GenPERHeader()
|
|
{
|
|
// output("#include \"perfnlib.h\"\n");
|
|
}
|
|
|
|
/* set prototypes and function args of PER functions */
|
|
void
|
|
GetPERPrototype(Arguments_t *args)
|
|
{
|
|
args->enccast = "ASN1encoding_t, void *";
|
|
args->encfunc = "ASN1encoding_t enc, %s *val";
|
|
args->Pencfunc = "ASN1encoding_t enc, P%s *val";
|
|
args->deccast = "ASN1decoding_t, void *";
|
|
args->decfunc = "ASN1decoding_t dec, %s *val";
|
|
args->Pdecfunc = "ASN1decoding_t dec, P%s *val";
|
|
args->freecast = "void *";
|
|
args->freefunc = "%s *val";
|
|
args->Pfreefunc = "P%s *val";
|
|
args->cmpcast = "void *, void *";
|
|
args->cmpfunc = "%s *val1, %s *val2";
|
|
args->Pcmpfunc = "P%s *val1, P%s *val2";
|
|
}
|
|
|
|
/* write initialization function needed for PER encodings */
|
|
void
|
|
GenPERInit(AssignmentList_t ass, char *module)
|
|
{
|
|
output("%s = ASN1_CreateModule(0x%x, ASN1_PER_RULE_ALIGNED, %s, %d, (const ASN1GenericFun_t *) encfntab, (const ASN1GenericFun_t *) decfntab, freefntab, sizetab, 0x%lx);\n",
|
|
module,
|
|
ASN1_THIS_VERSION,
|
|
g_fNoAssert ? "ASN1FLAGS_NOASSERT" : "ASN1FLAGS_NONE",
|
|
g_cPDUs,
|
|
g_nDbgModuleName);
|
|
}
|
|
|
|
/* generate function body for a type */
|
|
void GenPERFuncType(AssignmentList_t ass, char *module, Assignment_t *at, TypeFunc_e et)
|
|
{
|
|
Type_t *type;
|
|
char *encref;
|
|
char *valref;
|
|
|
|
/* get some informations */
|
|
type = at->U.Type.Type;
|
|
switch (et) {
|
|
case eStringTable:
|
|
valref = encref = "";
|
|
break;
|
|
case eEncode:
|
|
encref = "enc";
|
|
valref = "val";
|
|
break;
|
|
case eDecode:
|
|
encref = "dec";
|
|
valref = "val";
|
|
break;
|
|
}
|
|
|
|
/* function body */
|
|
switch (type->Type) {
|
|
case eType_Boolean:
|
|
case eType_Integer:
|
|
case eType_Enumerated:
|
|
case eType_Real:
|
|
case eType_BitString:
|
|
case eType_OctetString:
|
|
case eType_UTF8String:
|
|
case eType_Null:
|
|
case eType_EmbeddedPdv:
|
|
case eType_External:
|
|
case eType_ObjectIdentifier:
|
|
case eType_BMPString:
|
|
case eType_GeneralString:
|
|
case eType_GraphicString:
|
|
case eType_IA5String:
|
|
case eType_ISO646String:
|
|
case eType_NumericString:
|
|
case eType_PrintableString:
|
|
case eType_TeletexString:
|
|
case eType_T61String:
|
|
case eType_UniversalString:
|
|
case eType_VideotexString:
|
|
case eType_VisibleString:
|
|
case eType_CharacterString:
|
|
case eType_GeneralizedTime:
|
|
case eType_UTCTime:
|
|
case eType_ObjectDescriptor:
|
|
case eType_RestrictedString:
|
|
case eType_Open:
|
|
case eType_Reference:
|
|
GenPERFuncSimpleType(ass, &type->PERTypeInfo, Dereference(valref), et, encref);
|
|
break;
|
|
|
|
case eType_SequenceOf:
|
|
case eType_SetOf:
|
|
GenPERFuncSimpleType(ass, &type->PERTypeInfo, Dereference(valref), et, encref);
|
|
break;
|
|
|
|
case eType_Sequence:
|
|
case eType_Set:
|
|
case eType_InstanceOf:
|
|
GenPERFuncSequenceSetType(ass, module, at, valref, encref, et);
|
|
break;
|
|
|
|
case eType_Choice:
|
|
GenPERFuncChoiceType(ass, module, at, valref, encref, et);
|
|
break;
|
|
|
|
case eType_Selection:
|
|
case eType_Undefined:
|
|
MyAbort();
|
|
/*NOTREACHED*/
|
|
}
|
|
}
|
|
|
|
/* generate function body for components */
|
|
void
|
|
GenPERFuncComponents(AssignmentList_t ass, char *module, uint32_t optindex, ComponentList_t components, char *valref, char *encref, char *oref, TypeFunc_e et, int inextension, int inchoice)
|
|
{
|
|
Component_t *com;
|
|
NamedType_t *namedType;
|
|
char *ide;
|
|
char valbuf[256];
|
|
char typebuf[256];
|
|
int conditional, skip;
|
|
|
|
/* get a parented encoding_t/decoding_t for sequence/set */
|
|
if (inextension && !inchoice) {
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eEncode:
|
|
outputvar("ASN1encoding_t ee;\n");
|
|
output("if (ASN1_CreateEncoder(%s->module, &ee, NULL, 0, %s) < 0)\n",
|
|
encref, encref);
|
|
output("return 0;\n");
|
|
break;
|
|
case eDecode:
|
|
outputvar("ASN1decoding_t dd;\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* emit components of extension root */
|
|
for (com = components; com; com = com->Next) {
|
|
if (com->Type == eComponent_ExtensionMarker)
|
|
break;
|
|
|
|
/* get some information */
|
|
namedType = com->U.NOD.NamedType;
|
|
ide = Identifier2C(namedType->Identifier);
|
|
|
|
/* skip unnecessary elements */
|
|
skip = (namedType->Type->Flags & eTypeFlags_Null) && !inextension;
|
|
|
|
/* check if optional/default component is present or choice is */
|
|
/* selected */
|
|
conditional = 0;
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eEncode:
|
|
case eDecode:
|
|
if (inchoice) {
|
|
// lonchanc: we should not skip any case in Decode
|
|
// because we cannot tell skipped cases from extension.
|
|
// on the other hand, in Encode, we'd better not either.
|
|
// when people put in customization in extension,
|
|
// we cannot tell as well.
|
|
if (skip)
|
|
{
|
|
output("case %d:\nbreak;\n", optindex);
|
|
}
|
|
else
|
|
{
|
|
output("case %d:\n", optindex);
|
|
conditional = 1;
|
|
}
|
|
optindex++;
|
|
} else {
|
|
if (com->Type == eComponent_Optional ||
|
|
com->Type == eComponent_Default ||
|
|
inextension) {
|
|
if (!skip) {
|
|
output("if (%s[%u] & 0x%x) {\n", oref,
|
|
optindex / 8, 0x80 >> (optindex & 7));
|
|
conditional = 1;
|
|
}
|
|
optindex++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* get a parented encoding_t/decoding_t for choice */
|
|
if (inextension && inchoice) {
|
|
/* get a parented encoding_t/decoding_t */
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eEncode:
|
|
outputvar("ASN1encoding_t ee;\n");
|
|
output("if (ASN1_CreateEncoder(%s->module, &ee, NULL, 0, %s) < 0)\n",
|
|
encref, encref);
|
|
output("return 0;\n");
|
|
break;
|
|
case eDecode:
|
|
outputvar("ASN1decoding_t dd;\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* dereference pointer if pointer directive used */
|
|
if (inchoice) {
|
|
if (GetTypeRules(ass, namedType->Type) & eTypeRules_Pointer)
|
|
sprintf(valbuf, "*(%s)->u.%s", valref, ide);
|
|
else
|
|
sprintf(valbuf, "(%s)->u.%s", valref, ide);
|
|
} else {
|
|
if (GetTypeRules(ass, namedType->Type) & eTypeRules_Pointer)
|
|
sprintf(valbuf, "*(%s)->%s", valref, ide);
|
|
else
|
|
sprintf(valbuf, "(%s)->%s", valref, ide);
|
|
}
|
|
|
|
/* allocate memory if decoding and pointer directive used */
|
|
if (et == eDecode &&
|
|
(GetTypeRules(ass, namedType->Type) & eTypeRules_Pointer) &&
|
|
!(GetType(ass, namedType->Type)->Flags & eTypeFlags_Null)) {
|
|
sprintf(typebuf, "%s *",
|
|
GetTypeName(ass, namedType->Type));
|
|
output("if (!(%s = (%s)ASN1DecAlloc(%s, sizeof(%s))))\n",
|
|
Reference(valbuf), typebuf, encref, valbuf);
|
|
output("return 0;\n");
|
|
}
|
|
|
|
/* handle subtype value */
|
|
if (!skip) {
|
|
if (!inextension) {
|
|
GenPERFuncSimpleType(ass, &namedType->Type->PERTypeInfo,
|
|
valbuf, et, encref);
|
|
} else {
|
|
switch (et) {
|
|
case eStringTable:
|
|
GenPERFuncSimpleType(ass, &namedType->Type->PERTypeInfo,
|
|
valbuf, et, encref);
|
|
break;
|
|
case eEncode:
|
|
GenPERFuncSimpleType(ass, &namedType->Type->PERTypeInfo,
|
|
valbuf, et, "ee");
|
|
// lonchanc: added the following API to replace the following
|
|
// chunk of code.
|
|
output("if (!ASN1PEREncFlushFragmentedToParent(ee))\n");
|
|
// output("if (!ASN1PEREncFlush(ee))\n");
|
|
// output("return 0;\n");
|
|
// output("if (!ASN1PEREncFragmented(%s, ee->len, ee->buf, 8))\n",
|
|
// encref);
|
|
output("return 0;\n");
|
|
break;
|
|
case eDecode:
|
|
outputvar("ASN1octet_t *db;\n");
|
|
outputvar("ASN1uint32_t ds;\n");
|
|
output("if (!ASN1PERDecFragmented(%s, &ds, &db, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("if (ASN1_CreateDecoderEx(%s->module, &dd, db, ds, %s, ASN1DECODE_AUTOFREEBUFFER) < 0)\n",
|
|
encref, encref);
|
|
output("return 0;\n");
|
|
GenPERFuncSimpleType(ass, &namedType->Type->PERTypeInfo,
|
|
valbuf, et, "dd");
|
|
output("ASN1_CloseDecoder(dd);\n");
|
|
// output("DecMemFree(%s, db);\n", encref);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* drop the parented encoding_t/decoding_t for choice */
|
|
if (inextension && inchoice) {
|
|
if (et == eEncode) {
|
|
output("ASN1_CloseEncoder2(ee);\n");
|
|
}
|
|
}
|
|
|
|
/* end of check for presence of optional/default component */
|
|
if (inchoice) {
|
|
if (conditional)
|
|
output("break;\n");
|
|
} else {
|
|
if (conditional)
|
|
output("}\n");
|
|
}
|
|
}
|
|
|
|
/* drop the parented encoding_t/decoding_t for sequence/set */
|
|
if (inextension && !inchoice) {
|
|
if (et == eEncode) {
|
|
output("ASN1_CloseEncoder2(ee);\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* generate function body for sequence/set type */
|
|
void GenPERFuncSequenceSetType(AssignmentList_t ass, char *module, Assignment_t *at, char *valref, char *encref, TypeFunc_e et)
|
|
{
|
|
uint32_t optionals, extensions;
|
|
Component_t *components, *com;
|
|
PERTypeInfo_t inf;
|
|
Type_t *type;
|
|
char valbuf[256];
|
|
int conditional;
|
|
char obuf[256];
|
|
|
|
type = at->U.Type.Type;
|
|
optionals = type->U.SSC.Optionals;
|
|
extensions = type->U.SSC.Extensions;
|
|
components = type->U.SSC.Components;
|
|
inf.Identifier = NULL;
|
|
inf.Flags = 0;
|
|
inf.Rules = 0;
|
|
inf.EnumerationValues = NULL;
|
|
inf.NOctets = 0;
|
|
inf.Type = eExtension_Unextended;
|
|
inf.Root.TableIdentifier = NULL;
|
|
inf.Root.Table = NULL;
|
|
inf.Root.Data = ePERSTIData_Extension;
|
|
inf.Root.SubType = NULL;
|
|
inf.Root.SubIdentifier = NULL;
|
|
inf.Root.NBits = 0;
|
|
inf.Root.Constraint = ePERSTIConstraint_Unconstrained;
|
|
intx_setuint32(&inf.Root.LowerVal, 0);
|
|
intx_setuint32(&inf.Root.UpperVal, 0);
|
|
inf.Root.Alignment = ePERSTIAlignment_BitAligned;
|
|
inf.Root.Length = ePERSTILength_NoLength;
|
|
inf.Root.LConstraint = ePERSTIConstraint_Unconstrained;
|
|
inf.Root.LLowerVal = 0;
|
|
inf.Root.LUpperVal = 0;
|
|
inf.Root.LNBits = 0;
|
|
inf.Root.LAlignment = ePERSTIAlignment_OctetAligned;
|
|
|
|
/* set/clear missing bits in optional/default bit field */
|
|
GenFuncSequenceSetOptionals(ass, valref, components,
|
|
optionals, extensions, obuf, et);
|
|
|
|
/* emit/get extension bit if needed */
|
|
if (type->Flags & eTypeFlags_ExtensionMarker) {
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eEncode:
|
|
if (type->Flags & eTypeFlags_ExtensionMarker) {
|
|
if (!extensions) {
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
output("if (!ASN1PEREncExtensionBitClear(%s))\n", encref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PEREncBitVal(%s, 1, 0))\n", encref);
|
|
}
|
|
output("return 0;\n");
|
|
} else {
|
|
outputvar("ASN1uint32_t y;\n");
|
|
output("y = ASN1PEREncCheckExtensions(%d, %s + %d);\n",
|
|
extensions, strcmp(obuf, "o") ? obuf : "(val)->o", (optionals + 7) / 8);
|
|
output("if (!ASN1PEREncBitVal(%s, 1, y))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
}
|
|
break;
|
|
case eDecode:
|
|
if (type->Flags & eTypeFlags_ExtensionMarker) {
|
|
outputvar("ASN1uint32_t y;\n");
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
output("if (!ASN1PERDecExtensionBit(%s, &y))\n", encref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecBit(%s, &y))\n", encref);
|
|
}
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* emit/get bit field of optionals */
|
|
if (optionals) {
|
|
inf.Root.NBits = optionals;
|
|
inf.Root.Length = ePERSTILength_NoLength;
|
|
if (optionals >= 0x10000)
|
|
MyAbort();
|
|
GenPERFuncSimpleType(ass, &inf, obuf, et, encref);
|
|
}
|
|
|
|
/* emit components of extension root */
|
|
GenPERFuncComponents(ass, module, 0, components,
|
|
valref, encref, obuf, et, 0, 0);
|
|
|
|
/* handle extensions */
|
|
if (type->Flags & eTypeFlags_ExtensionMarker) {
|
|
conditional = 0;
|
|
if (!extensions) {
|
|
|
|
/* skip unknown extension bit field */
|
|
if (et == eDecode) {
|
|
output("if (y) {\n");
|
|
inf.Root.NBits = 1;
|
|
inf.Root.Length = ePERSTILength_SmallLength;
|
|
inf.Root.LConstraint = ePERSTIConstraint_Semiconstrained;
|
|
inf.Root.LLowerVal = 1;
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
output("if (!ASN1PERDecSkipNormallySmallExtensionFragmented(%s))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
goto FinalTouch;
|
|
}
|
|
else
|
|
{
|
|
GenPERFuncSimpleType(ass, &inf, NULL, et, encref);
|
|
conditional = 1;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
/* check if extension bit is set */
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eEncode:
|
|
output("if (y) {\n");
|
|
conditional = 1;
|
|
break;
|
|
case eDecode:
|
|
output("if (!y) {\n");
|
|
output("ZeroMemory(%s + %d, %d);\n", obuf,
|
|
(optionals + 7) / 8, (extensions + 7) / 8);
|
|
output("} else {\n");
|
|
conditional = 1;
|
|
break;
|
|
}
|
|
|
|
/* emit/get bit field of extensions */
|
|
inf.Root.NBits = extensions;
|
|
inf.Root.Length = ePERSTILength_SmallLength;
|
|
inf.Root.LConstraint = ePERSTIConstraint_Semiconstrained;
|
|
inf.Root.LLowerVal = 1;
|
|
sprintf(valbuf, "%s + %d", obuf, (optionals + 7) / 8);
|
|
GenPERFuncSimpleType(ass, &inf, valbuf, et, encref);
|
|
|
|
/* get start of extensions */
|
|
for (com = components; com; com = com->Next) {
|
|
if (com->Type == eComponent_ExtensionMarker) {
|
|
com = com->Next;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* emit components of extension */
|
|
GenPERFuncComponents(ass, module, (optionals + 7) & ~7, com,
|
|
valref, encref, obuf, et, 1, 0);
|
|
}
|
|
|
|
/* skip unknown extensions */
|
|
if (et == eDecode) {
|
|
outputvar("ASN1uint32_t i;\n");
|
|
outputvar("ASN1uint32_t e;\n");
|
|
output("for (i = 0; i < e; i++) {\n");
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
}
|
|
|
|
/* end of extension handling */
|
|
if (conditional)
|
|
output("}\n");
|
|
}
|
|
|
|
FinalTouch:
|
|
|
|
/* some user-friendly assignments for non-present optional/default */
|
|
/* components */
|
|
GenFuncSequenceSetDefaults(ass, valref, components, obuf, et);
|
|
}
|
|
|
|
/* generate function body for choice type */
|
|
void GenPERFuncChoiceType(AssignmentList_t ass, char *module, Assignment_t *at, char *valref, char *encref, TypeFunc_e et)
|
|
{
|
|
Type_t *type;
|
|
char valbuf[256];
|
|
uint32_t alternatives;
|
|
Component_t *components, *com;
|
|
int fOptimizeCase = 0;
|
|
|
|
/* get some informations */
|
|
type = at->U.Type.Type;
|
|
alternatives = type->U.SSC.Alternatives;
|
|
components = type->U.SSC.Components;
|
|
|
|
/* encode choice selector */
|
|
switch (et) {
|
|
case eStringTable:
|
|
sprintf(valbuf, "(%s)->choice", valref);
|
|
break;
|
|
case eEncode:
|
|
sprintf(valbuf, "(%s)->choice", valref);
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
switch (type->PERTypeInfo.Type)
|
|
{
|
|
case eExtension_Unconstrained:
|
|
break;
|
|
case eExtension_Unextended: // no extension mark at all
|
|
output("if (!ASN1PEREncSimpleChoice(%s, %s, %u))\n",
|
|
encref, valbuf, type->PERTypeInfo.Root.NBits);
|
|
output("return 0;\n");
|
|
fOptimizeCase = 1;
|
|
break;
|
|
case eExtension_Extendable: // extension mark exists, but no choice appears after the mark
|
|
output("if (!ASN1PEREncSimpleChoiceEx(%s, %s, %u))\n",
|
|
encref, valbuf, type->PERTypeInfo.Root.NBits);
|
|
output("return 0;\n");
|
|
fOptimizeCase = 1;
|
|
break;
|
|
case eExtension_Extended: // extension mark exists, but some choices appear after the mark
|
|
output("if (!ASN1PEREncComplexChoice(%s, %s, %u, %u))\n",
|
|
encref, valbuf, type->PERTypeInfo.Root.NBits, intx2uint32(&(type->PERTypeInfo.Additional.LowerVal)));
|
|
output("return 0;\n");
|
|
fOptimizeCase = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (ASN1_CHOICE_BASE)
|
|
{
|
|
sprintf(valbuf, "(%s)->choice - %d", valref, ASN1_CHOICE_BASE);
|
|
}
|
|
break;
|
|
case eDecode:
|
|
sprintf(valbuf, "(%s)->choice", valref);
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
switch (type->PERTypeInfo.Type)
|
|
{
|
|
case eExtension_Unconstrained:
|
|
break;
|
|
case eExtension_Unextended: // no extension mark at all
|
|
output("if (!ASN1PERDecSimpleChoice(%s, %s, %u))\n",
|
|
encref, Reference(valbuf), type->PERTypeInfo.Root.NBits);
|
|
output("return 0;\n");
|
|
fOptimizeCase = 1;
|
|
break;
|
|
case eExtension_Extendable: // extension mark exists, but no choice appears after the mark
|
|
output("if (!ASN1PERDecSimpleChoiceEx(%s, %s, %u))\n",
|
|
encref, Reference(valbuf), type->PERTypeInfo.Root.NBits);
|
|
output("return 0;\n");
|
|
fOptimizeCase = 1;
|
|
break;
|
|
case eExtension_Extended: // extension mark exists, but some choices appear after the mark
|
|
output("if (!ASN1PERDecComplexChoice(%s, %s, %u, %u))\n",
|
|
encref, Reference(valbuf), type->PERTypeInfo.Root.NBits, intx2uint32(&(type->PERTypeInfo.Additional.LowerVal)));
|
|
output("return 0;\n");
|
|
fOptimizeCase = 1;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (! fOptimizeCase)
|
|
{
|
|
if (eDecode == et)
|
|
{
|
|
output("%s = %d;\n", valbuf, ASN1_CHOICE_INVALID);
|
|
}
|
|
GenPERFuncSimpleType(ass, &type->PERTypeInfo, valbuf, et, encref);
|
|
|
|
// lonchanc: in case of decoding, we need to increment choice value
|
|
// by the amount of ASN1_CHOICE_BASE
|
|
if (et == eDecode && ASN1_CHOICE_BASE)
|
|
{
|
|
output("(%s)->choice += %d;\n", valref, ASN1_CHOICE_BASE);
|
|
}
|
|
}
|
|
|
|
/* finished if choice only contains NULL alternatives or if choice */
|
|
/* contains no data to free */
|
|
if (type->Flags & eTypeFlags_NullChoice)
|
|
return;
|
|
|
|
/* create switch statement */
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eDecode:
|
|
case eEncode:
|
|
output("switch ((%s)->choice) {\n", valref);
|
|
break;
|
|
}
|
|
|
|
/* generate components of extension root */
|
|
GenPERFuncComponents(ass, module, ASN1_CHOICE_BASE, components,
|
|
valref, encref, NULL, et, 0, 1);
|
|
|
|
/* get start of extensions */
|
|
for (com = components; com; com = com->Next) {
|
|
if (com->Type == eComponent_ExtensionMarker) {
|
|
com = com->Next;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* generate components of extension */
|
|
GenPERFuncComponents(ass, module, ASN1_CHOICE_BASE + alternatives, com,
|
|
valref, encref, NULL, et, 1, 1);
|
|
|
|
/* skip unknown extensions */
|
|
if (et == eDecode && (type->Flags & eTypeFlags_ExtensionMarker)) {
|
|
output("case %d:\n\t/* extension case */\n", ASN1_CHOICE_INVALID + 1);
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n", encref);
|
|
output("return 0;\n");
|
|
output("break;\n");
|
|
}
|
|
|
|
// debug purpose
|
|
switch (et)
|
|
{
|
|
case eEncode:
|
|
output("default:\n\t/* impossible */\n");
|
|
output("ASN1EncSetError(%s, ASN1_ERR_CHOICE);\n", encref);
|
|
output("return 0;\n");
|
|
break;
|
|
case eDecode:
|
|
output("default:\n\t/* impossible */\n");
|
|
output("ASN1DecSetError(%s, ASN1_ERR_CHOICE);\n", encref);
|
|
output("return 0;\n");
|
|
break;
|
|
}
|
|
|
|
/* end of switch statement */
|
|
switch (et) {
|
|
case eStringTable:
|
|
break;
|
|
case eEncode:
|
|
case eDecode:
|
|
output("}\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* generate function body for simple type */
|
|
void
|
|
GenPERFuncSimpleType(AssignmentList_t ass, PERTypeInfo_t *info, char *valref, TypeFunc_e et, char *encref)
|
|
{
|
|
switch (et) {
|
|
case eStringTable:
|
|
GenPERStringTableSimpleType(ass, info);
|
|
break;
|
|
case eEncode:
|
|
GenPEREncSimpleType(ass, info, valref, encref);
|
|
break;
|
|
case eDecode:
|
|
GenPERDecSimpleType(ass, info, valref, encref);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* generate string table for a simple type */
|
|
void
|
|
GenPERStringTableSimpleType(AssignmentList_t ass, PERTypeInfo_t *info)
|
|
{
|
|
ValueConstraint_t *pc;
|
|
uint32_t i, n, lo, up;
|
|
|
|
switch (info->Root.Data) {
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_TableString:
|
|
case ePERSTIData_ZeroString:
|
|
case ePERSTIData_ZeroTableString:
|
|
if (info->Root.TableIdentifier) {
|
|
if (!strcmp(info->Root.TableIdentifier, "ASN1NumericStringTable"))
|
|
break;
|
|
output("static ASN1stringtableentry_t %sEntries[] = {\n",
|
|
info->Root.TableIdentifier);
|
|
i = n = 0;
|
|
for (pc = info->Root.Table; pc; pc = pc->Next) {
|
|
lo = GetValue(ass, pc->Lower.Value)->
|
|
U.RestrictedString.Value.value[0];
|
|
up = GetValue(ass, pc->Upper.Value)->
|
|
U.RestrictedString.Value.value[0];
|
|
output("{ %u, %u, %u }, ", lo, up, n);
|
|
n += (up - lo) + 1;
|
|
i++;
|
|
if ((i & 3) == 3 || !pc->Next)
|
|
output("\n");
|
|
}
|
|
output("};\n");
|
|
output("\n");
|
|
output("static ASN1stringtable_t %s = {\n",
|
|
info->Root.TableIdentifier);
|
|
output("%d, %sEntries\n", i, info->Root.TableIdentifier);
|
|
output("};\n");
|
|
output("\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
case ePERSTIData_SequenceOf:
|
|
GenPERFuncSimpleType(ass, &info->Root.SubType->PERTypeInfo, "", eStringTable, "");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* generate encoding statements for a simple value */
|
|
void
|
|
GenPEREncSimpleType(AssignmentList_t ass, PERTypeInfo_t *info, char *valref, char *encref)
|
|
{
|
|
uint32_t i;
|
|
char lbbuf[256], ubbuf[256];
|
|
char *lenref;
|
|
char lenbuf[256], valbuf[256];
|
|
char *p;
|
|
PERTypeInfo_t inf;
|
|
|
|
inf = *info;
|
|
|
|
/* examine type for special handling */
|
|
switch (inf.Root.Data) {
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
if (inf.Root.cbFixedSizeBitString)
|
|
{
|
|
sprintf(lenbuf, "%u", inf.Root.LUpperVal);
|
|
sprintf(valbuf, "&(%s)", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
}
|
|
|
|
// lonchanc: intentionally fall through
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
if (inf.Root.Data == ePERSTIData_OctetString && inf.Type == eExtension_Unextended)
|
|
{
|
|
switch (inf.Root.Length)
|
|
{
|
|
case ePERSTILength_NoLength:
|
|
if (inf.Root.LConstraint == ePERSTIConstraint_Constrained &&
|
|
inf.Root.LLowerVal == inf.Root.LUpperVal &&
|
|
inf.Root.LUpperVal < 64 * 1024)
|
|
{
|
|
// fixed size constraint, eg. OCTET STRING (SIZE (8))
|
|
if (inf.pPrivateDirectives->fLenPtr)
|
|
{
|
|
output("if (!ASN1PEREncOctetString_FixedSizeEx(%s, %s, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PEREncOctetString_FixedSize(%s, (ASN1octetstring2_t *) %s, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal);
|
|
}
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
break;
|
|
case ePERSTILength_Length:
|
|
break;
|
|
case ePERSTILength_BitLength:
|
|
if (inf.Root.LConstraint == ePERSTIConstraint_Constrained &&
|
|
inf.Root.LLowerVal < inf.Root.LUpperVal &&
|
|
inf.Root.LUpperVal < 64 * 1024)
|
|
{
|
|
// variable size constraint, eg. OCTET STRING (SIZE (4..16))
|
|
if (inf.pPrivateDirectives->fLenPtr)
|
|
{
|
|
output("if (!ASN1PEREncOctetString_VarSizeEx(%s, %s, %u, %u, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal, inf.Root.LUpperVal, inf.Root.LNBits);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PEREncOctetString_VarSize(%s, (ASN1octetstring2_t *) %s, %u, %u, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal, inf.Root.LUpperVal, inf.Root.LNBits);
|
|
}
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
break;
|
|
case ePERSTILength_SmallLength:
|
|
break;
|
|
case ePERSTILength_InfiniteLength: // no size constraint, eg OCTET STRING
|
|
/* encode octet string in fragmented format */
|
|
output("if (!ASN1PEREncOctetString_NoSize(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
return;
|
|
} // switch
|
|
} // if
|
|
}
|
|
|
|
/* length and value of bit string, octet string and string */
|
|
sprintf(lenbuf, "(%s).length", valref);
|
|
sprintf(valbuf, "(%s).value", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* length and value of bit string, octet string and string */
|
|
sprintf(lenbuf, "(%s).length", valref);
|
|
sprintf(valbuf, "(%s).value", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_TableString:
|
|
|
|
/* length and value of bit string, octet string and string */
|
|
sprintf(lenbuf, "(%s).length", valref);
|
|
sprintf(valbuf, "(%s).value", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
|
|
case ePERSTIData_SequenceOf:
|
|
case ePERSTIData_SetOf:
|
|
|
|
if (inf.Rules & eTypeRules_PointerArrayMask)
|
|
{
|
|
/* length and value of sequence of/set of value with */
|
|
/* length-pointer representation */
|
|
if (inf.Rules & eTypeRules_PointerToElement)
|
|
{
|
|
sprintf(lenbuf, "(%s)->count", valref);
|
|
sprintf(valbuf, "(%s)->%s", valref, GetPrivateValueName(inf.pPrivateDirectives, "value"));
|
|
}
|
|
else
|
|
{
|
|
sprintf(lenbuf, "(%s)->count", Reference(valref));
|
|
sprintf(valbuf, "(%s)->%s", Reference(valref), GetPrivateValueName(inf.pPrivateDirectives, "value"));
|
|
}
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
}
|
|
else
|
|
if (inf.Rules & eTypeRules_LinkedListMask)
|
|
{
|
|
/* use a loop for sequence of/set of value with */
|
|
/* list representation */
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
if (PerOptCase_IsTargetSeqOf(&inf))
|
|
{
|
|
// generate the iterator
|
|
char szElmFn[128];
|
|
char szElmFnDecl[256];
|
|
sprintf(szElmFn, "ASN1Enc_%s_ElmFn", inf.Identifier);
|
|
sprintf(szElmFnDecl, "int ASN1CALL %s(ASN1encoding_t %s, P%s val)",
|
|
szElmFn, encref, inf.Identifier);
|
|
|
|
setoutfile(g_finc);
|
|
output("extern %s;\n", szElmFnDecl);
|
|
setoutfile(g_fout);
|
|
|
|
if ((inf.Root.LLowerVal == 0 && inf.Root.LUpperVal == 0) ||
|
|
(inf.Root.LUpperVal >= 64 * 1024)
|
|
)
|
|
{
|
|
output("return ASN1PEREncSeqOf_NoSize(%s, (ASN1iterator_t **) %s, (ASN1iterator_encfn) %s);\n",
|
|
encref, Reference(valref), szElmFn);
|
|
}
|
|
else
|
|
{
|
|
if (inf.Root.LLowerVal == inf.Root.LUpperVal)
|
|
MyAbort();
|
|
output("return ASN1PEREncSeqOf_VarSize(%s, (ASN1iterator_t **) %s, (ASN1iterator_encfn) %s, %u, %u, %u);\n",
|
|
encref, Reference(valref), szElmFn,
|
|
inf.Root.LLowerVal, inf.Root.LUpperVal, inf.Root.LNBits);
|
|
}
|
|
output("}\n\n"); // end of iterator body
|
|
|
|
// generate the element function
|
|
output("static %s\n", szElmFnDecl);
|
|
output("{\n");
|
|
sprintf(valbuf, "val->%s", GetPrivateValueName(inf.pPrivateDirectives, "value"));
|
|
GenPERFuncSimpleType(ass, &inf.Root.SubType->PERTypeInfo, valbuf,
|
|
eEncode, encref);
|
|
// end of element body
|
|
return;
|
|
}
|
|
}
|
|
|
|
outputvar("ASN1uint32_t t;\n");
|
|
outputvar("P%s f;\n", inf.Identifier);
|
|
output("for (t = 0, f = %s; f; f = f->next)\n", valref);
|
|
output("t++;\n");
|
|
lenref = "t";
|
|
|
|
} else {
|
|
MyAbort();
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_ZeroString:
|
|
case ePERSTIData_ZeroTableString:
|
|
|
|
/* length of a zero-terminated string value */
|
|
outputvar("ASN1uint32_t t;\n");
|
|
output("t = lstrlenA(%s);\n", valref);
|
|
lenref = "t";
|
|
break;
|
|
|
|
case ePERSTIData_Boolean:
|
|
|
|
/* value of a boolean value */
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
if (PerOptCase_IsBoolean(&inf.Root))
|
|
{
|
|
lenref = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sprintf(valbuf, "(%s) ? 1 : 0", valref);
|
|
valref = valbuf;
|
|
lenref = NULL;
|
|
inf.Root.Data = ePERSTIData_Unsigned;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* other values have no additional length */
|
|
lenref = NULL;
|
|
break;
|
|
}
|
|
|
|
/* map enumeration values */
|
|
if (inf.EnumerationValues) {
|
|
outputvar("ASN1uint32_t u;\n");
|
|
output("switch (%s) {\n", valref);
|
|
for (i = 0; inf.EnumerationValues[i]; i++) {
|
|
output("case %u:\n", intx2uint32(inf.EnumerationValues[i]));
|
|
output("u = %u;\n", i);
|
|
output("break;\n");
|
|
}
|
|
output("}\n");
|
|
valref = "u";
|
|
inf.NOctets = 4;
|
|
}
|
|
|
|
/* check for extended values */
|
|
if (inf.Type == eExtension_Extended) {
|
|
switch (inf.Root.Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
switch (inf.Root.Constraint) {
|
|
case ePERSTIConstraint_Unconstrained:
|
|
inf.Type = eExtension_Extendable;
|
|
break;
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
if (inf.NOctets == 0) {
|
|
sprintf(lbbuf, "%s_lb", inf.Identifier);
|
|
outputvarintx(lbbuf, &inf.Root.LowerVal);
|
|
output("if (ASN1intx_cmp(%s, &%s) >= 0) {\n",
|
|
Reference(valref), lbbuf);
|
|
} else if (inf.Root.Data == ePERSTIData_Integer) {
|
|
output("if (%s >= %d) {\n",
|
|
valref, intx2int32(&inf.Root.LowerVal));
|
|
} else {
|
|
if (intx2uint32(&inf.Root.LowerVal) > 0) {
|
|
output("if (%s >= %u) {\n",
|
|
valref, intx2uint32(&inf.Root.LowerVal));
|
|
} else {
|
|
inf.Type = eExtension_Extendable;
|
|
}
|
|
}
|
|
break;
|
|
case ePERSTIConstraint_Upperconstrained:
|
|
if (inf.NOctets == 0) {
|
|
sprintf(ubbuf, "%s_ub", inf.Identifier);
|
|
outputvarintx(ubbuf, &inf.Root.UpperVal);
|
|
output("if (ASN1intx_cmp(%s, &%s) <= 0) {\n",
|
|
Reference(valref), ubbuf);
|
|
} else if (inf.Root.Data == ePERSTIData_Integer) {
|
|
output("if (%s <= %d) {\n",
|
|
valref, intx2int32(&inf.Root.UpperVal));
|
|
} else {
|
|
output("if (%s <= %u) {\n",
|
|
valref, intx2uint32(&inf.Root.UpperVal));
|
|
}
|
|
break;
|
|
case ePERSTIConstraint_Constrained:
|
|
if (inf.NOctets == 0) {
|
|
sprintf(lbbuf, "%s_lb", inf.Identifier);
|
|
sprintf(ubbuf, "%s_ub", inf.Identifier);
|
|
outputvarintx(lbbuf, &inf.Root.LowerVal);
|
|
outputvarintx(ubbuf, &inf.Root.UpperVal);
|
|
output("if (ASN1intx_cmp(%s, &%s) >= 0 && ASN1intx_cmp(%s, &%s) <= 0) {\n",
|
|
Reference(valref), lbbuf, Reference(valref), ubbuf);
|
|
} else if (inf.Root.Data == ePERSTIData_Integer) {
|
|
output("if (%s >= %d && %s <= %d) {\n",
|
|
valref, intx2int32(&inf.Root.LowerVal),
|
|
valref, intx2int32(&inf.Root.UpperVal));
|
|
} else {
|
|
if (intx2uint32(&inf.Root.LowerVal) > 0) {
|
|
output("if (%s >= %u && %s <= %u) {\n",
|
|
valref, intx2uint32(&inf.Root.LowerVal),
|
|
valref, intx2uint32(&inf.Root.UpperVal));
|
|
} else {
|
|
output("if (%s <= %u) {\n",
|
|
valref, intx2uint32(&inf.Root.UpperVal));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case ePERSTIData_SequenceOf:
|
|
case ePERSTIData_SetOf:
|
|
case ePERSTIData_OctetString:
|
|
case ePERSTIData_UTF8String:
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
case ePERSTIData_Extension:
|
|
switch (inf.Root.LConstraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
if (inf.Root.LLowerVal != 0) {
|
|
output("if (%s >= %u) {\n",
|
|
lenref, inf.Root.LLowerVal);
|
|
} else {
|
|
inf.Type = eExtension_Extendable;
|
|
}
|
|
break;
|
|
case ePERSTIConstraint_Constrained:
|
|
if (inf.Root.LLowerVal != 0) {
|
|
output("if (%s >= %u && %s <= %u) {\n",
|
|
lenref, inf.Root.LLowerVal, lenref, inf.Root.LUpperVal);
|
|
} else {
|
|
output("if (%s <= %u) {\n",
|
|
lenref, inf.Root.LUpperVal);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_TableString:
|
|
case ePERSTIData_ZeroString:
|
|
case ePERSTIData_ZeroTableString:
|
|
inf.Type = eExtension_Extendable;
|
|
switch (inf.Root.LConstraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
if (inf.Root.LLowerVal != 0) {
|
|
output("if (%s >= %u",
|
|
lenref, inf.Root.LLowerVal);
|
|
inf.Type = eExtension_Extended;
|
|
}
|
|
break;
|
|
case ePERSTIConstraint_Constrained:
|
|
output("if (%s >= %u && %s <= %u",
|
|
lenref, inf.Root.LLowerVal, lenref, inf.Root.LUpperVal);
|
|
inf.Type = eExtension_Extended;
|
|
break;
|
|
}
|
|
if (inf.Root.TableIdentifier) {
|
|
if (inf.Type == eExtension_Extended)
|
|
output(" && ");
|
|
else
|
|
output("if (");
|
|
if (inf.NOctets == 1) {
|
|
p = "Char";
|
|
} else if (inf.NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (inf.NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
output("ASN1PEREncCheckTable%sString(%s, %s, %s)",
|
|
p, lenref, valref, Reference(inf.Root.TableIdentifier));
|
|
inf.Type = eExtension_Extended;
|
|
}
|
|
if (inf.Type == eExtension_Extended)
|
|
output(") {\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* encode unset extension bit */
|
|
if (inf.Type > eExtension_Unextended) {
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
output("if (!ASN1PEREncExtensionBitClear(%s))\n", encref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PEREncBitVal(%s, 1, 0))\n", encref);
|
|
}
|
|
output("return 0;\n");
|
|
}
|
|
|
|
/* encode unextended value (of extension root) */
|
|
GenPEREncGenericUnextended(ass, &inf, &inf.Root, valref, lenref, encref);
|
|
|
|
/* type is extended? */
|
|
if (inf.Type == eExtension_Extended) {
|
|
output("} else {\n");
|
|
|
|
/* encode set extension bit */
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
output("if (!ASN1PEREncExtensionBitSet(%s))\n", encref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PEREncBitVal(%s, 1, 1))\n", encref);
|
|
}
|
|
output("return 0;\n");
|
|
|
|
/* encode extended value (of extension addition) */
|
|
GenPEREncGenericUnextended(ass, &inf, &inf.Additional, valref, lenref, encref);
|
|
output("}\n");
|
|
}
|
|
}
|
|
|
|
/* generate encoding statements for a simple value (after some special */
|
|
/* handling has been done, esp. the evaluation of the extension) */
|
|
void GenPEREncGenericUnextended(AssignmentList_t ass, PERTypeInfo_t *info, PERSimpleTypeInfo_t *sinfo, char *valref, char *lenref, char *encref)
|
|
{
|
|
char valbuf[256];
|
|
char *lvref, lvbuf[256];
|
|
char lbbuf[256];
|
|
char *p;
|
|
|
|
/* check for empty field */
|
|
if (sinfo->NBits == 0)
|
|
return;
|
|
|
|
/* initial calculations for value encoding: */
|
|
/* substract lower bound of constraint/semiconstraint value */
|
|
/* for Integer and NormallySmall */
|
|
switch (sinfo->Constraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
case ePERSTIConstraint_Constrained:
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
case ePERSTIData_NormallySmall:
|
|
if (!info->NOctets) {
|
|
|
|
/* calculate value-lowerbound for intx_t values */
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0) != 0) {
|
|
sprintf(lbbuf, "%s_lb", info->Identifier);
|
|
outputvar("ASN1intx_t newval;\n");
|
|
outputvarintx(lbbuf, &sinfo->LowerVal);
|
|
output("ASN1intx_sub(&newval, %s, &%s);\n",
|
|
Reference(valref), lbbuf);
|
|
valref = "newval";
|
|
}
|
|
} else if (sinfo->Data == ePERSTIData_Integer) {
|
|
|
|
/* calculate value-lowerbound for intx_t values */
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0)) {
|
|
char szLowB[24];
|
|
sprintf(&szLowB[0], "%d", intx2int32(&sinfo->LowerVal));
|
|
if (szLowB[0] == '-')
|
|
sprintf(valbuf, "%s + %s", valref, &szLowB[1]); // minus minus become plus
|
|
else
|
|
sprintf(valbuf, "%s - %s", valref, &szLowB[0]);
|
|
valref = valbuf;
|
|
}
|
|
} else {
|
|
|
|
/* calculate value-lowerbound for integer values */
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0)) {
|
|
sprintf(valbuf, "%s - %u", valref, intx2uint32(&sinfo->LowerVal));
|
|
valref = valbuf;
|
|
}
|
|
}
|
|
|
|
/* semiconstraint/constraint values will be encoded as unsigned */
|
|
if (sinfo->Data == ePERSTIData_Integer)
|
|
sinfo->Data = ePERSTIData_Unsigned;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* general rules */
|
|
if (sinfo->LAlignment == ePERSTIAlignment_OctetAligned &&
|
|
sinfo->Length == ePERSTILength_BitLength &&
|
|
!(sinfo->LNBits & 7))
|
|
sinfo->Alignment = ePERSTIAlignment_BitAligned;
|
|
/* octet alignment will be given by length */
|
|
if (sinfo->Length == ePERSTILength_InfiniteLength &&
|
|
(sinfo->Data == ePERSTIData_Integer && info->NOctets == 0 ||
|
|
sinfo->Data == ePERSTIData_Unsigned && info->NOctets == 0 ||
|
|
sinfo->Data == ePERSTIData_BitString ||
|
|
sinfo->Data == ePERSTIData_RZBBitString ||
|
|
sinfo->Data == ePERSTIData_Extension ||
|
|
sinfo->Data == ePERSTIData_OctetString ||
|
|
sinfo->Data == ePERSTIData_UTF8String ||
|
|
sinfo->Data == ePERSTIData_SequenceOf ||
|
|
sinfo->Data == ePERSTIData_SetOf ||
|
|
sinfo->Data == ePERSTIData_String ||
|
|
sinfo->Data == ePERSTIData_TableString ||
|
|
sinfo->Data == ePERSTIData_ZeroString ||
|
|
sinfo->Data == ePERSTIData_ZeroTableString) ||
|
|
sinfo->Data == ePERSTIData_ObjectIdentifier ||
|
|
sinfo->Data == ePERSTIData_Real ||
|
|
sinfo->Data == ePERSTIData_GeneralizedTime ||
|
|
sinfo->Data == ePERSTIData_UTCTime ||
|
|
sinfo->Data == ePERSTIData_External ||
|
|
sinfo->Data == ePERSTIData_EmbeddedPdv ||
|
|
sinfo->Data == ePERSTIData_MultibyteString ||
|
|
sinfo->Data == ePERSTIData_UnrestrictedString ||
|
|
sinfo->Data == ePERSTIData_Open)
|
|
sinfo->LAlignment = sinfo->Alignment = ePERSTIAlignment_BitAligned;
|
|
/* alignment will be done by encoding fn */
|
|
if (sinfo->Length == ePERSTILength_NoLength ||
|
|
sinfo->Length == ePERSTILength_SmallLength)
|
|
sinfo->LAlignment = ePERSTIAlignment_BitAligned;
|
|
/* no alignment of no/small length */
|
|
|
|
/* special initial calculations */
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* remove trailing zero-bits */
|
|
outputvar("ASN1uint32_t r;\n");
|
|
output("r = %s;\n", lenref);
|
|
output("ASN1PEREncRemoveZeroBits(&r, %s, %u);\n",
|
|
valref, sinfo->LLowerVal);
|
|
if (sinfo->LLowerVal) {
|
|
outputvar("ASN1uint32_t s;\n");
|
|
output("s = r < %u ? %u : r;\n", sinfo->LLowerVal, sinfo->LLowerVal);
|
|
lenref = "s";
|
|
} else {
|
|
lenref = "r";
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
// lonchanc: special handling for macro operations
|
|
if (PerOptCase_IsSignedInteger(sinfo))
|
|
{
|
|
output("if (!ASN1PEREncInteger(%s, %s))\n", encref, valref);
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
if (PerOptCase_IsUnsignedInteger(sinfo))
|
|
{
|
|
output("if (!ASN1PEREncUnsignedInteger(%s, %s))\n", encref, valref);
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
if (PerOptCase_IsUnsignedShort(sinfo))
|
|
{
|
|
output("if (!ASN1PEREncUnsignedShort(%s, %s))\n", encref, valref);
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
if (PerOptCase_IsBoolean(sinfo))
|
|
{
|
|
output("if (!ASN1PEREncBoolean(%s, %s))\n", encref, valref);
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* initial calculations for length: */
|
|
/* get length of integer numbers if length req. */
|
|
switch (sinfo->Length) {
|
|
case ePERSTILength_BitLength:
|
|
case ePERSTILength_InfiniteLength:
|
|
switch (sinfo->Constraint) {
|
|
case ePERSTIConstraint_Unconstrained:
|
|
case ePERSTIConstraint_Upperconstrained:
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
if (info->NOctets != 0) {
|
|
outputvar("ASN1uint32_t l;\n");
|
|
if (sinfo->Data == ePERSTIData_Integer)
|
|
output("l = ASN1int32_octets(%s);\n", valref);
|
|
else
|
|
output("l = ASN1uint32_octets(%s);\n", valref);
|
|
lenref = "l";
|
|
} else {
|
|
if (sinfo->Length != ePERSTILength_InfiniteLength) {
|
|
outputvar("ASN1uint32_t l;\n");
|
|
output("l = ASN1intx_octets(%s);\n",
|
|
Reference(valref));
|
|
lenref = "l";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
case ePERSTIConstraint_Constrained:
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
if (info->NOctets != 0) {
|
|
outputvar("ASN1uint32_t l;\n");
|
|
output("l = ASN1uint32_uoctets(%s);\n", valref);
|
|
lenref = "l";
|
|
} else {
|
|
if (sinfo->Length != ePERSTILength_InfiniteLength) {
|
|
outputvar("ASN1uint32_t l;\n");
|
|
output("l = ASN1intx_uoctets(%s);\n",
|
|
Reference(valref));
|
|
lenref = "l";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* initial settings for length enconding: */
|
|
/* substract lower bound of length from length */
|
|
if (sinfo->LLowerVal != 0 && lenref) {
|
|
sprintf(lvbuf, "%s - %u", lenref, sinfo->LLowerVal);
|
|
lvref = lvbuf;
|
|
} else {
|
|
lvref = lenref;
|
|
}
|
|
|
|
/* length encoding */
|
|
if (sinfo->LAlignment == ePERSTIAlignment_OctetAligned) {
|
|
output("ASN1PEREncAlignment(%s);\n", encref);
|
|
}
|
|
switch (sinfo->Length) {
|
|
case ePERSTILength_NoLength:
|
|
|
|
/* not length used */
|
|
break;
|
|
|
|
case ePERSTILength_BitLength:
|
|
|
|
/* length will be encoded in a bit field */
|
|
output("if (!ASN1PEREncBitVal(%s, %u, %s))\n",
|
|
encref, sinfo->LNBits, lvref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTILength_InfiniteLength:
|
|
|
|
/* infinite length case: encode length only for integer values, */
|
|
/* other length encodings will be the encoding function */
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
if (info->NOctets != 0) {
|
|
output("if (!ASN1PEREncBitVal(%s, 8, %s))\n",
|
|
encref, lvref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* special initial calculations */
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* real length of the bit string */
|
|
lenref = "r";
|
|
break;
|
|
}
|
|
|
|
/* value encoding */
|
|
switch (sinfo->Length) {
|
|
case ePERSTILength_NoLength:
|
|
|
|
/* encode alignment of the value */
|
|
if (sinfo->Alignment == ePERSTIAlignment_OctetAligned) {
|
|
output("ASN1PEREncAlignment(%s);\n", encref);
|
|
}
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* encode the value as bit field */
|
|
if (info->NOctets != 0) {
|
|
output("if (!ASN1PEREncBitVal(%s, %u, %s))\n",
|
|
encref, sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PEREncBitIntx(%s, %u, %s))\n",
|
|
encref, sinfo->NBits, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_NormallySmall:
|
|
|
|
/* encode the value as normally small number */
|
|
output("if (!ASN1PEREncNormallySmall(%s, %s))\n",
|
|
encref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* encode bit string in a bit field */
|
|
output("if (!ASN1PEREncBits(%s, %s, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
/* encode octet string in a bit field */
|
|
output("if (!ASN1PEREncBits(%s, %s * 8, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* encode octet string in a bit field */
|
|
output("if (!ASN1PEREncUTF8String(%s, %s, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_Extension:
|
|
|
|
/* encode extension bits in a bit field */
|
|
output("if (!ASN1PEREncBits(%s, %u, %s))\n",
|
|
encref, sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
|
|
/* same as BitLength encoding */
|
|
goto SetOfEncoding;
|
|
|
|
case ePERSTIData_SequenceOf:
|
|
|
|
/* same as BitLength encoding */
|
|
goto SequenceOfEncoding;
|
|
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_ZeroString:
|
|
|
|
/* same as BitLength encoding */
|
|
goto StringEncoding;
|
|
|
|
case ePERSTIData_TableString:
|
|
case ePERSTIData_ZeroTableString:
|
|
|
|
/* same as BitLength encoding */
|
|
goto TableStringEncoding;
|
|
|
|
case ePERSTIData_Reference:
|
|
|
|
/* call encoding function of referenced type */
|
|
output("if (!ASN1Enc_%s(%s, %s))\n",
|
|
Identifier2C(sinfo->SubIdentifier),
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_Real:
|
|
|
|
/* encode real value */
|
|
if (info->NOctets)
|
|
output("if (!ASN1PEREncDouble(%s, %s))\n",
|
|
encref, valref);
|
|
else
|
|
output("if (!ASN1PEREncReal(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_GeneralizedTime:
|
|
|
|
/* encode generalized time value */
|
|
output("if (!ASN1PEREncGeneralizedTime(%s, %s, %d))\n",
|
|
encref, Reference(valref), sinfo->NBits);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_UTCTime:
|
|
|
|
/* encode utc time value */
|
|
output("if (!ASN1PEREncUTCTime(%s, %s, %d))\n",
|
|
encref, Reference(valref), sinfo->NBits);
|
|
output("return 0;\n");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ePERSTILength_BitLength:
|
|
|
|
/* encode alignment of the value */
|
|
if (sinfo->Alignment == ePERSTIAlignment_OctetAligned) {
|
|
output("ASN1PEREncAlignment(%s);\n", encref);
|
|
}
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* encode the value as bit field */
|
|
if (info->NOctets != 0) {
|
|
output("if (!ASN1PEREncBitVal(%s, %s * 8, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PEREncBitIntx(%s, %s * 8, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* encode the value as bit field */
|
|
output("if (!ASN1PEREncBits(%s, %s, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
/* encode the value as bit field */
|
|
output("if (!ASN1PEREncBits(%s, %s * 8, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* encode the value as bit field */
|
|
output("if (!ASN1PEREncUTF8String(%s, %s, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
SetOfEncoding:
|
|
|
|
/* skip null set of */
|
|
if (sinfo->SubType->Flags & eTypeFlags_Null)
|
|
break;
|
|
|
|
/* canonical PER? */
|
|
if (g_eSubEncodingRule == eSubEncoding_Canonical) {
|
|
|
|
/* encode the elements one by one and sort them */
|
|
outputvar("ASN1uint32_t i;\n");
|
|
outputvar("ASN1encoding_t e, *p;\n");
|
|
if (info->Rules &
|
|
(eTypeRules_SinglyLinkedList | eTypeRules_DoublyLinkedList))
|
|
MyAbort(); /*XXX*/
|
|
output("if (%s) {\n", lenref);
|
|
output("e = p = (ASN1encoding_t)malloc(%s * sizeof(ASN1encoding_t));\n",
|
|
lenref);
|
|
output("ZeroMemory(b, %s * sizeof(ASN1encoding_t));\n", lenref);
|
|
output("for (i = 0; i < %s; i++, p++) {\n", lenref);
|
|
sprintf(valbuf, "(%s)[i]", valref);
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, valbuf, eEncode, encref);
|
|
output("}\n");
|
|
output("qsort(e, %s, sizeof(ASN1encoding_t), ASN1PEREncCmpEncodings);\n",
|
|
lenref);
|
|
output("}\n");
|
|
|
|
/* then dump them */
|
|
output("for (p = e, i = 0; i < %s; i++, p++) {\n", lenref);
|
|
output("if (!ASN1PEREncBits(%s, (p->pos - p->buf) * 8 + p->bit, p->buf))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
break;
|
|
}
|
|
|
|
/* again in non-canonical PER: */
|
|
/*FALLTHROUGH*/
|
|
case ePERSTIData_SequenceOf:
|
|
SequenceOfEncoding:
|
|
|
|
/* skip null sequence of */
|
|
if (sinfo->SubType->Flags & eTypeFlags_Null)
|
|
break;
|
|
|
|
if (info->Rules & eTypeRules_PointerArrayMask)
|
|
{
|
|
/* loop over all elements */
|
|
outputvar("ASN1uint32_t i;\n");
|
|
output("for (i = 0; i < %s; i++) {\n", lenref);
|
|
sprintf(valbuf, "(%s)[i]", valref);
|
|
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_LinkedListMask)
|
|
{
|
|
/* iterate over all elements */
|
|
outputvar("P%s f;\n", info->Identifier);
|
|
output("for (f = %s; f; f = f->next) {\n", valref);
|
|
sprintf(valbuf, "f->%s", GetPrivateValueName(info->pPrivateDirectives, "value"));
|
|
}
|
|
|
|
/* encode the element */
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, valbuf,
|
|
eEncode, encref);
|
|
|
|
/* loop end */
|
|
output("}\n");
|
|
break;
|
|
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_ZeroString:
|
|
StringEncoding:
|
|
|
|
/* encode string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
output("if (!ASN1PEREnc%sString(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, valref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_TableString:
|
|
case ePERSTIData_ZeroTableString:
|
|
TableStringEncoding:
|
|
|
|
/* encode table string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
output("if (!ASN1PEREncTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, valref, sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
output("return 0;\n");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ePERSTILength_InfiniteLength:
|
|
/* infinite length case */
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* encode an integer in fragmented format */
|
|
if (info->NOctets != 0) {
|
|
output("if (!ASN1PEREncBitVal(%s, %s * 8, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
} else {
|
|
if (sinfo->Data == ePERSTIData_Integer) {
|
|
output("if (!ASN1PEREncFragmentedIntx(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PEREncFragmentedUIntx(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* encode bit string in fragmented format */
|
|
output("if (!ASN1PEREncFragmented(%s, %s, %s, 1))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
/* encode octet string in fragmented format */
|
|
output("if (!ASN1PEREncFragmented(%s, %s, %s, 8))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* encode octet string in fragmented format */
|
|
output("if (!ASN1PEREncUTF8String(%s, %s, %s))\n",
|
|
encref, lenref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_Extension:
|
|
|
|
/* encode extension bits in fragmented format */
|
|
output("if (!ASN1PEREncFragmented(%s, %u, %s, 1))\n",
|
|
encref, sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
|
|
/* skip null set of */
|
|
if (sinfo->SubType->Flags & eTypeFlags_Null)
|
|
break;
|
|
|
|
/* canonical PER? */
|
|
if (g_eSubEncodingRule == eSubEncoding_Canonical) {
|
|
|
|
/* encode the elements one by one and sort them */
|
|
outputvar("ASN1uint32_t i;\n");
|
|
outputvar("ASN1uint32_t j, n = 0x4000;\n");
|
|
outputvar("ASN1encoding_t e, *p;\n");
|
|
if (info->Rules &
|
|
(eTypeRules_SinglyLinkedList | eTypeRules_DoublyLinkedList))
|
|
MyAbort(); /*XXX*/
|
|
output("if (%s) {\n", lenref);
|
|
output("e = p = (ASN1encoding_t)malloc(%s * sizeof(ASN1encoding_t));\n",
|
|
lenref);
|
|
output("ZeroMemory(b, %s * sizeof(ASN1encoding_t));\n", lenref);
|
|
output("for (i = 0; i < %s; i++, p++) {\n", lenref);
|
|
sprintf(valbuf, "(%s)[i]", valref);
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, valbuf, eEncode, encref);
|
|
output("}\n");
|
|
output("qsort(e, %s, sizeof(ASN1encoding_t), ASN1PEREncCmpEncodings);\n",
|
|
lenref);
|
|
output("}\n");
|
|
|
|
/* then dump them */
|
|
output("for (p = e, i = 0; i < %s; i += n) {\n", lenref);
|
|
output("if (!ASN1PEREncFragmentedLength(&n, %s, %s - i))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
output("for (j = 0; j < n; p++, j++) {\n");
|
|
output("if (!ASN1PEREncBits(%s, (p->pos - p->buf) * 8 + p->bit, p->buf))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
output("}\n");
|
|
output("}\n");
|
|
output("if (n >= 0x4000) {\n");
|
|
output("if (!ASN1PEREncFragmentedLength(&n, %s, 0))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
break;
|
|
}
|
|
|
|
/* again in non-canonical PER: */
|
|
/*FALLTHROUGH*/
|
|
case ePERSTIData_SequenceOf:
|
|
|
|
/* skip null sequence of */
|
|
if (sinfo->SubType->Flags & eTypeFlags_Null)
|
|
break;
|
|
outputvar("ASN1uint32_t i;\n");
|
|
outputvar("ASN1uint32_t j, n = 0x4000;\n");
|
|
|
|
if (info->Rules &
|
|
(eTypeRules_SinglyLinkedList | eTypeRules_DoublyLinkedList)) {
|
|
|
|
/* additional iterator needed */
|
|
outputvar("P%s f;\n", info->Identifier);
|
|
output("f = %s;\n", valref);
|
|
}
|
|
|
|
/* encode all elements */
|
|
output("for (i = 0; i < %s;) {\n", lenref);
|
|
|
|
/* encode fragmented length */
|
|
output("if (!ASN1PEREncFragmentedLength(&n, %s, %s - i))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
|
|
/* encode elements of the fragment */
|
|
output("for (j = 0; j < n; i++, j++) {\n");
|
|
if (info->Rules & eTypeRules_PointerArrayMask)
|
|
{
|
|
sprintf(valbuf, "(%s)[i]", valref);
|
|
}
|
|
else if (info->Rules & eTypeRules_LinkedListMask)
|
|
{
|
|
sprintf(valbuf, "f->%s", GetPrivateValueName(info->pPrivateDirectives, "value"));
|
|
}
|
|
else
|
|
{
|
|
MyAbort();
|
|
}
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, valbuf,
|
|
eEncode, encref);
|
|
|
|
/* advance the iterator */
|
|
if (info->Rules & eTypeRules_LinkedListMask)
|
|
{
|
|
output("f = f->next;\n");
|
|
}
|
|
|
|
/* end of inner loop */
|
|
output("}\n");
|
|
|
|
/* end of outer loop */
|
|
output("}\n");
|
|
|
|
/* add an zero-sized fragment if needed */
|
|
output("if (n >= 0x4000) {\n");
|
|
output("if (!ASN1PEREncFragmentedLength(&n, %s, 0))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
break;
|
|
|
|
case ePERSTIData_ObjectIdentifier:
|
|
|
|
if (info->pPrivateDirectives->fOidArray || g_fOidArray)
|
|
{
|
|
/* encode object identifier value */
|
|
output("if (!ASN1PEREncObjectIdentifier2(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
else
|
|
{
|
|
/* encode object identifier value */
|
|
output("if (!ASN1PEREncObjectIdentifier(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_External:
|
|
|
|
/* encode external value */
|
|
output("if (!ASN1PEREncExternal(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_EmbeddedPdv:
|
|
|
|
/* encode embedded pdv value */
|
|
if (sinfo->Identification) {
|
|
output("if (!ASN1PEREncEmbeddedPdvOpt(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
} else {
|
|
output("if (!ASN1PEREncEmbeddedPdv(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_MultibyteString:
|
|
|
|
/* encode multibyte string value */
|
|
output("if (!ASN1PEREncMultibyteString(%s, %s))\n",
|
|
encref, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_UnrestrictedString:
|
|
|
|
/* encode character string value */
|
|
if (sinfo->Identification) {
|
|
output("if (!ASN1PEREncCharacterStringOpt(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
} else {
|
|
output("if (!ASN1PEREncCharacterString(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_ZeroString:
|
|
|
|
/* encode string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
output("if (!ASN1PEREncFragmented%sString(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, valref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_TableString:
|
|
case ePERSTIData_ZeroTableString:
|
|
|
|
/* encode table string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
output("if (!ASN1PEREncFragmentedTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, valref, sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_Open:
|
|
|
|
/* encode open type value */
|
|
output("if (!ASN1PEREncOpenType(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ePERSTILength_SmallLength:
|
|
/* small length */
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Extension:
|
|
/* encode extension bits with normally small length */
|
|
output("if (!ASN1PEREncNormallySmallBits(%s, %u, %s))\n",
|
|
encref, sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* encode additional zero bits for remove zero bits bit string */
|
|
/* of short length */
|
|
if (sinfo->LLowerVal) {
|
|
output("if (%s < %u) {\n", lenref, sinfo->LLowerVal);
|
|
output("if (!ASN1PEREncZero(%s, %u - %s))\n",
|
|
encref, sinfo->LLowerVal, lenref);
|
|
output("return 0;\n");
|
|
output("}\n");
|
|
}
|
|
}
|
|
|
|
/* free calculated intx_t value */
|
|
switch (sinfo->Constraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
case ePERSTIConstraint_Constrained:
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
case ePERSTIData_NormallySmall:
|
|
if (!info->NOctets) {
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0) != 0) {
|
|
output("ASN1intx_free(&newval);\n");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* generate decoding statements for a simple value */
|
|
void
|
|
GenPERDecSimpleType(AssignmentList_t ass, PERTypeInfo_t *info, char *valref, char *encref)
|
|
{
|
|
uint32_t i;
|
|
char *oldvalref;
|
|
char valbuf[256], lenbuf[256];
|
|
char *lenref;
|
|
PERTypeInfo_t inf;
|
|
|
|
inf = *info;
|
|
|
|
/* examine type for special handling */
|
|
switch (inf.Root.Data) {
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
if (inf.Root.cbFixedSizeBitString)
|
|
{
|
|
sprintf(lenbuf, "%u", inf.Root.LUpperVal);
|
|
sprintf(valbuf, "%s", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
}
|
|
|
|
// lonchanc: intentionally fall through
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
if (inf.Root.Data == ePERSTIData_OctetString && inf.Type == eExtension_Unextended)
|
|
{
|
|
switch (inf.Root.Length)
|
|
{
|
|
case ePERSTILength_NoLength:
|
|
if (inf.Root.LConstraint == ePERSTIConstraint_Constrained &&
|
|
inf.Root.LLowerVal == inf.Root.LUpperVal &&
|
|
inf.Root.LUpperVal < 64 * 1024)
|
|
{
|
|
// fixed size constraint, eg. OCTET STRING (SIZE (8))
|
|
if (inf.pPrivateDirectives->fLenPtr)
|
|
{
|
|
output("if (!ASN1PERDecOctetString_FixedSizeEx(%s, %s, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecOctetString_FixedSize(%s, (ASN1octetstring2_t *) %s, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal);
|
|
}
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
break;
|
|
case ePERSTILength_Length:
|
|
break;
|
|
case ePERSTILength_BitLength:
|
|
if (inf.Root.LConstraint == ePERSTIConstraint_Constrained &&
|
|
inf.Root.LLowerVal < inf.Root.LUpperVal &&
|
|
inf.Root.LUpperVal < 64 * 1024)
|
|
{
|
|
// variable size constraint, eg. OCTET STRING (SIZE (4..16))
|
|
if (inf.pPrivateDirectives->fLenPtr)
|
|
{
|
|
output("if (!ASN1PERDecOctetString_VarSizeEx(%s, %s, %u, %u, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal, inf.Root.LUpperVal, inf.Root.LNBits);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecOctetString_VarSize(%s, (ASN1octetstring2_t *) %s, %u, %u, %u))\n",
|
|
encref, Reference(valref), inf.Root.LLowerVal, inf.Root.LUpperVal, inf.Root.LNBits);
|
|
}
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
break;
|
|
case ePERSTILength_SmallLength:
|
|
break;
|
|
case ePERSTILength_InfiniteLength: // no size constraint
|
|
/* get octet string as fragmented */
|
|
if (valref)
|
|
{
|
|
output("if (!ASN1PERDecOctetString_NoSize(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
break;
|
|
} // switch
|
|
} // if
|
|
}
|
|
|
|
/* length and value of bit string/octet string/string value */
|
|
sprintf(lenbuf, "(%s).length", valref);
|
|
sprintf(valbuf, "(%s).value", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* length and value of bit string/octet string/string value */
|
|
sprintf(lenbuf, "(%s).length", valref);
|
|
sprintf(valbuf, "(%s).value", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_TableString:
|
|
|
|
/* length and value of bit string/octet string/string value */
|
|
sprintf(lenbuf, "(%s).length", valref);
|
|
sprintf(valbuf, "(%s).value", valref);
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
break;
|
|
|
|
case ePERSTIData_SequenceOf:
|
|
case ePERSTIData_SetOf:
|
|
|
|
if (inf.Rules & eTypeRules_PointerArrayMask)
|
|
{
|
|
/* length and value of sequence of/set of value with */
|
|
/* length-pointer representation */
|
|
if (inf.Rules & eTypeRules_PointerToElement)
|
|
{
|
|
sprintf(lenbuf, "(%s)->count", valref);
|
|
sprintf(valbuf, "(%s)->%s", valref, GetPrivateValueName(inf.pPrivateDirectives, "value"));
|
|
}
|
|
else
|
|
{
|
|
sprintf(lenbuf, "(%s)->count", Reference(valref));
|
|
sprintf(valbuf, "(%s)->%s", Reference(valref), GetPrivateValueName(inf.pPrivateDirectives, "value"));
|
|
}
|
|
lenref = lenbuf;
|
|
valref = valbuf;
|
|
}
|
|
else
|
|
if (inf.Rules & eTypeRules_LinkedListMask)
|
|
{
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
if (PerOptCase_IsTargetSeqOf(&inf))
|
|
{
|
|
// generate the iterator
|
|
char szElmFn[128];
|
|
char szElmFnDecl[256];
|
|
sprintf(szElmFn, "ASN1Dec_%s_ElmFn", inf.Identifier);
|
|
sprintf(szElmFnDecl, "int ASN1CALL %s(ASN1decoding_t %s, P%s val)",
|
|
szElmFn, encref, inf.Identifier);
|
|
|
|
setoutfile(g_finc);
|
|
output("extern %s;\n", szElmFnDecl);
|
|
setoutfile(g_fout);
|
|
|
|
if ((inf.Root.LLowerVal == 0 && inf.Root.LUpperVal == 0) ||
|
|
(inf.Root.LUpperVal >= 64 * 1024)
|
|
)
|
|
{
|
|
output("return ASN1PERDecSeqOf_NoSize(%s, (ASN1iterator_t **) %s, (ASN1iterator_decfn) %s, sizeof(*%s));\n",
|
|
encref, Reference(valref), szElmFn, valref);
|
|
}
|
|
else
|
|
{
|
|
if (inf.Root.LLowerVal == inf.Root.LUpperVal)
|
|
MyAbort();
|
|
output("return ASN1PERDecSeqOf_VarSize(%s, (ASN1iterator_t **) %s, (ASN1iterator_decfn) %s, sizeof(*%s), %u, %u, %u);\n",
|
|
encref, Reference(valref), szElmFn, valref,
|
|
inf.Root.LLowerVal, inf.Root.LUpperVal, inf.Root.LNBits);
|
|
}
|
|
output("}\n\n"); // end of iterator body
|
|
|
|
// generate the element function
|
|
output("static %s\n", szElmFnDecl);
|
|
output("{\n");
|
|
sprintf(valbuf, "val->%s", GetPrivateValueName(inf.pPrivateDirectives, "value"));
|
|
GenPERFuncSimpleType(ass, &inf.Root.SubType->PERTypeInfo, valbuf,
|
|
eDecode, encref);
|
|
// end of element body
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* use a loop for sequence of/set of value with */
|
|
/* list representation */
|
|
outputvar("P%s *f;\n", inf.Identifier);
|
|
lenref = NULL;
|
|
|
|
} else {
|
|
MyAbort();
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_Extension:
|
|
|
|
/* length of extension */
|
|
if (inf.Root.Length == ePERSTILength_SmallLength)
|
|
lenref = "e";
|
|
else
|
|
lenref = NULL;
|
|
break;
|
|
|
|
case ePERSTIData_Boolean:
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
if (PerOptCase_IsBoolean(&inf.Root))
|
|
{
|
|
lenref = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* boolean value */
|
|
inf.Root.Data = ePERSTIData_Unsigned;
|
|
lenref = NULL;
|
|
break;
|
|
|
|
default:
|
|
|
|
/* other values have no additional length */
|
|
lenref = NULL;
|
|
break;
|
|
}
|
|
|
|
/* check for extended values */
|
|
if (inf.Type > eExtension_Unextended) {
|
|
outputvar("ASN1uint32_t x;\n");
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
output("if (!ASN1PERDecExtensionBit(%s, &x))\n", encref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecBit(%s, &x))\n", encref);
|
|
}
|
|
output("return 0;\n");
|
|
output("if (!x) {\n");
|
|
}
|
|
|
|
/* additional variable for enumeraton value mapping */
|
|
oldvalref = valref;
|
|
if (inf.EnumerationValues && valref) {
|
|
outputvar("ASN1uint32_t u;\n");
|
|
valref = "u";
|
|
inf.NOctets = 4;
|
|
}
|
|
|
|
/* decode unextended value (of extension root) */
|
|
GenPERDecGenericUnextended(ass, &inf, &inf.Root, valref, lenref, encref);
|
|
|
|
/* map enumeration values if type is extendable */
|
|
if (inf.EnumerationValues && oldvalref &&
|
|
inf.Type == eExtension_Extendable) {
|
|
output("switch (u) {\n");
|
|
for (i = 0; inf.EnumerationValues[i]; i++) {
|
|
output("case %u:\n", i);
|
|
output("%s = %u;\n", oldvalref, intx2uint32(inf.EnumerationValues[i]));
|
|
output("break;\n");
|
|
}
|
|
output("}\n");
|
|
}
|
|
|
|
/* type is extendable? */
|
|
if (inf.Type > eExtension_Unextended) {
|
|
output("} else {\n");
|
|
if (inf.Type == eExtension_Extendable)
|
|
valref = lenref = NULL;
|
|
|
|
/* decode extended value (of extension addition) */
|
|
GenPERDecGenericUnextended(ass, &inf, &inf.Additional, valref, lenref, encref);
|
|
output("}\n");
|
|
}
|
|
|
|
/* map enumeration values if type is unextended/extended */
|
|
if (inf.EnumerationValues && oldvalref &&
|
|
inf.Type != eExtension_Extendable) {
|
|
output("switch (u) {\n");
|
|
for (i = 0; inf.EnumerationValues[i]; i++) {
|
|
output("case %u:\n", i);
|
|
output("%s = %u;\n", oldvalref, intx2uint32(inf.EnumerationValues[i]));
|
|
output("break;\n");
|
|
}
|
|
output("}\n");
|
|
}
|
|
}
|
|
|
|
/* generate decoding statements for a simple value (after some special */
|
|
/* handling has been done, esp. the evaluation of the extension) */
|
|
void GenPERDecGenericUnextended(
|
|
AssignmentList_t ass,
|
|
PERTypeInfo_t *info,
|
|
PERSimpleTypeInfo_t *sinfo,
|
|
char *valref,
|
|
char *lenref,
|
|
char *encref)
|
|
{
|
|
char valbuf[256];
|
|
char lenbuf[256];
|
|
char lbbuf[256];
|
|
char *p;
|
|
char *oldvalref;
|
|
intx_t ix;
|
|
|
|
/* check for empty field */
|
|
if (sinfo->NBits == 0) {
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Null:
|
|
return;
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
if (valref && (sinfo->Constraint == ePERSTIConstraint_Semiconstrained || sinfo->Constraint == ePERSTIConstraint_Constrained)) {
|
|
if (info->NOctets == 0) {
|
|
sprintf(lbbuf, "%s_lb", info->Identifier);
|
|
outputvarintx(lbbuf, &sinfo->LowerVal);
|
|
output("ASN1intx_dup(%s, %s);\n", Reference(valref), lbbuf);
|
|
} else if (sinfo->Data == ePERSTIData_Integer) {
|
|
output("%s = %d;\n", valref, intx2int32(&sinfo->LowerVal));
|
|
} else {
|
|
output("%s = %u;\n", valref, intx2uint32(&sinfo->LowerVal));
|
|
}
|
|
}
|
|
return;
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
case ePERSTIData_OctetString:
|
|
case ePERSTIData_UTF8String:
|
|
case ePERSTIData_SequenceOf:
|
|
case ePERSTIData_SetOf:
|
|
case ePERSTIData_String:
|
|
case ePERSTIData_TableString:
|
|
case ePERSTIData_ZeroString:
|
|
case ePERSTIData_ZeroTableString:
|
|
if (lenref)
|
|
output("%s = 0;\n", lenref);
|
|
return;
|
|
case ePERSTIData_Extension:
|
|
if (sinfo->Length == ePERSTILength_SmallLength)
|
|
break;
|
|
return;
|
|
default:
|
|
MyAbort();
|
|
}
|
|
}
|
|
|
|
/* check for decoding of non-negative-binary-integer */
|
|
switch (sinfo->Constraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
case ePERSTIConstraint_Constrained:
|
|
if (sinfo->Data == ePERSTIData_Integer)
|
|
sinfo->Data = ePERSTIData_Unsigned;
|
|
break;
|
|
}
|
|
|
|
/* use newval for dec of semiconstraint/constraint intx_t with lb != 0 */
|
|
switch (sinfo->Constraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
case ePERSTIConstraint_Constrained:
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
case ePERSTIData_NormallySmall:
|
|
if (valref) {
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0) != 0) {
|
|
if (info->NOctets == 0) {
|
|
outputvar("ASN1intx_t newval;\n");
|
|
oldvalref = valref;
|
|
valref = "newval";
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* general rules */
|
|
if (sinfo->LAlignment == ePERSTIAlignment_OctetAligned && sinfo->Length == ePERSTILength_BitLength &&
|
|
!(sinfo->LNBits & 7))
|
|
sinfo->Alignment = ePERSTIAlignment_BitAligned;
|
|
/* octet alignment will be given my length */
|
|
if (sinfo->Length == ePERSTILength_InfiniteLength &&
|
|
(sinfo->Data == ePERSTIData_Integer && info->NOctets == 0 ||
|
|
sinfo->Data == ePERSTIData_Unsigned && info->NOctets == 0 ||
|
|
sinfo->Data == ePERSTIData_BitString ||
|
|
sinfo->Data == ePERSTIData_RZBBitString ||
|
|
sinfo->Data == ePERSTIData_Extension ||
|
|
sinfo->Data == ePERSTIData_OctetString ||
|
|
sinfo->Data == ePERSTIData_UTF8String ||
|
|
sinfo->Data == ePERSTIData_SequenceOf ||
|
|
sinfo->Data == ePERSTIData_SetOf ||
|
|
sinfo->Data == ePERSTIData_String ||
|
|
sinfo->Data == ePERSTIData_TableString ||
|
|
sinfo->Data == ePERSTIData_ZeroString ||
|
|
sinfo->Data == ePERSTIData_ZeroTableString) ||
|
|
sinfo->Data == ePERSTIData_ObjectIdentifier ||
|
|
sinfo->Data == ePERSTIData_Real ||
|
|
sinfo->Data == ePERSTIData_GeneralizedTime ||
|
|
sinfo->Data == ePERSTIData_UTCTime ||
|
|
sinfo->Data == ePERSTIData_External ||
|
|
sinfo->Data == ePERSTIData_EmbeddedPdv ||
|
|
sinfo->Data == ePERSTIData_MultibyteString ||
|
|
sinfo->Data == ePERSTIData_UnrestrictedString ||
|
|
sinfo->Data == ePERSTIData_Open)
|
|
sinfo->LAlignment = sinfo->Alignment = ePERSTIAlignment_BitAligned;
|
|
/* alignment will be done by encoding fn */
|
|
if (sinfo->Length == ePERSTILength_NoLength ||
|
|
sinfo->Length == ePERSTILength_SmallLength)
|
|
sinfo->LAlignment = ePERSTIAlignment_BitAligned;
|
|
/* no alignment of no length */
|
|
|
|
if (g_fCaseBasedOptimizer)
|
|
{
|
|
// lonchanc: special handling for macro operations
|
|
if (PerOptCase_IsSignedInteger(sinfo))
|
|
{
|
|
output("if (!ASN1PERDecInteger(%s, %s))\n", encref, Reference(valref));
|
|
output("return 0;\n");
|
|
goto FinalTouch;
|
|
}
|
|
if (PerOptCase_IsUnsignedInteger(sinfo))
|
|
{
|
|
output("if (!ASN1PERDecUnsignedInteger(%s, %s))\n", encref, Reference(valref));
|
|
output("return 0;\n");
|
|
goto FinalTouch;
|
|
}
|
|
if (PerOptCase_IsUnsignedShort(sinfo))
|
|
{
|
|
output("if (!ASN1PERDecUnsignedShort(%s, %s))\n", encref, Reference(valref));
|
|
output("return 0;\n");
|
|
goto FinalTouch;
|
|
}
|
|
if (PerOptCase_IsBoolean(sinfo))
|
|
{
|
|
output("if (!ASN1PERDecBoolean(%s, %s))\n", encref, Reference(valref));
|
|
output("return 0;\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* initial settings for length enconding: */
|
|
/* add lower bound of length to length */
|
|
if (!lenref) {
|
|
if (sinfo->Length == ePERSTILength_NoLength &&
|
|
sinfo->Data != ePERSTIData_Extension) {
|
|
sprintf(lenbuf, "%u", sinfo->LLowerVal);
|
|
lenref = lenbuf;
|
|
} else if (sinfo->Data != ePERSTIData_ObjectIdentifier &&
|
|
sinfo->Data != ePERSTIData_External &&
|
|
sinfo->Data != ePERSTIData_EmbeddedPdv &&
|
|
sinfo->Data != ePERSTIData_MultibyteString &&
|
|
sinfo->Data != ePERSTIData_UnrestrictedString &&
|
|
sinfo->Data != ePERSTIData_Extension &&
|
|
(sinfo->Length != ePERSTILength_InfiniteLength ||
|
|
(sinfo->Data != ePERSTIData_SetOf &&
|
|
sinfo->Data != ePERSTIData_SequenceOf) ||
|
|
!IsStructuredType(GetType(ass, sinfo->SubType))) &&
|
|
((sinfo->Data != ePERSTIData_SetOf &&
|
|
sinfo->Data != ePERSTIData_SequenceOf) || valref) &&
|
|
(sinfo->Length != ePERSTILength_InfiniteLength ||
|
|
info->NOctets != 0 ||
|
|
(sinfo->Data != ePERSTIData_Integer &&
|
|
sinfo->Data != ePERSTIData_Unsigned)) &&
|
|
((sinfo->Data != ePERSTIData_ZeroString &&
|
|
sinfo->Data != ePERSTIData_ZeroTableString) ||
|
|
sinfo->Length != ePERSTILength_InfiniteLength) &&
|
|
(sinfo->Data != ePERSTIData_BitString &&
|
|
sinfo->Data != ePERSTIData_UTF8String &&
|
|
sinfo->Data != ePERSTIData_OctetString)) {
|
|
outputvar("ASN1uint32_t l;\n");
|
|
lenref = "l";
|
|
}
|
|
} else if (sinfo->Length == ePERSTILength_NoLength) {
|
|
if ((sinfo->Data == ePERSTIData_BitString ||
|
|
sinfo->Data == ePERSTIData_RZBBitString) &&
|
|
sinfo->cbFixedSizeBitString)
|
|
{
|
|
// lonchanc: doing nothing here because lenref is a constant number
|
|
}
|
|
else
|
|
{
|
|
output("%s = %u;\n", lenref, sinfo->LLowerVal);
|
|
}
|
|
}
|
|
|
|
/* length encoding */
|
|
if (sinfo->LAlignment == ePERSTIAlignment_OctetAligned) {
|
|
output("ASN1PERDecAlignment(%s);\n", encref);
|
|
}
|
|
switch (sinfo->Length) {
|
|
case ePERSTILength_NoLength:
|
|
break;
|
|
|
|
case ePERSTILength_BitLength:
|
|
|
|
/* get length */
|
|
output("if (!ASN1PERDecU32Val(%s, %u, %s))\n",
|
|
encref, sinfo->LNBits, Reference(lenref));
|
|
output("return 0;\n");
|
|
|
|
/* add lower bound of length */
|
|
if (sinfo->LLowerVal)
|
|
output("%s += %u;\n", lenref, sinfo->LLowerVal);
|
|
|
|
/*
|
|
if (sinfo->LConstraint == ePERSTIConstraint_Constrained) {
|
|
output("if (%s > %u)\n", lenref, sinfo->LUpperVal);
|
|
output("return ASN1DecError(%s, ASN1_ERR_CORRUPT);\n", encref);
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case ePERSTILength_InfiniteLength:
|
|
|
|
/* infinite length case */
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* get length of integer value */
|
|
if (info->NOctets != 0) {
|
|
output("if (!ASN1PERDecFragmentedLength(%s, %s))\n",
|
|
encref, Reference(lenref));
|
|
output("return 0;\n");
|
|
if (sinfo->LLowerVal)
|
|
output("%s += %u;\n", lenref, sinfo->LLowerVal);
|
|
/*
|
|
if (sinfo->LConstraint == ePERSTIConstraint_Constrained) {
|
|
output("if (%s > %u)\n", lenref, sinfo->LUpperVal);
|
|
output("return ASN1DecError(%s, ASN1_ERR_CORRUPT);\n",
|
|
encref);
|
|
}
|
|
*/
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* value decoding */
|
|
switch (sinfo->Length) {
|
|
case ePERSTILength_NoLength:
|
|
|
|
/* decode alignment of the value */
|
|
if (sinfo->Alignment == ePERSTIAlignment_OctetAligned) {
|
|
output("ASN1PERDecAlignment(%s);\n", encref);
|
|
}
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
|
|
/* decode the value as bit field */
|
|
if (valref) {
|
|
if (!info->NOctets) {
|
|
output("if (!ASN1PERDecSXVal(%s, %u, %s))\n",
|
|
info->NOctets * 8, encref, sinfo->NBits, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecS%dVal(%s, %u, %s))\n",
|
|
info->NOctets * 8, encref, sinfo->NBits, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* decode the value as bit field */
|
|
if (valref) {
|
|
if (!info->NOctets) {
|
|
output("if (!ASN1PERDecUXVal(%s, %u, %s))\n",
|
|
info->NOctets * 8, encref, sinfo->NBits, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecU%dVal(%s, %u, %s))\n",
|
|
info->NOctets * 8, encref, sinfo->NBits, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_NormallySmall:
|
|
|
|
/* decode the value as normally small number */
|
|
if (valref) {
|
|
if (!info->NOctets) {
|
|
MyAbort();
|
|
} else {
|
|
output("if (!ASN1PERDecN%dVal(%s, %s))\n",
|
|
info->NOctets * 8, encref, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
} else {
|
|
output("if (!ASN1PERDecSkipNormallySmall(%s))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* decode bit string in a bit field */
|
|
if (valref) {
|
|
if (sinfo->cbFixedSizeBitString)
|
|
{
|
|
output("if (!ASN1PERDecExtension(%s, %s, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecBits(%s, %s, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
/* decode octet string in a bit field */
|
|
if (valref) {
|
|
if (sinfo->LConstraint == ePERSTIConstraint_Constrained &&
|
|
(! info->pPrivateDirectives->fLenPtr))
|
|
{
|
|
output("if (!ASN1PERDecExtension(%s, %s * 8, %s))\n",
|
|
encref, lenref, valref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecBits(%s, %s * 8, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * 8))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* decode octet string in a bit field */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecUTF8String(%s, %s, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
MyAbort();
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_Extension:
|
|
|
|
/* decode extension bits in a bit field */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecExtension(%s, %u, %s))\n",
|
|
encref, sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
|
|
/* same as BitLength encoding */
|
|
goto SetOfEncoding;
|
|
|
|
case ePERSTIData_SequenceOf:
|
|
|
|
/* same as BitLength encoding */
|
|
goto SequenceOfEncoding;
|
|
|
|
case ePERSTIData_String:
|
|
|
|
/* same as BitLength encoding */
|
|
goto StringEncoding;
|
|
|
|
case ePERSTIData_ZeroString:
|
|
|
|
/* same as BitLength encoding */
|
|
goto ZeroStringEncoding;
|
|
|
|
case ePERSTIData_TableString:
|
|
|
|
/* same as BitLength encoding */
|
|
goto TableStringEncoding;
|
|
|
|
case ePERSTIData_ZeroTableString:
|
|
|
|
/* same as BitLength encoding */
|
|
goto ZeroTableStringEncoding;
|
|
|
|
case ePERSTIData_Reference:
|
|
|
|
/* call encoding function of referenced type */
|
|
if (valref) {
|
|
output("if (!ASN1Dec_%s(%s, %s))\n",
|
|
Identifier2C(sinfo->SubIdentifier),
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1Dec_%s(%s, NULL))\n",
|
|
Identifier2C(sinfo->SubIdentifier),
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_Real:
|
|
|
|
/* decode real value */
|
|
if (valref) {
|
|
if (info->NOctets)
|
|
output("if (!ASN1PERDecDouble(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
else
|
|
output("if (!ASN1PERDecReal(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_GeneralizedTime:
|
|
|
|
/* decode generalized time value */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecGeneralizedTime(%s, %s, %d))\n",
|
|
encref, Reference(valref), sinfo->NBits);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, %d))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_UTCTime:
|
|
|
|
/* decode utc time value */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecUTCTime(%s, %s, %d))\n",
|
|
encref, Reference(valref), sinfo->NBits);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, %d))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ePERSTILength_BitLength:
|
|
|
|
/* decode alignment of the value */
|
|
if (sinfo->Alignment == ePERSTIAlignment_OctetAligned) {
|
|
output("ASN1PERDecAlignment(%s);\n", encref);
|
|
}
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* decode the value as bit field */
|
|
if (valref) {
|
|
if (info->NOctets == 0 && sinfo->Data == ePERSTIData_Integer) {
|
|
output("if (!ASN1PERDecSXVal(%s, %s * 8, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else if (info->NOctets == 0 && sinfo->Data == ePERSTIData_Unsigned) {
|
|
output("if (!ASN1PERDecUXVal(%s, %s * 8, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else if (sinfo->Data == ePERSTIData_Integer) {
|
|
output("if (!ASN1PERDecS%dVal(%s, %s * 8, %s))\n",
|
|
info->NOctets * 8, encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecU%dVal(%s, %s * 8, %s))\n",
|
|
info->NOctets * 8, encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * 8))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* decode the value as bit field */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecBits(%s, %s, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
/* decode the value as bit field */
|
|
if (valref) {
|
|
if (sinfo->LConstraint == ePERSTIConstraint_Constrained &&
|
|
(! info->pPrivateDirectives->fLenPtr))
|
|
{
|
|
output("if (!ASN1PERDecExtension(%s, %s * 8, %s))\n",
|
|
encref, lenref, valref);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecBits(%s, %s * 8, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * 8))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* decode the value as bit field */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecUTF8String(%s, %s, %s))\n",
|
|
encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
MyAbort();
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
SetOfEncoding:
|
|
/*FALLTHROUGH*/
|
|
case ePERSTIData_SequenceOf:
|
|
SequenceOfEncoding:
|
|
|
|
/* skip null sequence of/set of */
|
|
if (sinfo->SubType->Flags & eTypeFlags_Null)
|
|
break;
|
|
|
|
outputvar("ASN1uint32_t i;\n");
|
|
if (!valref || (info->Rules & eTypeRules_PointerArrayMask))
|
|
{
|
|
// lonchanc: no need to allocate memory for eTypeRules_FixedArray
|
|
/* allocate memory for elements */
|
|
if (valref && (info->Rules & eTypeRules_LengthPointer))
|
|
{
|
|
output("if (!%s) {\n", lenref);
|
|
output("%s = NULL;\n", valref);
|
|
output("} else {\n");
|
|
output("if (!(%s = (%s *)ASN1DecAlloc(%s, %s * sizeof(%s))))\n",
|
|
valref, sinfo->SubIdentifier, encref,
|
|
lenref, Dereference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
|
|
/* decode elements */
|
|
output("for (i = 0; i < %s; i++) {\n", lenref);
|
|
if (valref) {
|
|
sprintf(valbuf, "(%s)[i]", valref);
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, valbuf, eDecode, encref);
|
|
} else {
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, NULL, eDecode, encref);
|
|
}
|
|
|
|
/* loop end */
|
|
output("}\n");
|
|
if (valref && (info->Rules & eTypeRules_LengthPointer))
|
|
output("}\n"); // closing bracket for else
|
|
}
|
|
else if (info->Rules & eTypeRules_SinglyLinkedList)
|
|
{
|
|
char szPrivateValueName[64];
|
|
sprintf(&szPrivateValueName[0], "(*f)->%s", GetPrivateValueName(info->pPrivateDirectives, "value"));
|
|
/* allocate and decode elements */
|
|
outputvar("P%s *f;\n", info->Identifier);
|
|
output("f = %s;\n", Reference(valref));
|
|
output("for (i = 0; i < %s; i++) {\n", lenref);
|
|
output("if (!(*f = (P%s)ASN1DecAlloc(%s, sizeof(**f))))\n",
|
|
info->Identifier, encref);
|
|
output("return 0;\n");
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, &szPrivateValueName[0],
|
|
eDecode, encref);
|
|
output("f = &(*f)->next;\n");
|
|
output("}\n");
|
|
output("*f = NULL;\n");
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_DoublyLinkedList)
|
|
{
|
|
char szPrivateValueName[64];
|
|
sprintf(&szPrivateValueName[0], "(*f)->%s", GetPrivateValueName(info->pPrivateDirectives, "value"));
|
|
/* allocate and decode elements */
|
|
outputvar("P%s *f;\n", info->Identifier);
|
|
outputvar("%s b;\n", info->Identifier);
|
|
output("f = %s;\n", Reference(valref));
|
|
output("b = NULL;\n");
|
|
output("for (i = 0; i < %s; i++) {\n", lenref);
|
|
output("if (!(*f = (P%s)ASN1DecAlloc(%s, sizeof(**f))))\n",
|
|
info->Identifier, encref);
|
|
output("return 0;\n");
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, &szPrivateValueName[0],
|
|
eDecode, encref);
|
|
output("f->prev = b;\n");
|
|
output("b = *f;\n");
|
|
output("f = &b->next;\n");
|
|
output("}\n");
|
|
output("*f = NULL;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_String:
|
|
StringEncoding:
|
|
|
|
/* decode string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
#ifdef ENABLE_CHAR_STR_SIZE
|
|
if (info->NOctets == 1 &&
|
|
info->Root.LConstraint == ePERSTIConstraint_Constrained)
|
|
{
|
|
output("if (!ASN1PERDec%sStringNoAlloc(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, valref, sinfo->NBits);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDec%sString(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits);
|
|
}
|
|
#else
|
|
output("if (!ASN1PERDec%sString(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits);
|
|
#endif
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * %u))\n",
|
|
encref, lenref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_ZeroString:
|
|
ZeroStringEncoding:
|
|
|
|
/* decode zero-terminated string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
#ifdef ENABLE_CHAR_STR_SIZE
|
|
if (info->NOctets == 1 &&
|
|
info->Root.LConstraint == ePERSTIConstraint_Constrained)
|
|
{
|
|
output("if (!ASN1PERDecZero%sStringNoAlloc(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, valref, sinfo->NBits);
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecZero%sString(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits);
|
|
}
|
|
#else
|
|
output("if (!ASN1PERDecZero%sString(%s, %s, %s, %u))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits);
|
|
#endif
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * %u))\n",
|
|
encref, lenref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_TableString:
|
|
TableStringEncoding:
|
|
|
|
/* decode table string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
#ifdef ENABLE_CHAR_STR_SIZE
|
|
if (info->NOctets == 1 &&
|
|
info->Root.LConstraint == ePERSTIConstraint_Constrained)
|
|
{
|
|
output("if (!ASN1PERDecTable%sStringNoAlloc(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, valref, sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
}
|
|
#else
|
|
output("if (!ASN1PERDecTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
#endif
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * %u, %s))\n",
|
|
encref, lenref, sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_ZeroTableString:
|
|
ZeroTableStringEncoding:
|
|
|
|
/* decode zero-terminated table string value */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
#ifdef ENABLE_CHAR_STR_SIZE
|
|
if (info->NOctets == 1 &&
|
|
info->Root.LConstraint == ePERSTIConstraint_Constrained)
|
|
{
|
|
output("if (!ASN1PERDecZeroTable%sStringNoAlloc(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, valref, sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecZeroTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
}
|
|
#else
|
|
output("if (!ASN1PERDecZeroTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, lenref, Reference(valref), sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
#endif
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * %u, %s))\n",
|
|
encref, lenref, sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ePERSTILength_InfiniteLength:
|
|
|
|
/* infinite length case */
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
|
|
/* get integer value as fragmented */
|
|
if (valref) {
|
|
if (info->NOctets == 0) {
|
|
if (sinfo->Data == ePERSTIData_Integer) {
|
|
output("if (!ASN1PERDecFragmentedIntx(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
} else {
|
|
output("if (!ASN1PERDecFragmentedUIntx(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
} else if (sinfo->Data == ePERSTIData_Integer) {
|
|
output("if (!ASN1PERDecS%dVal(%s, %s * 8, %s))\n",
|
|
info->NOctets * 8, encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecU%dVal(%s, %s * 8, %s))\n",
|
|
info->NOctets * 8, encref, lenref, Reference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
} else {
|
|
if (info->NOctets != 0) {
|
|
output("if (!ASN1PERDecSkipBits(%s, %s * 8))\n",
|
|
encref, lenref);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_Extension:
|
|
|
|
/* get extension bits as fragmented */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmentedExtension(%s, %u, %s))\n",
|
|
encref, sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 1))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_BitString:
|
|
case ePERSTIData_RZBBitString:
|
|
|
|
/* get bit string as fragmented */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmented(%s, %s, %s, 1))\n",
|
|
encref, Reference(lenref), Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 1))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_OctetString:
|
|
|
|
/* get octet string as fragmented */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmented(%s, %s, %s, 8))\n",
|
|
encref, Reference(lenref), Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_UTF8String:
|
|
|
|
/* get octet string as fragmented */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecUTF8StringEx(%s, %s, %s))\n",
|
|
encref, Reference(lenref), Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
MyAbort();
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_SetOf:
|
|
case ePERSTIData_SequenceOf:
|
|
|
|
/* we need some counters and iterators */
|
|
outputvar("ASN1uint32_t i;\n");
|
|
outputvar("ASN1uint32_t n;\n");
|
|
if (valref)
|
|
{
|
|
if (info->Rules & eTypeRules_LengthPointer)
|
|
{
|
|
output("%s = 0;\n", lenref);
|
|
output("%s = NULL;\n", valref);
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_FixedArray)
|
|
{
|
|
output("%s = 0;\n", lenref);
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_SinglyLinkedList)
|
|
{
|
|
outputvar("P%s *f;\n", info->Identifier);
|
|
output("f = %s;\n", Reference(valref));
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_DoublyLinkedList)
|
|
{
|
|
outputvar("P%s *f;\n", info->Identifier);
|
|
outputvar("%s b;\n", info->Identifier);
|
|
output("f = %s;\n", Reference(valref));
|
|
output("b = NULL;\n");
|
|
}
|
|
}
|
|
|
|
/* get all elements of the sequence of/set of */
|
|
output("do {\n");
|
|
|
|
/* get length of a fragment */
|
|
output("if (!ASN1PERDecFragmentedLength(%s, &n))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
|
|
if (valref)
|
|
{
|
|
if (info->Rules & eTypeRules_LengthPointer)
|
|
{
|
|
// lonchanc: no need to allocate memory for eTypeRules_FixedArray
|
|
/* resize memory for the element */
|
|
output("if (!(%s = (%s *)ASN1DecRealloc(%s, %s, (%s + n) * sizeof(%s))))\n",
|
|
valref, GetTypeName(ass, sinfo->SubType), encref,
|
|
valref, lenref, Dereference(valref));
|
|
output("return 0;\n");
|
|
}
|
|
}
|
|
|
|
/* get the elements of the fragment */
|
|
output("for (i = 0; i < n; i++) {\n");
|
|
if (valref) {
|
|
if (info->Rules & eTypeRules_PointerArrayMask)
|
|
{
|
|
sprintf(valbuf, "(%s)[%s]", valref, lenref);
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_LinkedListMask)
|
|
{
|
|
output("if (!(*f = (P%s)ASN1DecAlloc(%s, sizeof(**f))))\n",
|
|
info->Identifier, encref);
|
|
output("return 0;\n");
|
|
sprintf(valbuf, "(*f)->%s", GetPrivateValueName(info->pPrivateDirectives, "value"));
|
|
}
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, valbuf, eDecode, encref);
|
|
if (info->Rules & eTypeRules_SinglyLinkedList)
|
|
{
|
|
output("f = &(*f)->next;\n");
|
|
}
|
|
else
|
|
if (info->Rules & eTypeRules_DoublyLinkedList)
|
|
{
|
|
output("(*f)->prev = b;\n");
|
|
output("b = *f;\n");
|
|
output("f = &b->next;\n");
|
|
}
|
|
} else {
|
|
GenPERFuncSimpleType(ass, &sinfo->SubType->PERTypeInfo, NULL, eDecode, encref);
|
|
}
|
|
if ((info->Rules & (eTypeRules_LengthPointer | eTypeRules_FixedArray)) && lenref)
|
|
output("(%s)++;\n", lenref);
|
|
|
|
/* end of inner loop */
|
|
output("}\n");
|
|
|
|
/* end of outer loop */
|
|
output("} while (n >= 0x4000);\n");
|
|
|
|
/* terminate list */
|
|
if (valref && (info->Rules & (eTypeRules_SinglyLinkedList | eTypeRules_DoublyLinkedList)))
|
|
output("*f = NULL;\n");
|
|
break;
|
|
|
|
case ePERSTIData_ObjectIdentifier:
|
|
|
|
/* decode object identifier value */
|
|
if (valref) {
|
|
if (info->pPrivateDirectives->fOidArray || g_fOidArray)
|
|
{
|
|
output("if (!ASN1PERDecObjectIdentifier2(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
else
|
|
{
|
|
output("if (!ASN1PERDecObjectIdentifier(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_External:
|
|
|
|
/* decode external value */
|
|
output("if (!ASN1PERDecExternal(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_EmbeddedPdv:
|
|
|
|
/* decode embedded pdv value */
|
|
if (sinfo->Identification) {
|
|
if (!strcmp(sinfo->Identification->Identifier, "fixed")) {
|
|
output("if (!ASN1PERDecEmbeddedPdvOpt(%s, %s, NULL, NULL))\n",
|
|
encref, Reference(valref));
|
|
} else {
|
|
output("if (!ASN1PERDecEmbeddedPdvOpt(%s, %s, &%s_identification_syntaxes_abstract, &%s_identification_syntaxes_transfer))\n",
|
|
encref, Reference(valref),
|
|
info->Identifier, info->Identifier);
|
|
}
|
|
} else {
|
|
output("if (!ASN1PERDecEmbeddedPdv(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_MultibyteString:
|
|
|
|
/* decode multibyte string value */
|
|
output("if (!ASN1PERDecMultibyteString(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_UnrestrictedString:
|
|
|
|
/* decode character string value */
|
|
if (sinfo->Identification) {
|
|
if (!strcmp(sinfo->Identification->Identifier, "fixed")) {
|
|
output("if (!ASN1PERDecCharacterStringOpt(%s, %s, NULL, NULL))\n",
|
|
encref, Reference(valref));
|
|
} else {
|
|
output("if (!ASN1PERDecCharacterStringOpt(%s, %s, &%s_identification_syntaxes_abstract, &%s_identification_syntaxes_transfer))\n",
|
|
encref, Reference(valref),
|
|
info->Identifier, info->Identifier);
|
|
}
|
|
} else {
|
|
output("if (!ASN1PERDecCharacterString(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
}
|
|
output("return 0;\n");
|
|
break;
|
|
|
|
case ePERSTIData_String:
|
|
|
|
/* decode string value as fragmented */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmented%sString(%s, %s, %s, %u))\n",
|
|
p, encref, Reference(lenref), Reference(valref), sinfo->NBits);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_ZeroString:
|
|
|
|
/* decode zero-terminated string value as fragmented */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmentedZero%sString(%s, %s, %u))\n",
|
|
p, encref, Reference(valref), sinfo->NBits);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_TableString:
|
|
|
|
/* decode table string value as fragmented */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmentedTable%sString(%s, %s, %s, %u, %s))\n",
|
|
p, encref, Reference(lenref), Reference(valref), sinfo->NBits,
|
|
Reference(sinfo->TableIdentifier));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_ZeroTableString:
|
|
|
|
/* decode zero-terminated table-string as fragmented */
|
|
if (info->NOctets == 1) {
|
|
p = "Char";
|
|
} else if (info->NOctets == 2) {
|
|
p = "Char16";
|
|
} else if (info->NOctets == 4) {
|
|
p = "Char32";
|
|
} else
|
|
MyAbort();
|
|
if (valref) {
|
|
output("if (!ASN1PERDecFragmentedZeroTable%sString(%s, %s, %u, %s))\n",
|
|
p, encref, Reference(valref), sinfo->NBits, Reference(sinfo->TableIdentifier));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, %u))\n",
|
|
encref, sinfo->NBits);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
|
|
case ePERSTIData_Open:
|
|
|
|
/* decode open type value */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecOpenType(%s, %s))\n",
|
|
encref, Reference(valref));
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipFragmented(%s, 8))\n",
|
|
encref);
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case ePERSTILength_SmallLength:
|
|
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Extension:
|
|
|
|
/* decode extension bits with normally small length */
|
|
if (valref) {
|
|
output("if (!ASN1PERDecNormallySmallExtension(%s, %s, %u, %s))\n",
|
|
encref, Reference(lenref), sinfo->NBits, valref);
|
|
output("return 0;\n");
|
|
} else {
|
|
output("if (!ASN1PERDecSkipNormallySmallExtension(%s, %s))\n",
|
|
encref, Reference(lenref));
|
|
output("return 0;\n");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
FinalTouch:
|
|
|
|
/* additional calculations for value decoding: */
|
|
/* add lower bound of constraint/semiconstraint value */
|
|
switch (sinfo->Constraint) {
|
|
case ePERSTIConstraint_Semiconstrained:
|
|
case ePERSTIConstraint_Constrained:
|
|
switch (sinfo->Data) {
|
|
case ePERSTIData_Integer:
|
|
case ePERSTIData_Unsigned:
|
|
case ePERSTIData_NormallySmall:
|
|
if (valref) {
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0) != 0) {
|
|
if (info->NOctets != 0) {
|
|
if (intx_cmp(&sinfo->LowerVal, &intx_0) > 0) {
|
|
output("%s += %u;\n",
|
|
valref, intx2uint32(&sinfo->LowerVal));
|
|
} else {
|
|
intx_neg(&ix, &sinfo->LowerVal);
|
|
// LONCHANC: to workaround a compiler bug in vc++.
|
|
// output("%s += -%u;\n",
|
|
output("%s += 0 - %u;\n",
|
|
valref, intx2uint32(&ix));
|
|
}
|
|
} else {
|
|
sprintf(lbbuf, "%s_lb", info->Identifier);
|
|
outputvarintx(lbbuf, &sinfo->LowerVal);
|
|
output("ASN1intx_add(%s, %s, &%s);\n",
|
|
Reference(oldvalref), Reference(valref), lbbuf);
|
|
output("ASN1intx_free(%s);\n",
|
|
Reference(valref));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|