asn1: Add --decorate=... for internal bookkeeping
This option, `--decorate=TYPE-NAME:FIELD-TYPE:field-name[?]` allows one to add a field to any struct generated by the ASN.1 compiler for any SET or SEQUENCE type such that: - the field will be freed by the `free_TYPE_NAME()` function - the field will be copied by the `copy_TYPE_NAME()` function - the field will not be printed by the `print_TYPE_NAME()` function - the field will NOT be encoded or decoded This is useful for internal bookkeeping. The first use of this may well be for adding an optional field to `Principal` where information about name attributes will be stored, which will then allow us to have GSS name attributes for the krb5 mechanism w/o having to refactor the mechanism to use a different structure for representing `gss_name_t` mechnames than the one currently used (`Principal`; `krb5_principal` happens to be a typedef alias of `Principal *`). So w/o massive rototilling of the GSS krb5 mechanism we can have name attributes, _and_ we'll also be able to have those in the krb5 API as well w/o any massive rototilling there either.
This commit is contained in:
@@ -390,7 +390,10 @@ crmf_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/cr
|
||||
$(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_template_asn1 || (rm -f crmf_template_asn1_files ; exit 1)
|
||||
|
||||
krb5_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt
|
||||
$(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/krb5.opt $(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1)
|
||||
$(ASN1_COMPILE) --one-code-file --template \
|
||||
--option-file=$(srcdir)/krb5.opt \
|
||||
--decorate='Principal:PrincipalNameAttrs:nameattrs?' \
|
||||
$(srcdir)/krb5.asn1 krb5_template_asn1 || (rm -f krb5_template_asn1_files ; exit 1)
|
||||
|
||||
ocsp_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1
|
||||
$(ASN1_COMPILE) --one-code-file --template --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_template_asn1 || (rm -f ocsp_template_asn1_files ; exit 1)
|
||||
@@ -429,7 +432,10 @@ crmf_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/crmf.asn1 $(srcdir)/crmf.opt
|
||||
$(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/crmf.opt $(srcdir)/crmf.asn1 crmf_asn1 || (rm -f crmf_asn1_files ; exit 1)
|
||||
|
||||
krb5_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/krb5.asn1 $(srcdir)/krb5.opt
|
||||
$(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/krb5.opt $(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1)
|
||||
$(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) \
|
||||
--option-file=$(srcdir)/krb5.opt \
|
||||
--decorate='Principal:PrincipalNameAttrs:nameattrs?' \
|
||||
$(srcdir)/krb5.asn1 krb5_asn1 || (rm -f krb5_asn1_files ; exit 1)
|
||||
|
||||
ocsp_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/ocsp.asn1
|
||||
$(ASN1_COMPILE) --one-code-file $(TEMPLATE_OPTION) --option-file=$(srcdir)/ocsp.opt $(srcdir)/ocsp.asn1 ocsp_asn1 || (rm -f ocsp_asn1_files ; exit 1)
|
||||
@@ -462,10 +468,17 @@ x690sample_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/x690sample.asn1
|
||||
$(ASN1_COMPILE) --one-code-file $(srcdir)/x690sample.asn1 x690sample_asn1 || (rm -f x690sample_asn1_files ; exit 1)
|
||||
|
||||
test_template_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1
|
||||
$(ASN1_COMPILE) --one-code-file --template --sequence=TESTSeqOf $(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1)
|
||||
$(ASN1_COMPILE) --one-code-file \
|
||||
--template \
|
||||
--sequence=TESTSeqOf \
|
||||
--decorate='TESTDecorated:TESTuint32:version2?' \
|
||||
$(srcdir)/test.asn1 test_template_asn1 || (rm -f test_template_asn1_files ; exit 1)
|
||||
|
||||
test_asn1_files: asn1_compile$(EXEEXT) $(srcdir)/test.asn1
|
||||
$(ASN1_COMPILE) --one-code-file --sequence=TESTSeqOf $(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1)
|
||||
$(ASN1_COMPILE) --one-code-file \
|
||||
--decorate='TESTDecorated:TESTuint32:version2?' \
|
||||
--sequence=TESTSeqOf \
|
||||
$(srcdir)/test.asn1 test_asn1 || (rm -f test_asn1_files ; exit 1)
|
||||
|
||||
|
||||
EXTRA_DIST = \
|
||||
|
@@ -202,6 +202,7 @@ $(gen_files_krb5) $(OBJ)\krb5_asn1.hx: $(BINDIR)\asn1_compile.exe krb5.asn1 krb5
|
||||
$(BINDIR)\asn1_compile.exe \
|
||||
--template \
|
||||
--one-code-file \
|
||||
--decorate="Principal:PrincipalNameAttrs:nameattrs?" \
|
||||
--option-file=$(SRCDIR)\krb5.opt \
|
||||
$(SRCDIR)\krb5.asn1 krb5_asn1 \
|
||||
|| ($(RM) $(OBJ)\krb5_asn1.h ; exit /b 1)
|
||||
@@ -315,6 +316,7 @@ $(gen_files_test) $(OBJ)\test_asn1.hx: $(BINDIR)\asn1_compile.exe test.asn1
|
||||
cd $(OBJ)
|
||||
$(BINDIR)\asn1_compile.exe \
|
||||
--template \
|
||||
--decorate='TESTDecorated:TESTuint32:version2?' \
|
||||
--one-code-file --sequence=TESTSeqOf \
|
||||
$(SRCDIR)\test.asn1 test_asn1 \
|
||||
|| ($(RM) $(OBJ)\test_asn1.h ; exit /b 1)
|
||||
@@ -324,7 +326,8 @@ $(gen_files_test_template) $(OBJ)\test_template_asn1.hx: $(BINDIR)\asn1_compile.
|
||||
cd $(OBJ)
|
||||
$(BINDIR)\asn1_compile.exe \
|
||||
--template \
|
||||
--one-code-file --template \
|
||||
--decorate='TESTDecorated:TESTuint32:version2?' \
|
||||
--one-code-file \
|
||||
--sequence=TESTSeqOf \
|
||||
$(SRCDIR)\test.asn1 test_template_asn1 \
|
||||
|| ($(RM) $(OBJ)\test_template_asn1.h ; exit /b 1)
|
||||
|
@@ -843,7 +843,23 @@ In recent times the following features have been added:
|
||||
|
||||
## Compiler Usage
|
||||
|
||||
First, see the manual page `asn1_compile.1`:
|
||||
The various options for the Heimdal ASN.1 compiler are described in its manual
|
||||
page, which is included below.
|
||||
|
||||
The `--option-file=FILE` option is particularly useful, as it allows additional
|
||||
compiler options to be read from a file.
|
||||
|
||||
The `--preserve-binary=TYPE-NAME` option is critical for signature validation
|
||||
as it causes the decoder to save the encoding of the given type so that
|
||||
signature validation code can easily find the original encoding and thus avoid
|
||||
having to re-encode or resort to other hacks. E.g., we use this for preserving
|
||||
the original encoding of the `tbsCertificate` field of `Certificate`.
|
||||
|
||||
The `--sequence=TYPE-NAME` causes the compiler to generate additional utility
|
||||
functions for adding or removing items from the named type when it is a
|
||||
`SEQUENCE OF` or `SET OF` type.
|
||||
|
||||
See the manual page `asn1_compile.1`:
|
||||
|
||||
```
|
||||
ASN1_COMPILE(1) HEIMDAL General Commands Manual ASN1_COMPILE(1)
|
||||
@@ -856,6 +872,7 @@ SYNOPSIS
|
||||
[--encode-rfc1510-bit-string] [--decode-dce-ber]
|
||||
[--support-ber] [--preserve-binary=TYPE-NAME]
|
||||
[--sequence=TYPE-NAME] [--one-code-file] [--gen-name=NAME]
|
||||
[--decorate=TYPE-NAME:FIELD-TYPE:field-name[?]]
|
||||
[--option-file=FILE] [--original-order] [--no-parse-units]
|
||||
[--type-file=C-HEADER-FILE] [--version] [--help]
|
||||
[FILE.asn1 [NAME]]
|
||||
@@ -870,7 +887,7 @@ DESCRIPTION
|
||||
Use the “template” backend instead of the “codegen” backend
|
||||
(which is the default backend). The template backend generates
|
||||
“templates” which are akin to bytecode, and which are interpreted
|
||||
at run-time. The codegen backend generates C code for all func‐
|
||||
at run-time. The codegen backend generates C code for all func-
|
||||
tions directly, with no template interpretation. The template
|
||||
backend scales better than the codegen backend because as we add
|
||||
support for more encoding rules the templates stay mostly the
|
||||
@@ -897,13 +914,22 @@ DESCRIPTION
|
||||
--preserve-binary=TYPE-NAME
|
||||
Generate ‘_save’ fields in structs to preserve the original
|
||||
encoding of some sub-value. This is useful for cryptographic
|
||||
applications to avoid having to re-encode values to check signa‐
|
||||
applications to avoid having to re-encode values to check signa-
|
||||
tures, etc.
|
||||
|
||||
--sequence=TYPE-NAME
|
||||
Generate add/remove functions for ‘SET OF’ and ‘SEQUENCE OF’
|
||||
types.
|
||||
|
||||
--decorate=TYPE-NAME:FIELD-TYPE:field-name[?]
|
||||
Add to the TYPE-NAME SET or SEQUENCE type a field of the given
|
||||
FIELD-TYPE and field-name, but do not encode or decode this
|
||||
field. If the field-name ends in a question mark, then treat the
|
||||
field as OPTIONAL for the purposes of copy/free function stubs.
|
||||
This is useful for adding fields to existing types that can be
|
||||
used for internal bookkeeping but which do not affect interoper-
|
||||
ability because they are not encoded.
|
||||
|
||||
--one-code-file
|
||||
Generate a single source code file. Otherwise a separate code
|
||||
file will be generated for every type.
|
||||
@@ -916,7 +942,7 @@ DESCRIPTION
|
||||
|
||||
--original-order
|
||||
Attempt to preserve the original order of type definition in the
|
||||
ASN.1 module. By default the compiler generates types in a topo‐
|
||||
ASN.1 module. By default the compiler generates types in a topo-
|
||||
logical sort order.
|
||||
|
||||
--no-parse-units
|
||||
@@ -1065,9 +1091,9 @@ SYNOPSIS
|
||||
[-l -v | --version] [-l -h | --help] [FILE [TypeName...]]
|
||||
|
||||
DESCRIPTION
|
||||
asn1_print Dumps ASN.1 DER-encoded values. If one or more TypeName argu‐
|
||||
ments are given, then asn1_print will print the value in a JSON-like for‐
|
||||
mat using its knowledge of the ASN.1 modules defining those types, stop‐
|
||||
asn1_print Dumps ASN.1 DER-encoded values. If one or more TypeName argu-
|
||||
ments are given, then asn1_print will print the value in a JSON-like for-
|
||||
mat using its knowledge of the ASN.1 modules defining those types, stop-
|
||||
ping at the first type for which it can successfully decode the value.
|
||||
If TypeNames are given, they must be the names of ASN.1 types exported by
|
||||
an ASN.1 modules that are compiled into asn1_print. Use the
|
||||
|
@@ -169,6 +169,7 @@
|
||||
#define A1_OP_OPENTYPE_ID (0xb0000000)
|
||||
#define A1_OP_OPENTYPE (0xc0000000)
|
||||
#define A1_OP_NAME (0xd0000000)
|
||||
#define A1_OP_TYPE_DECORATE (0xe0000000)
|
||||
|
||||
#define A1_FLAG_MASK (0x0f000000)
|
||||
#define A1_FLAG_OPTIONAL (0x01000000)
|
||||
|
@@ -48,6 +48,7 @@
|
||||
.Op Fl Fl support-ber
|
||||
.Op Fl Fl preserve-binary=TYPE-NAME
|
||||
.Op Fl Fl sequence=TYPE-NAME
|
||||
.Op Fl Fl decorate=TYPE-NAME:FIELD-TYPE:field-name[?]
|
||||
.Op Fl Fl one-code-file
|
||||
.Op Fl Fl gen-name=NAME
|
||||
.Op Fl Fl option-file=FILE
|
||||
@@ -109,6 +110,21 @@ Generate add/remove functions for
|
||||
and
|
||||
.Sq SEQUENCE OF
|
||||
types.
|
||||
.It Fl Fl decorate=TYPE-NAME:FIELD-TYPE:field-name[?]
|
||||
Add to the
|
||||
.Va TYPE-NAME
|
||||
SET or SEQUENCE type a field of the given
|
||||
.Va FIELD-TYPE
|
||||
and
|
||||
.Va field-name ,
|
||||
but do not encode or decode this field.
|
||||
If the
|
||||
.Va field-name
|
||||
ends in a question mark, then treat the field as OPTIONAL for
|
||||
the purposes of copy/free function stubs.
|
||||
This is useful for adding fields to existing types that can be used
|
||||
for internal bookkeeping but which do not affect interoperability
|
||||
because they are not encoded.
|
||||
.It Fl Fl one-code-file
|
||||
Generate a single source code file.
|
||||
Otherwise a separate code file will be generated for every type.
|
||||
|
@@ -100,9 +100,9 @@ test_principal (void)
|
||||
|
||||
|
||||
Principal values[] = {
|
||||
{ { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, "SU.SE" },
|
||||
{ { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, "SU.SE" },
|
||||
{ { KRB5_NT_SRV_HST, { 2, datan_princ } }, "E.KTH.SE" }
|
||||
{ { KRB5_NT_PRINCIPAL, { 1, lha_principal } }, "SU.SE", NULL },
|
||||
{ { KRB5_NT_PRINCIPAL, { 2, lharoot_princ } }, "SU.SE", NULL },
|
||||
{ { KRB5_NT_SRV_HST, { 2, datan_princ } }, "E.KTH.SE", NULL }
|
||||
};
|
||||
int i, ret;
|
||||
int ntests = sizeof(tests) / sizeof(*tests);
|
||||
@@ -1016,6 +1016,50 @@ test_choice (void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Test --decorate=TYPE:FIELD-TYPE:field-name[?] */
|
||||
static int
|
||||
test_decorated(void)
|
||||
{
|
||||
TESTNotDecorated tnd;
|
||||
TESTDecorated td;
|
||||
size_t len, size;
|
||||
void *ptr;
|
||||
int ret;
|
||||
|
||||
memset(&td, 0, sizeof(td));
|
||||
memset(&tnd, 0, sizeof(tnd));
|
||||
|
||||
td.version = 3;
|
||||
if ((td.version2 = malloc(sizeof(*td.version2))) == NULL)
|
||||
errx(1, "out of memory");
|
||||
*td.version2 = 5;
|
||||
ASN1_MALLOC_ENCODE(TESTDecorated, ptr, len, &td, &size, ret);
|
||||
if (ret) {
|
||||
warnx("could not encode a TESTDecorated struct");
|
||||
return 1;
|
||||
}
|
||||
ret = decode_TESTNotDecorated(ptr, len, &tnd, &size);
|
||||
if (ret) {
|
||||
warnx("could not decode a TESTDecorated struct as TESTNotDecorated");
|
||||
return 1;
|
||||
}
|
||||
if (size != len) {
|
||||
warnx("TESTDecorated encoded size mismatch");
|
||||
return 1;
|
||||
}
|
||||
if (td.version != tnd.version) {
|
||||
warnx("TESTDecorated did not decode as a TESTNotDecorated correctly");
|
||||
return 1;
|
||||
}
|
||||
free_TESTDecorated(&td);
|
||||
if (td.version2) {
|
||||
warnx("free_TESTDecorated() did not work correctly");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmp_TESTImplicit (void *a, void *b)
|
||||
{
|
||||
@@ -2493,6 +2537,8 @@ main(int argc, char **argv)
|
||||
|
||||
DO_ONE(test_default);
|
||||
|
||||
DO_ONE(test_decorated);
|
||||
|
||||
#if ASN1_IOS_SUPPORTED
|
||||
DO_ONE(test_ios);
|
||||
#endif
|
||||
|
@@ -1355,6 +1355,8 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t
|
||||
case TSet:
|
||||
case TSequence: {
|
||||
Member *m;
|
||||
char *ft, *fn;
|
||||
int deco_opt;
|
||||
|
||||
getnewbasename(&newbasename, typedefp || level == 0, basename, name);
|
||||
|
||||
@@ -1395,6 +1397,13 @@ define_type(int level, const char *name, const char *basename, Type *pt, Type *t
|
||||
fprintf(jsonfile, ",\"opentype\":");
|
||||
define_open_type(level, newbasename, name, basename, t, t);
|
||||
}
|
||||
if (decorate_type(newbasename, &ft, &fn, &deco_opt)) {
|
||||
space(level + 1);
|
||||
fprintf(headerfile, "%s %s%s;\n", ft, deco_opt ? "*" : "", fn);
|
||||
fprintf(jsonfile, ",\"decorate\":{\"type\":\"%s\",\"name\":\"%s\", \"optional\":%s}", ft, fn, deco_opt ? "true" : "false");
|
||||
free(ft);
|
||||
free(fn);
|
||||
}
|
||||
space(level);
|
||||
fprintf (headerfile, "} %s;\n", name);
|
||||
break;
|
||||
|
@@ -229,6 +229,9 @@ void
|
||||
generate_type_copy (const Symbol *s)
|
||||
{
|
||||
int preserve = preserve_type(s->name) ? TRUE : FALSE;
|
||||
int save_used_fail = used_fail;
|
||||
int deco_opt;
|
||||
char *ft, *fn;
|
||||
|
||||
used_fail = 0;
|
||||
|
||||
@@ -238,6 +241,19 @@ generate_type_copy (const Symbol *s)
|
||||
"memset(to, 0, sizeof(*to));\n",
|
||||
s->gen_name, s->gen_name, s->gen_name);
|
||||
copy_type ("from", "to", s->type, preserve);
|
||||
if (decorate_type(s->gen_name, &ft, &fn, &deco_opt)) {
|
||||
if (deco_opt) {
|
||||
fprintf(codefile, "if (from->%s) {\n", fn);
|
||||
fprintf(codefile, "(to)->%s = malloc(sizeof(*(to)->%s));\n", fn, fn);
|
||||
fprintf(codefile, "if (copy_%s((from)->%s, (to)->%s)) goto fail;\n", ft, fn, fn);
|
||||
fprintf(codefile, "}\n");
|
||||
} else {
|
||||
fprintf(codefile, "if (copy_%s(&(from)->%s, &(to)->%s)) goto fail;\n", ft, fn, fn);
|
||||
}
|
||||
used_fail++;
|
||||
free(ft);
|
||||
free(fn);
|
||||
}
|
||||
fprintf (codefile, "return 0;\n");
|
||||
|
||||
if (used_fail)
|
||||
@@ -248,5 +264,6 @@ generate_type_copy (const Symbol *s)
|
||||
|
||||
fprintf(codefile,
|
||||
"}\n\n");
|
||||
used_fail = save_used_fail;
|
||||
}
|
||||
|
||||
|
@@ -119,7 +119,7 @@ free_type (const char *name, const Type *t, int preserve)
|
||||
have_ellipsis->label,
|
||||
name, have_ellipsis->gen_name);
|
||||
fprintf(codefile, "}\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TSetOf:
|
||||
@@ -179,6 +179,8 @@ void
|
||||
generate_type_free (const Symbol *s)
|
||||
{
|
||||
int preserve = preserve_type(s->name) ? TRUE : FALSE;
|
||||
int deco_opt;
|
||||
char *ft, *fn;
|
||||
|
||||
fprintf (codefile, "void ASN1CALL\n"
|
||||
"free_%s(%s *data)\n"
|
||||
@@ -186,6 +188,19 @@ generate_type_free (const Symbol *s)
|
||||
s->gen_name, s->gen_name);
|
||||
|
||||
free_type ("data", s->type, preserve);
|
||||
if (decorate_type(s->gen_name, &ft, &fn, &deco_opt)) {
|
||||
if (deco_opt) {
|
||||
fprintf(codefile, "if ((data)->%s) {\n", fn);
|
||||
fprintf(codefile, "free_%s((data)->%s);\n", ft, fn);
|
||||
fprintf(codefile, "free((data)->%s);\n", fn);
|
||||
fprintf(codefile, "(data)->%s = NULL;\n", fn);
|
||||
fprintf(codefile, "}\n");
|
||||
} else {
|
||||
fprintf(codefile, "free_%s(&(data)->%s);\n", ft, fn);
|
||||
}
|
||||
free(ft);
|
||||
free(fn);
|
||||
}
|
||||
fprintf (codefile, "}\n\n");
|
||||
}
|
||||
|
||||
|
@@ -144,6 +144,7 @@ int is_tagged_type(const Type *);
|
||||
|
||||
int preserve_type(const char *);
|
||||
int seq_type(const char *);
|
||||
int decorate_type(const char *, char **, char **, int *);
|
||||
|
||||
void generate_header_of_codefile(const char *);
|
||||
void close_codefile(void);
|
||||
|
@@ -1063,6 +1063,8 @@ template_members(struct templatehead *temp,
|
||||
Member *m;
|
||||
size_t i = 0, typeididx = 0, opentypeidx = 0;
|
||||
int is_array_of_open_type = 0;
|
||||
int deco_opt;
|
||||
char *ft, *fn;
|
||||
|
||||
if (isstruct && t->actual_parameter)
|
||||
get_open_type_defn_fields(t, &typeidmember, &opentypemember,
|
||||
@@ -1102,6 +1104,17 @@ template_members(struct templatehead *temp,
|
||||
typeidfield, opentypefield, opentypemember,
|
||||
is_array_of_open_type);
|
||||
|
||||
if (decorate_type(basetype, &ft, &fn, &deco_opt)) {
|
||||
char *poffset2;
|
||||
|
||||
poffset2 = partial_offset(basetype, fn, 1, isstruct);
|
||||
add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s",
|
||||
deco_opt ? "|A1_FLAG_OPTIONAL" : "");
|
||||
free(poffset2);
|
||||
free(ft);
|
||||
free(fn);
|
||||
}
|
||||
|
||||
if (isstruct)
|
||||
template_names(temp, basetype, t);
|
||||
break;
|
||||
@@ -1114,6 +1127,8 @@ template_members(struct templatehead *temp,
|
||||
Member *m;
|
||||
size_t i = 0, typeididx = 0, opentypeidx = 0;
|
||||
int is_array_of_open_type = 0;
|
||||
int deco_opt;
|
||||
char *ft, *fn;
|
||||
|
||||
if (isstruct && t->actual_parameter)
|
||||
get_open_type_defn_fields(t, &typeidmember, &opentypemember,
|
||||
@@ -1153,6 +1168,17 @@ template_members(struct templatehead *temp,
|
||||
typeidfield, opentypefield, opentypemember,
|
||||
is_array_of_open_type);
|
||||
|
||||
if (decorate_type(basetype, &ft, &fn, &deco_opt)) {
|
||||
char *poffset2;
|
||||
|
||||
poffset2 = partial_offset(basetype, fn, 1, isstruct);
|
||||
add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s",
|
||||
deco_opt ? "|A1_FLAG_OPTIONAL" : "");
|
||||
free(poffset2);
|
||||
free(ft);
|
||||
free(fn);
|
||||
}
|
||||
|
||||
if (isstruct)
|
||||
template_names(temp, basetype, t);
|
||||
break;
|
||||
|
@@ -39,6 +39,7 @@ extern FILE *yyin;
|
||||
|
||||
static getarg_strings preserve;
|
||||
static getarg_strings seq;
|
||||
static getarg_strings decorate;
|
||||
|
||||
int
|
||||
preserve_type(const char *p)
|
||||
@@ -53,13 +54,49 @@ preserve_type(const char *p)
|
||||
int
|
||||
seq_type(const char *p)
|
||||
{
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < seq.num_strings; i++)
|
||||
if (strcmp(seq.strings[i], p) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
decorate_type(const char *p, char **field_type, char **field_name, int *opt)
|
||||
{
|
||||
size_t plen = strlen(p);
|
||||
size_t i;
|
||||
|
||||
*field_type = NULL;
|
||||
*field_name = NULL;
|
||||
*opt = 0;
|
||||
|
||||
for (i = 0; i < decorate.num_strings; i++) {
|
||||
const char *r;
|
||||
char *q;
|
||||
|
||||
if (strncmp(decorate.strings[i], p, plen) != 0)
|
||||
continue;
|
||||
if (decorate.strings[i][plen] != ':')
|
||||
errx(1, "--decorate argument missing field type");
|
||||
|
||||
p = &decorate.strings[i][plen + 1];
|
||||
if ((r = strchr(p, ':')) == NULL)
|
||||
errx(1, "--decorate argument missing field name");
|
||||
r++;
|
||||
*field_type = estrdup(p);
|
||||
*(strchr(*field_type, ':')) = '\0';
|
||||
*field_name = estrdup(r);
|
||||
if ((q = strchr(*field_name, '?'))) {
|
||||
*q = '\0';
|
||||
*opt = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
my_basename(const char *fn)
|
||||
{
|
||||
@@ -113,6 +150,8 @@ struct getargs args[] = {
|
||||
"verification)", "TYPE-NAME" },
|
||||
{ "sequence", 0, arg_strings, &seq,
|
||||
"Generate add/remove functions for SEQUENCE OF types", "TYPE-NAME" },
|
||||
{ "decorate", 0, arg_strings, &decorate,
|
||||
"Generate private field for SEQUENCE/SET type", "TYPE-NAME:FIELD_TYPE:field_name[?]" },
|
||||
{ "one-code-file", 0, arg_flag, &one_code_file, NULL, NULL },
|
||||
{ "gen-name", 0, arg_string, &name,
|
||||
"Name of generated module", "NAME" },
|
||||
|
@@ -774,6 +774,7 @@ _asn1_decode(const struct asn1_template *t, unsigned flags,
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
case A1_OP_TYPE_DECORATE: break;
|
||||
case A1_OP_NAME: break;
|
||||
case A1_OP_DEFVAL:
|
||||
tdefval = t;
|
||||
@@ -1417,6 +1418,7 @@ _asn1_encode(const struct asn1_template *t, unsigned char *p, size_t len, const
|
||||
}
|
||||
case A1_OP_NAME: break;
|
||||
case A1_OP_DEFVAL: break;
|
||||
case A1_OP_TYPE_DECORATE: break;
|
||||
case A1_OP_TYPE:
|
||||
case A1_OP_TYPE_EXTERN: {
|
||||
size_t newsize;
|
||||
@@ -1992,6 +1994,7 @@ _asn1_length(const struct asn1_template *t, const void *data)
|
||||
}
|
||||
case A1_OP_NAME: break;
|
||||
case A1_OP_DEFVAL: break;
|
||||
case A1_OP_TYPE_DECORATE: break;
|
||||
case A1_OP_TYPE:
|
||||
case A1_OP_TYPE_EXTERN: {
|
||||
const void *el = DPOC(data, t->offset);
|
||||
@@ -2253,6 +2256,7 @@ _asn1_free(const struct asn1_template *t, void *data)
|
||||
}
|
||||
case A1_OP_NAME: break;
|
||||
case A1_OP_DEFVAL: break;
|
||||
case A1_OP_TYPE_DECORATE:
|
||||
case A1_OP_TYPE:
|
||||
case A1_OP_TYPE_EXTERN: {
|
||||
void *el = DPO(data, t->offset);
|
||||
@@ -2264,7 +2268,7 @@ _asn1_free(const struct asn1_template *t, void *data)
|
||||
el = *pel;
|
||||
}
|
||||
|
||||
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE) {
|
||||
if ((t->tt & A1_OP_MASK) == A1_OP_TYPE || (t->tt & A1_OP_MASK) == A1_OP_TYPE_DECORATE) {
|
||||
_asn1_free(t->ptr, el);
|
||||
} else {
|
||||
const struct asn1_type_func *f = t->ptr;
|
||||
@@ -2541,6 +2545,7 @@ _asn1_print(const struct asn1_template *t,
|
||||
break;
|
||||
case A1_OP_NAME: break;
|
||||
case A1_OP_DEFVAL: break;
|
||||
case A1_OP_TYPE_DECORATE: break; /* We could probably print this though */
|
||||
case A1_OP_TYPE:
|
||||
case A1_OP_TYPE_EXTERN: {
|
||||
const void *el = DPOC(data, t->offset);
|
||||
@@ -2858,6 +2863,7 @@ _asn1_copy(const struct asn1_template *t, const void *from, void *to)
|
||||
}
|
||||
case A1_OP_NAME: break;
|
||||
case A1_OP_DEFVAL: break;
|
||||
case A1_OP_TYPE_DECORATE:
|
||||
case A1_OP_TYPE:
|
||||
case A1_OP_TYPE_EXTERN: {
|
||||
const void *fel = DPOC(from, t->offset);
|
||||
|
@@ -286,4 +286,14 @@ TESTExtensible ::= SEQUENCE {
|
||||
extensions SEQUENCE OF TESTExtension
|
||||
}
|
||||
|
||||
TESTDecorated ::= SEQUENCE {
|
||||
version TESTuint32
|
||||
-- gets decorated
|
||||
}
|
||||
|
||||
TESTNotDecorated ::= SEQUENCE {
|
||||
version TESTuint32
|
||||
-- should have the same encoding as TESTDecorated
|
||||
}
|
||||
|
||||
END
|
||||
|
Reference in New Issue
Block a user