asn1: Further IMPLICIT tagging fixes
Commit 89389bc7a
(asn1: Fix long-standing IMPLICIT tagging brokenness)
was incomplete. Removing the hacks in lib/asn1/cms.asn1 revealed this.
Now the ASN.1 compiler generates enums to indicate what is the class and
tag of each type. This is needed so the decoder functions generated by
the compiler can know what tag to restore.
Now, too, the compiler does handle IMPLICIT tags whose encoded length is
different from that of the underlying type.
However, we now don't handle indefinite BER and non-DER definite lengths
(DCE) following IMPLICIT tags. This would affect only CMS in-tree.
This commit is contained in:
@@ -2,13 +2,6 @@
|
||||
|
||||
CANTHANDLE DEFINITIONS ::= BEGIN
|
||||
|
||||
-- Can't handle tags larger than 30 because while we encode large tags
|
||||
-- correctly, we don't account for more than one byte of them in the length
|
||||
-- functions. The compiler shouldn't crash, but the code generate will be
|
||||
-- incorrect and should crash.
|
||||
|
||||
Foo31 ::= SEQUENCE { foo [31] INTEGER }
|
||||
|
||||
-- Can't handle primitives in SET OF, causing the compiler to crash
|
||||
-- Workaround is to define a type that is only an integer and use that
|
||||
|
||||
|
@@ -1016,7 +1016,6 @@ test_choice (void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef IMPLICIT_TAGGING_WORKS
|
||||
static int
|
||||
cmp_TESTImplicit (void *a, void *b)
|
||||
{
|
||||
@@ -1028,7 +1027,20 @@ cmp_TESTImplicit (void *a, void *b)
|
||||
COMPARE_INTEGER(aa,ab,ti3);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
cmp_TESTImplicit2 (void *a, void *b)
|
||||
{
|
||||
TESTImplicit2 *aa = a;
|
||||
TESTImplicit2 *ab = b;
|
||||
|
||||
COMPARE_INTEGER(aa,ab,ti1);
|
||||
COMPARE_INTEGER(aa,ab,ti3);
|
||||
IF_OPT_COMPARE(aa,ab,ti4) {
|
||||
COMPARE_INTEGER(aa,ab,ti4[0]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
UNIV CONS Sequence 14
|
||||
@@ -1043,16 +1055,20 @@ static int
|
||||
test_implicit (void)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef IMPLICIT_TAGGING_WORKS
|
||||
struct test_case tests[] = {
|
||||
{ NULL, 18,
|
||||
"\x30\x10\x80\x01\x00\xa1\x06\xbf"
|
||||
"\x7f\x03\x02\x01\x02\xa2\x03\x84\x01\x03",
|
||||
{ NULL, 16,
|
||||
"\x30\x0e\x80\x01\x00\xa1\x06\xbf\x7f\x03\x02\x01\x02\x82\x01\x03",
|
||||
"implicit 1" }
|
||||
};
|
||||
struct test_case tests2[] = {
|
||||
{ NULL, 12,
|
||||
"\x30\x0a\x80\x01\x01\x82\x01\x03\x9f\x33\x01\x04",
|
||||
"implicit 2" }
|
||||
};
|
||||
|
||||
int ntests = sizeof(tests) / sizeof(*tests);
|
||||
TESTImplicit c0;
|
||||
TESTImplicit2 c1;
|
||||
int ti4 = 4;
|
||||
|
||||
memset(&c0, 0, sizeof(c0));
|
||||
c0.ti1 = 0;
|
||||
@@ -1060,23 +1076,32 @@ test_implicit (void)
|
||||
c0.ti3 = 3;
|
||||
tests[0].val = &c0;
|
||||
|
||||
ret += generic_test (tests, ntests, sizeof(TESTImplicit),
|
||||
(generic_encode)encode_TESTImplicit,
|
||||
(generic_length)length_TESTImplicit,
|
||||
(generic_decode)decode_TESTImplicit,
|
||||
(generic_free)free_TESTImplicit,
|
||||
cmp_TESTImplicit,
|
||||
(generic_copy)copy_TESTImplicit);
|
||||
memset(&c1, 0, sizeof(c1));
|
||||
c1.ti1 = 1;
|
||||
c1.ti3 = 3;
|
||||
c1.ti4 = &ti4;
|
||||
tests2[0].val = &c1;
|
||||
|
||||
ret += generic_test (tests, ntests, sizeof(TESTImplicit2),
|
||||
(generic_encode)encode_TESTImplicit2,
|
||||
(generic_length)length_TESTImplicit2,
|
||||
(generic_decode)decode_TESTImplicit2,
|
||||
(generic_free)free_TESTImplicit2,
|
||||
cmp_TESTImplicit,
|
||||
NULL);
|
||||
ret += generic_test(tests,
|
||||
sizeof(tests) / sizeof(*tests),
|
||||
sizeof(TESTImplicit),
|
||||
(generic_encode)encode_TESTImplicit,
|
||||
(generic_length)length_TESTImplicit,
|
||||
(generic_decode)decode_TESTImplicit,
|
||||
(generic_free)free_TESTImplicit,
|
||||
cmp_TESTImplicit,
|
||||
(generic_copy)copy_TESTImplicit);
|
||||
|
||||
ret += generic_test(tests2,
|
||||
sizeof(tests2) / sizeof(*tests2),
|
||||
sizeof(TESTImplicit2),
|
||||
(generic_encode)encode_TESTImplicit2,
|
||||
(generic_length)length_TESTImplicit2,
|
||||
(generic_decode)decode_TESTImplicit2,
|
||||
(generic_free)free_TESTImplicit2,
|
||||
cmp_TESTImplicit2,
|
||||
NULL);
|
||||
|
||||
#endif /* IMPLICIT_TAGGING_WORKS */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1502,7 +1527,6 @@ check_TESTMechTypeList(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IMPLICIT_TAGGING_WORKS
|
||||
static int
|
||||
cmp_TESTSeqOf4(void *a, void *b)
|
||||
{
|
||||
@@ -1545,13 +1569,11 @@ cmp_TESTSeqOf4(void *a, void *b)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* IMPLICIT_TAGGING_WORKS */
|
||||
|
||||
static int
|
||||
test_seq4 (void)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef IMPLICIT_TAGGING_WORKS
|
||||
struct test_case tests[] = {
|
||||
{ NULL, 2,
|
||||
"\x30\x00",
|
||||
@@ -1674,7 +1696,6 @@ test_seq4 (void)
|
||||
(generic_free)free_TESTSeqOf4,
|
||||
cmp_TESTSeqOf4,
|
||||
(generic_copy)copy_TESTSeqOf4);
|
||||
#endif /* IMPLICIT_TAGGING_WORKS */
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1775,7 +1796,11 @@ test_seqof5(void)
|
||||
static int
|
||||
test_x690sample(void)
|
||||
{
|
||||
/* Taken from X.690, Appendix A */
|
||||
/*
|
||||
* Taken from X.690, Appendix A, though sadly it's not specified whether
|
||||
* it's in BER, DER, or CER, but it turns out to be DER since, as you can
|
||||
* see below, we re-encode and get the same encoding back.
|
||||
*/
|
||||
X690SamplePersonnelRecord r;
|
||||
heim_octet_string os;
|
||||
unsigned char encoded_sample[] = {
|
||||
@@ -1803,6 +1828,7 @@ test_x690sample(void)
|
||||
free_X690SamplePersonnelRecord(&r);
|
||||
memset(&r, 0, sizeof(r));
|
||||
|
||||
/* We re-construct the record manually to double-check the spec */
|
||||
r.name.givenName = strdup("John");
|
||||
r.name.initial = strdup("P");
|
||||
r.name.familyName = strdup("Smith");
|
||||
@@ -1839,40 +1865,41 @@ main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret += test_principal ();
|
||||
ret += test_authenticator();
|
||||
ret += test_krb_error();
|
||||
ret += test_Name();
|
||||
ret += test_bit_string();
|
||||
ret += test_bit_string_rfc1510();
|
||||
ret += test_time();
|
||||
ret += test_cert();
|
||||
#define DO_ONE(t) if (t()) { fprintf(stderr, "%s() failed!\n", #t); ret++; }
|
||||
DO_ONE(test_principal);
|
||||
DO_ONE(test_authenticator);
|
||||
DO_ONE(test_krb_error);
|
||||
DO_ONE(test_Name);
|
||||
DO_ONE(test_bit_string);
|
||||
DO_ONE(test_bit_string_rfc1510);
|
||||
DO_ONE(test_time);
|
||||
DO_ONE(test_cert);
|
||||
|
||||
ret += check_tag_length();
|
||||
ret += check_tag_length64();
|
||||
ret += check_tag_length64s();
|
||||
ret += test_large_tag();
|
||||
ret += test_choice();
|
||||
DO_ONE(check_tag_length);
|
||||
DO_ONE(check_tag_length64);
|
||||
DO_ONE(check_tag_length64s);
|
||||
DO_ONE(test_large_tag);
|
||||
DO_ONE(test_choice);
|
||||
|
||||
ret += test_implicit();
|
||||
DO_ONE(test_implicit);
|
||||
|
||||
ret += test_taglessalloc();
|
||||
ret += test_optional();
|
||||
DO_ONE(test_taglessalloc);
|
||||
DO_ONE(test_optional);
|
||||
|
||||
ret += check_fail_largetag();
|
||||
ret += check_fail_sequence();
|
||||
ret += check_fail_choice();
|
||||
ret += check_fail_Ticket();
|
||||
DO_ONE(check_fail_largetag);
|
||||
DO_ONE(check_fail_sequence);
|
||||
DO_ONE(check_fail_choice);
|
||||
DO_ONE(check_fail_Ticket);
|
||||
|
||||
ret += check_seq();
|
||||
ret += check_seq_of_size();
|
||||
ret += test_SignedData();
|
||||
DO_ONE(check_seq);
|
||||
DO_ONE(check_seq_of_size);
|
||||
DO_ONE(test_SignedData);
|
||||
|
||||
ret += check_TESTMechTypeList();
|
||||
ret += test_seq4();
|
||||
ret += test_seqof5();
|
||||
DO_ONE(check_TESTMechTypeList);
|
||||
DO_ONE(test_seq4);
|
||||
DO_ONE(test_seqof5);
|
||||
|
||||
ret += test_x690sample();
|
||||
DO_ONE(test_x690sample);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -75,12 +75,10 @@ SignerInfo ::= SEQUENCE {
|
||||
version CMSVersion,
|
||||
sid SignerIdentifier,
|
||||
digestAlgorithm DigestAlgorithmIdentifier,
|
||||
signedAttrs [0] IMPLICIT -- CMSAttributes --
|
||||
SET OF Attribute OPTIONAL,
|
||||
signedAttrs [0] IMPLICIT CMSAttributes OPTIONAL,
|
||||
signatureAlgorithm SignatureAlgorithmIdentifier,
|
||||
signature SignatureValue,
|
||||
unsignedAttrs [1] IMPLICIT -- CMSAttributes --
|
||||
SET OF Attribute OPTIONAL
|
||||
unsignedAttrs [1] IMPLICIT CMSAttributes OPTIONAL
|
||||
}
|
||||
|
||||
SignerInfos ::= SET OF SignerInfo
|
||||
@@ -89,18 +87,14 @@ SignedData ::= SEQUENCE {
|
||||
version CMSVersion,
|
||||
digestAlgorithms DigestAlgorithmIdentifiers,
|
||||
encapContentInfo EncapsulatedContentInfo,
|
||||
certificates [0] IMPLICIT -- CertificateSet --
|
||||
SET OF heim_any OPTIONAL,
|
||||
crls [1] IMPLICIT -- CertificateRevocationLists --
|
||||
heim_any OPTIONAL,
|
||||
certificates [0] IMPLICIT CertificateSet OPTIONAL,
|
||||
crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
|
||||
signerInfos SignerInfos
|
||||
}
|
||||
|
||||
OriginatorInfo ::= SEQUENCE {
|
||||
certs [0] IMPLICIT -- CertificateSet --
|
||||
SET OF heim_any OPTIONAL,
|
||||
crls [1] IMPLICIT --CertificateRevocationLists --
|
||||
heim_any OPTIONAL
|
||||
certs [0] IMPLICIT CertificateSet OPTIONAL,
|
||||
crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
|
||||
}
|
||||
|
||||
KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||
@@ -132,17 +126,15 @@ UnprotectedAttributes ::= SET OF Attribute -- SIZE (1..MAX)
|
||||
CMSEncryptedData ::= SEQUENCE {
|
||||
version CMSVersion,
|
||||
encryptedContentInfo EncryptedContentInfo,
|
||||
unprotectedAttrs [1] IMPLICIT -- UnprotectedAttributes --
|
||||
heim_any OPTIONAL
|
||||
unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
|
||||
}
|
||||
|
||||
EnvelopedData ::= SEQUENCE {
|
||||
version CMSVersion,
|
||||
originatorInfo [0] IMPLICIT -- OriginatorInfo -- heim_any OPTIONAL,
|
||||
originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
|
||||
recipientInfos RecipientInfos,
|
||||
encryptedContentInfo EncryptedContentInfo,
|
||||
unprotectedAttrs [1] IMPLICIT -- UnprotectedAttributes --
|
||||
heim_any OPTIONAL
|
||||
unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
|
||||
}
|
||||
|
||||
-- Data ::= OCTET STRING
|
||||
|
@@ -642,6 +642,15 @@ der_match_tag2 (const unsigned char *p, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 0 if the encoded data at `p' of length `len' starts with the tag of
|
||||
* class `cls`, type `type', and tag value `tag', and puts the length of the
|
||||
* payload (i.e., the length of V in TLV, not the length of TLV) in
|
||||
* `*length_ret', and the size of the whole thing (the TLV) in `*size' if
|
||||
* `size' is not NULL.
|
||||
*
|
||||
* Else returns an error.
|
||||
*/
|
||||
int ASN1CALL
|
||||
der_match_tag_and_length (const unsigned char *p, size_t len,
|
||||
Der_class cls, Der_type *type, unsigned int tag,
|
||||
|
@@ -441,25 +441,102 @@ der_put_oid (unsigned char *p, size_t len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a copy of the DER TLV at `p' with a different outermost tag.
|
||||
*
|
||||
* This is used in the implementation of IMPLICIT tags in generated decoder
|
||||
* functions.
|
||||
*/
|
||||
int
|
||||
der_replace_tag(unsigned char *p, size_t len, Der_class class, Der_type type,
|
||||
der_replace_tag(const unsigned char *p, size_t len,
|
||||
unsigned char **out, size_t *outlen,
|
||||
Der_class class, Der_type type,
|
||||
unsigned int tag)
|
||||
{
|
||||
Der_class found_class;
|
||||
Der_type found_type;
|
||||
unsigned int found_tag;
|
||||
size_t found_size, actual_size;
|
||||
size_t payload_len, l, tag_len, len_len;
|
||||
int e;
|
||||
|
||||
e = der_get_tag(p, len, &found_class, &found_type, &found_tag,
|
||||
&found_size);
|
||||
if (e == 0)
|
||||
e = der_put_tag(p, len, class, type, tag, &actual_size);
|
||||
if (e == 0 && actual_size != found_size)
|
||||
e = ASN1_OVERFLOW;
|
||||
e = der_get_tag(p, len, &found_class, &found_type, &found_tag, &l);
|
||||
if (e)
|
||||
return e;
|
||||
if (found_type != type)
|
||||
return ASN1_TYPE_MISMATCH;
|
||||
/* We don't care what found_class and found_tag are though */
|
||||
tag_len = der_length_tag(tag);
|
||||
p += l;
|
||||
len -= l;
|
||||
e = der_get_length(p, len, &payload_len, &len_len);
|
||||
if (e)
|
||||
return e;
|
||||
/*
|
||||
* `p' now points at the payload; `*out' + the length of the tag points at
|
||||
* where we should copy the DER length and the payload.
|
||||
*/
|
||||
if ((*out = malloc(*outlen = tag_len + len_len + payload_len)) == NULL)
|
||||
return ENOMEM;
|
||||
memcpy(*out + tag_len, p, len_len + payload_len);
|
||||
|
||||
/* Put the new tag */
|
||||
e = der_put_tag(*out + tag_len - 1, tag_len, class, type, tag, &l);
|
||||
if (e)
|
||||
return e;
|
||||
if (l != tag_len)
|
||||
return ASN1_OVERFLOW;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
der_encode_implicit(unsigned char *p, size_t len,
|
||||
asn1_generic_encoder_f encoder,
|
||||
void *obj, size_t *size,
|
||||
Der_type type,
|
||||
unsigned int ttag, Der_class iclass, unsigned int itag)
|
||||
{
|
||||
size_t ttaglen = der_length_tag(ttag);
|
||||
size_t itaglen = der_length_tag(itag);
|
||||
size_t l;
|
||||
unsigned char *p2;
|
||||
int e;
|
||||
|
||||
/* Attempt to encode in place */
|
||||
e = encoder(p, len, obj, size);
|
||||
if (e == 0) {
|
||||
/* Fits! Rewrite tag, adjust reported size. */
|
||||
e = der_put_tag(p + ttaglen - 1, itaglen, iclass, type, itag, &l);
|
||||
if (e == 0) {
|
||||
(*size) -= ttaglen;
|
||||
(*size) += itaglen;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
if (e != ASN1_OVERFLOW || itaglen <= ttaglen)
|
||||
return e;
|
||||
|
||||
/*
|
||||
* Did not fit because ttaglen > itaglen and this was the last / only thing
|
||||
* being encoded in a buffer of just the right size.
|
||||
*/
|
||||
if ((p2 = malloc(len + ttaglen - itaglen)) == NULL)
|
||||
e = ENOMEM;
|
||||
if (e == 0)
|
||||
e = encoder(p2 + len + ttaglen - itaglen - 1, len + ttaglen - itaglen,
|
||||
obj, size);
|
||||
if (e == 0)
|
||||
e = der_put_tag(p2 + ttaglen - 1, itaglen, iclass, type, itag, &l);
|
||||
if (e == 0) {
|
||||
(*size) -= ttaglen;
|
||||
(*size) += itaglen;
|
||||
memcpy(p - *size, p2 + ttaglen - itaglen, *size);
|
||||
}
|
||||
free(p2);
|
||||
return e;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
der_put_tag (unsigned char *p, size_t len, Der_class class, Der_type type,
|
||||
unsigned int tag, size_t *size)
|
||||
|
104
lib/asn1/gen.c
104
lib/asn1/gen.c
@@ -48,6 +48,21 @@ static const char *orig_filename;
|
||||
static char *privheader, *header, *template;
|
||||
static const char *headerbase = STEM;
|
||||
|
||||
/* XXX same as der_length_tag */
|
||||
static size_t
|
||||
length_tag(unsigned int tag)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if(tag <= 30)
|
||||
return 1;
|
||||
while(tag) {
|
||||
tag /= 128;
|
||||
len++;
|
||||
}
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* list of all IMPORTs
|
||||
*/
|
||||
@@ -162,6 +177,7 @@ init_generate (const char *filename, const char *base)
|
||||
"#define __%s_h__\n\n", headerbase, headerbase);
|
||||
fprintf (headerfile,
|
||||
"#include <stddef.h>\n"
|
||||
"#include <stdint.h>\n"
|
||||
"#include <time.h>\n\n");
|
||||
fprintf (headerfile,
|
||||
"#ifndef __asn1_common_definitions__\n"
|
||||
@@ -517,12 +533,36 @@ generate_constant (const Symbol *s)
|
||||
int
|
||||
is_primitive_type(const Type *t)
|
||||
{
|
||||
/*
|
||||
* Start by chasing aliasings like this:
|
||||
*
|
||||
* Type0 ::= ...
|
||||
* Type1 ::= Type0
|
||||
* ..
|
||||
* TypeN ::= TypeN-1
|
||||
*
|
||||
* to <Type0>, then check if <Type0> is primitive.
|
||||
*/
|
||||
while (t->type == TType &&
|
||||
t->symbol &&
|
||||
t->symbol->type &&
|
||||
t->symbol->type->type == TType)
|
||||
t = t->symbol->type;
|
||||
/* EXPLICIT non-UNIVERSAL tags are constructed */
|
||||
t->symbol->type) {
|
||||
if (t->symbol->type->type == TType)
|
||||
t = t->symbol->type; /* Alias */
|
||||
else if (t->symbol->type->type == TTag &&
|
||||
t->symbol->type->tag.tagenv == TE_IMPLICIT)
|
||||
/*
|
||||
* IMPLICIT-tagged alias, something like:
|
||||
*
|
||||
* Type0 ::= [0] IMPLICIT ...
|
||||
*
|
||||
* Just recurse.
|
||||
*/
|
||||
return is_primitive_type(t->symbol->type);
|
||||
else
|
||||
break;
|
||||
|
||||
}
|
||||
/* EXPLICIT non-UNIVERSAL tags are always constructed */
|
||||
if (t->type == TTag && t->tag.tagclass != ASN1_C_UNIV &&
|
||||
t->tag.tagenv == TE_EXPLICIT)
|
||||
return 0;
|
||||
@@ -561,6 +601,8 @@ is_primitive_type(const Type *t)
|
||||
case TVisibleString:
|
||||
case TNull:
|
||||
return 1;
|
||||
case TTag:
|
||||
return is_primitive_type(t->subtype);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1270,30 +1312,70 @@ generate_subtypes_header(const Symbol *s)
|
||||
static void
|
||||
generate_type_header (const Symbol *s)
|
||||
{
|
||||
Type *t = s->type;
|
||||
if (!s->type)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Recurse down the types of member fields of `s' to make sure that
|
||||
* referenced types have had their definitions emitted already if the
|
||||
* member fields are not OPTIONAL/DEFAULTed.
|
||||
*/
|
||||
if (s->type)
|
||||
generate_subtypes_header(s);
|
||||
|
||||
if (!s->type)
|
||||
return;
|
||||
|
||||
generate_subtypes_header(s);
|
||||
fprintf(headerfile, "/*\n");
|
||||
fprintf(headerfile, "%s ::= ", s->name);
|
||||
define_asn1 (0, s->type);
|
||||
fprintf(headerfile, "\n*/\n\n");
|
||||
|
||||
/*
|
||||
* Emit enums for the outermost tag of this type. These are needed for
|
||||
* dealing with IMPLICIT tags so we know what to rewrite the tag to when
|
||||
* decoding.
|
||||
*
|
||||
* See gen_encode.c and gen_decode.c for a complete explanation. Short
|
||||
* version: we need to change the prototypes of the length/encode/decode
|
||||
* functions to take an optional IMPLICIT tag to use instead of the type's
|
||||
* outermost tag, but for now we hack it, and to do that we need to know
|
||||
* the type's outermost tag outside the context of the bodies of the codec
|
||||
* functions we generate for it. Using an enum means no extra space is
|
||||
* needed in stripped objects.
|
||||
*/
|
||||
if (!s->emitted_tag_enums) {
|
||||
while (t->type == TType && s->type->symbol && s->type->symbol->type)
|
||||
t = s->type->symbol->type;
|
||||
|
||||
if (t->type == TType && t->symbol && strcmp(t->symbol->name, "heim_any")) {
|
||||
/*
|
||||
* This type is ultimately an alias of an imported type, so we don't
|
||||
* know its outermost tag here.
|
||||
*/
|
||||
fprintf(headerfile,
|
||||
"enum { asn1_tag_length_%s = asn1_tag_length_%s,\n"
|
||||
" asn1_tag_class_%s = asn1_tag_class_%s,\n"
|
||||
" asn1_tag_tag_%s = asn1_tag_tag_%s };\n",
|
||||
s->gen_name, s->type->symbol->gen_name,
|
||||
s->gen_name, s->type->symbol->gen_name,
|
||||
s->gen_name, s->type->symbol->gen_name);
|
||||
emitted_tag_enums(s);
|
||||
} else if (t->type != TType) {
|
||||
/* This type's outermost tag is known here */
|
||||
fprintf(headerfile,
|
||||
"enum { asn1_tag_length_%s = %lu,\n"
|
||||
" asn1_tag_class_%s = %d,\n"
|
||||
" asn1_tag_tag_%s = %d };\n",
|
||||
s->gen_name, (unsigned long)length_tag(s->type->tag.tagvalue),
|
||||
s->gen_name, s->type->tag.tagclass,
|
||||
s->gen_name, s->type->tag.tagvalue);
|
||||
emitted_tag_enums(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->emitted_definition)
|
||||
return;
|
||||
|
||||
fprintf(headerfile, "typedef ");
|
||||
define_type(0, s->gen_name, s->gen_name, s->type, TRUE,
|
||||
preserve_type(s->name) ? TRUE : FALSE);
|
||||
|
||||
fprintf(headerfile, "\n");
|
||||
|
||||
if (template_flag)
|
||||
|
@@ -362,6 +362,20 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval,
|
||||
break;
|
||||
}
|
||||
case TSet: {
|
||||
/*
|
||||
* SET { ... } is the dumbest construct in ASN.1. It's semantically
|
||||
* indistinguishable from SEQUENCE { ... } but in BER you can write the
|
||||
* fields in any order you wish, and in DER you have to write them in
|
||||
* lexicographic order. If you want a reason to hate ASN.1, this is
|
||||
* certainly one, though the real reason to hate ASN.1 is BER/DER/CER,
|
||||
* and, really, all tag-length-value (TLV) encodings ever invented,
|
||||
* including Protocol Buffers. Fortunately not all ASN.1 encoding
|
||||
* rules are TLV or otherwise self-describing. "Self-describing"
|
||||
* encoding rules other than those meant to be [somewhat] readable by
|
||||
* humans, such as XML and JSON, are simply dumb. But SET { ... } is a
|
||||
* truly special sort of dumb. The only possible use of SET { ... }
|
||||
* might well be for ASN.1 mappings of XML schemas(?).
|
||||
*/
|
||||
Member *m;
|
||||
unsigned int memno;
|
||||
|
||||
@@ -391,6 +405,7 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval,
|
||||
|
||||
fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n",
|
||||
classname(mst->tag.tagclass),
|
||||
(mst->tag.tagclass == ASN1_C_UNIV || mst->tag.tagenv == TE_IMPLICIT) &&
|
||||
is_primitive_type(mst->subtype) ? "PRIM" : "CONS",
|
||||
valuename(mst->tag.tagclass, mst->tag.tagvalue));
|
||||
|
||||
@@ -506,17 +521,41 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval,
|
||||
t->tag.tagenv == TE_EXPLICIT) &&
|
||||
is_primitive_type(t->subtype);
|
||||
|
||||
/*
|
||||
* XXX See the comments in gen_encode() about this.
|
||||
*/
|
||||
if (t->tag.tagenv == TE_IMPLICIT && !prim &&
|
||||
t->subtype->type != TSequenceOf && t->subtype->type != TSetOf &&
|
||||
t->subtype->type != TChoice) {
|
||||
if (t->subtype->symbol &&
|
||||
(t->subtype->type == TSequence ||
|
||||
t->subtype->type == TSet))
|
||||
replace_tag = 1;
|
||||
else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any"))
|
||||
replace_tag = 1;
|
||||
} else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol)
|
||||
replace_tag = 1;
|
||||
|
||||
if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL)
|
||||
errx(1, "malloc");
|
||||
|
||||
fprintf(codefile,
|
||||
"{\n"
|
||||
"size_t %s_datalen, %s_oldlen;\n"
|
||||
"size_t %s_datalen;\n"
|
||||
"Der_type %s;\n",
|
||||
tmpstr, tmpstr, typestring);
|
||||
if(support_ber)
|
||||
tmpstr, typestring);
|
||||
if (replace_tag)
|
||||
fprintf(codefile,
|
||||
"const unsigned char *psave%u = p;\n"
|
||||
"unsigned char *pcopy%u;\n"
|
||||
"size_t lensave%u, lsave%u;\n",
|
||||
depth, depth, depth, depth);
|
||||
else if (support_ber)
|
||||
fprintf(codefile,
|
||||
"int is_indefinite%u;\n", depth);
|
||||
if (!replace_tag)
|
||||
fprintf(codefile,
|
||||
"size_t %s_oldlen;\n", tmpstr);
|
||||
|
||||
fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, "
|
||||
"&%s_datalen, &l);\n",
|
||||
@@ -526,7 +565,7 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval,
|
||||
tmpstr);
|
||||
|
||||
/* XXX hardcode for now */
|
||||
if (support_ber && t->subtype->type == TOctetString) {
|
||||
if (!replace_tag && support_ber && t->subtype->type == TOctetString) {
|
||||
ide = typestring;
|
||||
} else {
|
||||
fprintf(codefile,
|
||||
@@ -556,62 +595,50 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval,
|
||||
} else {
|
||||
fprintf(codefile, "if (e) %s;\n", forwstr);
|
||||
}
|
||||
fprintf (codefile,
|
||||
"p += l; len -= l; ret += l;\n"
|
||||
"%s_oldlen = len;\n",
|
||||
tmpstr);
|
||||
if(support_ber)
|
||||
|
||||
if (replace_tag)
|
||||
fprintf(codefile,
|
||||
"lsave%u = %s_datalen + l;\n"
|
||||
"lensave%u = len;\n"
|
||||
"e = der_replace_tag(p, len, &pcopy%u, &len, asn1_tag_class_%s, %s, asn1_tag_tag_%s);\n"
|
||||
"if (e) %s;\n"
|
||||
"p = pcopy%u;\n",
|
||||
depth, tmpstr, depth, depth, t->subtype->symbol->gen_name,
|
||||
prim ? "PRIM" : "CONS",
|
||||
t->subtype->symbol->gen_name,
|
||||
forwstr, depth);
|
||||
else
|
||||
fprintf(codefile,
|
||||
"p += l; len -= l; ret += l;\n");
|
||||
if (!replace_tag)
|
||||
fprintf(codefile,
|
||||
"%s_oldlen = len;\n",
|
||||
tmpstr);
|
||||
if (support_ber && !replace_tag)
|
||||
fprintf (codefile,
|
||||
"if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
|
||||
"{ e = ASN1_BAD_FORMAT; %s; }\n"
|
||||
"if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }",
|
||||
depth, tmpstr, forwstr, depth, forwstr);
|
||||
else
|
||||
else if (!replace_tag)
|
||||
fprintf(codefile,
|
||||
"if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
|
||||
"len = %s_datalen;\n", tmpstr, forwstr, tmpstr);
|
||||
if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL)
|
||||
errx(1, "malloc");
|
||||
/*
|
||||
* XXX See the comments in gen_encode() about this.
|
||||
* If `replace_tag' then here `p' and `len' will be the copy mutated by
|
||||
* der_replace_tag().
|
||||
*/
|
||||
if (t->tag.tagenv == TE_IMPLICIT && !prim &&
|
||||
t->subtype->type != TSequenceOf && t->subtype->type != TSetOf &&
|
||||
t->subtype->type != TChoice) {
|
||||
if (t->subtype->symbol &&
|
||||
(t->subtype->type == TSequence ||
|
||||
t->subtype->type == TSet))
|
||||
replace_tag = 1;
|
||||
else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any"))
|
||||
replace_tag = 1;
|
||||
} else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol)
|
||||
replace_tag = 1;
|
||||
if (replace_tag) {
|
||||
/*
|
||||
* XXX We're assuming the IMPLICIT and original tags have the same
|
||||
* length. This is one of the places that needs fixing if we want
|
||||
* to properly support tags > 30.
|
||||
*/
|
||||
decode_type(name, t->subtype, 0, NULL, forwstr, tname, ide, depth + 1);
|
||||
if (replace_tag)
|
||||
fprintf(codefile,
|
||||
"{ unsigned char *pcopy;\n"
|
||||
"pcopy = calloc (1, len);\n"
|
||||
"if (pcopy == 0) { e = ENOMEM; %s;}\n"
|
||||
"memcpy (pcopy, p, len);\n"
|
||||
"e = der_replace_tag (pcopy, len, %s, %s, %s);\n"
|
||||
"if (e) %s;\n",
|
||||
forwstr,
|
||||
classname(t->subtype->tag.tagclass),
|
||||
prim ? "PRIM" : "CONS",
|
||||
valuename(t->subtype->tag.tagclass, t->subtype->tag.tagvalue),
|
||||
forwstr);
|
||||
decode_type(name, t->subtype, 0, NULL, forwstr, tname, ide, depth + 1);
|
||||
fprintf(codefile,
|
||||
"free(pcopy);"
|
||||
"}\n");
|
||||
} else {
|
||||
decode_type(name, t->subtype, 0, NULL, forwstr, tname, ide, depth + 1);
|
||||
}
|
||||
if(support_ber)
|
||||
"p = psave%u + lsave%u;\n"
|
||||
"len = lensave%u - lsave%u;\n"
|
||||
"ret += lsave%u - l;\n"
|
||||
"free(pcopy%u);\n",
|
||||
depth, depth, depth, depth, depth, depth);
|
||||
else if(support_ber)
|
||||
fprintf(codefile,
|
||||
"if(is_indefinite%u){\n"
|
||||
"len += 2;\n"
|
||||
@@ -627,9 +654,10 @@ decode_type(const char *name, const Type *t, int optional, struct value *defval,
|
||||
tmpstr,
|
||||
forwstr,
|
||||
typestring, forwstr);
|
||||
fprintf(codefile,
|
||||
"len = %s_oldlen - %s_datalen;\n",
|
||||
tmpstr, tmpstr);
|
||||
if (!replace_tag)
|
||||
fprintf(codefile,
|
||||
"len = %s_oldlen - %s_datalen;\n",
|
||||
tmpstr, tmpstr);
|
||||
if (optional)
|
||||
fprintf(codefile, "}\n");
|
||||
else if (defval)
|
||||
|
@@ -33,6 +33,21 @@
|
||||
|
||||
#include "gen_locl.h"
|
||||
|
||||
/* XXX same as der_length_tag */
|
||||
static size_t
|
||||
length_tag(unsigned int tag)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if(tag <= 30)
|
||||
return 1;
|
||||
while(tag) {
|
||||
tag /= 128;
|
||||
len++;
|
||||
}
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
static void
|
||||
encode_primitive (const char *typename, const char *name)
|
||||
{
|
||||
@@ -395,14 +410,10 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
|
||||
int c;
|
||||
if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
|
||||
errx(1, "malloc");
|
||||
c = encode_type (name, t->subtype, tname);
|
||||
/* Explicit tags are always constructed */
|
||||
if (!c && t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT)
|
||||
c = 1;
|
||||
/*
|
||||
* HACK HACK HACK
|
||||
*
|
||||
* This is part of the fix to the bug where we treat IMPLICIT tags of
|
||||
* This is part of the fix to the bug where we treated IMPLICIT tags of
|
||||
* named types as EXPLICIT. I.e.
|
||||
*
|
||||
* Foo ::= SEQUENCE { ... }
|
||||
@@ -412,37 +423,29 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
|
||||
* constructed tag when it should get only the first tag.
|
||||
*
|
||||
* Properly fixing this would require changing the signatures of the
|
||||
* encode, lenght, and decode functions we generate to take an optional
|
||||
* encode, length, and decode functions we generate to take an optional
|
||||
* tag to replace the one the encoder would generate / decoder would
|
||||
* expect. That would change the ABI, which... isn't stable, but it's
|
||||
* a bit soon to make that change.
|
||||
*
|
||||
* So, we're looking for IMPLICIT tags of named SEQUENCE/SET types, and
|
||||
* if we see any, we generate code to replace the tag.
|
||||
* So, we're looking for IMPLICIT, and if we see any, we generate code
|
||||
* to replace the tag.
|
||||
*
|
||||
* NOTE WELL: We're assuming that the length of the encoding of the tag
|
||||
* of the subtype and the length of the encoding of the
|
||||
* IMPLICIT tag are the same.
|
||||
* On the decode side we need to know what tag to restore. For this we
|
||||
* generate enums in the generated header.
|
||||
*
|
||||
* To avoid this we'll need to generate new length_tag_*
|
||||
* functions or else we'll need to add a boolean argument to
|
||||
* the length_* functions we generate to count only the
|
||||
* length of the tag of the type. The latter is an ABI
|
||||
* change. Or we'll need to enhance asn1_compile to be able
|
||||
* to load multiple modules so that we use the AST of the
|
||||
* modules to internally compute the length of types and
|
||||
* tags. The latter would be great anyways as it would
|
||||
* allow the computation of tag lengths for tagged types to
|
||||
* be constant.
|
||||
*
|
||||
* NOTE WELL: We *do* "replace" the tags of IMPLICIT-tagged primitive
|
||||
* types, but our primitive codec functions leave those tags
|
||||
* out, which is why we don't have to der_replace_tag() them
|
||||
* here.
|
||||
* NOTE: We *do* "replace" the tags of IMPLICIT-tagged primitive types,
|
||||
* but our primitive codec functions leave those tags out, which
|
||||
* is why we don't have to der_replace_tag() them here.
|
||||
*/
|
||||
/*
|
||||
* If the tag is IMPLICIT and it's not primitive and the subtype is not
|
||||
* any kind of structure...
|
||||
*/
|
||||
if (t->tag.tagenv == TE_IMPLICIT && !prim &&
|
||||
t->subtype->type != TSequenceOf && t->subtype->type != TSetOf &&
|
||||
t->subtype->type != TChoice) {
|
||||
/* If it is a named type for a structured thing */
|
||||
if (t->subtype->symbol &&
|
||||
(t->subtype->type == TSequence ||
|
||||
t->subtype->type == TSet))
|
||||
@@ -456,13 +459,132 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
|
||||
* tags unlike our raw primtive codec library.
|
||||
*/
|
||||
replace_tag = 1;
|
||||
|
||||
if (replace_tag)
|
||||
fprintf(codefile,
|
||||
"e = der_replace_tag (p, len, %s, %s, %s);\n"
|
||||
"if (e) return e;\np -= l; len -= l; ret += l;\n\n",
|
||||
"{ unsigned char *psave_%s = p;\n"
|
||||
"size_t l2_%s, lensave_%s = len;\n"
|
||||
"len = length_%s(%s);\n"
|
||||
/* Allocate a temp buffer for the encoder */
|
||||
"if ((p = malloc(len)) == NULL) return ENOMEM;\n"
|
||||
/* Make p point to the last byte of the allocated buf */
|
||||
"p += len - 1;\n",
|
||||
tmpstr, tmpstr, tmpstr,
|
||||
t->subtype->symbol->gen_name, name);
|
||||
|
||||
c = encode_type (name, t->subtype, tname);
|
||||
/* Explicit non-UNIVERSAL tags are always constructed */
|
||||
if (!c && t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT)
|
||||
c = 1;
|
||||
if (replace_tag)
|
||||
fprintf(codefile,
|
||||
"if (len) abort();\n"
|
||||
/*
|
||||
* Here we have `p' pointing to one byte before the buffer
|
||||
* we allocated above.
|
||||
*
|
||||
* [ T_wrong | LL | VVVV ] // temp buffer
|
||||
* ^ ^
|
||||
* | |
|
||||
* | \
|
||||
* \ +-- p + 1
|
||||
* +-- p
|
||||
*
|
||||
* psave_<fieldName> still points to the last byte in the
|
||||
* original buffer passed in where we should write the
|
||||
* encoding of <fieldName>.
|
||||
*
|
||||
* We adjust psave_<fieldName> to point to before the TLV
|
||||
* encoding of <fieldName> (with wrong tag) in the original
|
||||
* buffer (this may NOT be a valid pointer, but we won't
|
||||
* dereference it):
|
||||
*
|
||||
* [ ... | T_wrong | LL | VVVVV | ... ] // original buffer
|
||||
* ^
|
||||
* |
|
||||
* \
|
||||
* +-- psave_<fieldName>
|
||||
*/
|
||||
"psave_%s -= l;\n"
|
||||
/*
|
||||
* We further adjust psave_<fieldName> to point to the last
|
||||
* byte of what should be the T(ag) of the TLV encoding of
|
||||
* <fieldName> (this is now a valid pointer), then...
|
||||
*
|
||||
* |<--->| (not written yet)
|
||||
* | | |<-------->| (not written yet)
|
||||
* [ ... | T_right | LL | VVVVV | ... ] // original buffer
|
||||
* ^
|
||||
* |
|
||||
* \
|
||||
* +-- psave_<fieldName>
|
||||
*/
|
||||
"psave_%s += asn1_tag_length_%s;\n"
|
||||
/*
|
||||
* ...copy the L(ength)V(alue) of the TLV encoding of
|
||||
* <fieldName>.
|
||||
*
|
||||
* [ ... | T_right | LL | VVVVV | ... ] // original buffer
|
||||
* ^
|
||||
* |
|
||||
* \
|
||||
* +-- psave_<fieldName> + 1
|
||||
*
|
||||
* |<----->| length is
|
||||
* | | `l' - asn1_tag_length_<fieldName>
|
||||
* [ T_wrong | LL | VVVV ] // temp buffer
|
||||
* ^ ^
|
||||
* | |
|
||||
* | \
|
||||
* \ +-- p + 1 + asn1_tag_length_%s
|
||||
* +-- p + 1
|
||||
*/
|
||||
"memcpy(psave_%s + 1, p + 1 + asn1_tag_length_%s, l - asn1_tag_length_%s);\n"
|
||||
/*
|
||||
* Encode the IMPLICIT tag. Recall that encoders like
|
||||
* der_put_tag() take a pointer to the last byte they
|
||||
* should write to, and a length of bytes to the left of
|
||||
* that that they are allowed to write into.
|
||||
*
|
||||
* [ ... | T_right | LL | VVVVV | ... ] // original buffer
|
||||
* ^
|
||||
* |
|
||||
* \
|
||||
* +-- psave_<fieldName>
|
||||
*/
|
||||
"e = der_put_tag(psave_%s, %lu, %s, %s, %d, &l2_%s);\n"
|
||||
"if (e) return e;\n"
|
||||
/* Restore `len' and adjust it (see `p' below) */
|
||||
"len = lensave_%s - (l + %lu - asn1_tag_length_%s);\n"
|
||||
/*
|
||||
* Adjust `ret' to account for the difference in size
|
||||
* between the length of the right and wrong tags.
|
||||
*/
|
||||
"ret += %lu - asn1_tag_length_%s;\n"
|
||||
/* Free the buffer and restore `p' */
|
||||
"free(p + 1);\n"
|
||||
/*
|
||||
* Make `p' point into the original buffer again, to one
|
||||
* byte before the bytes we wrote:
|
||||
*
|
||||
* [ ... | T_right | LL | VVVVV | ... ] // original buffer
|
||||
* ^
|
||||
* |
|
||||
* \
|
||||
* +-- p
|
||||
*/
|
||||
"p = psave_%s - (1 + %lu - asn1_tag_length_%s); }\n",
|
||||
tmpstr, tmpstr, t->subtype->symbol->name,
|
||||
tmpstr, t->subtype->symbol->name, t->subtype->symbol->name,
|
||||
tmpstr, length_tag(t->tag.tagvalue),
|
||||
classname(t->tag.tagclass),
|
||||
c ? "CONS" : "PRIM",
|
||||
valuename(t->tag.tagclass, t->tag.tagvalue));
|
||||
t->tag.tagvalue,
|
||||
tmpstr,
|
||||
|
||||
tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name,
|
||||
length_tag(t->tag.tagvalue), t->subtype->symbol->name,
|
||||
tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name);
|
||||
else
|
||||
fprintf(codefile,
|
||||
"e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
|
||||
@@ -471,6 +593,7 @@ encode_type (const char *name, const Type *t, const char *tmpstr)
|
||||
c ? "CONS" : "PRIM",
|
||||
valuename(t->tag.tagclass, t->tag.tagvalue));
|
||||
free(tname);
|
||||
constructed = c;
|
||||
break;
|
||||
}
|
||||
case TChoice:{
|
||||
|
@@ -256,9 +256,7 @@ length_type (const char *name, const Type *t,
|
||||
if (asprintf(&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
|
||||
errx(1, "malloc");
|
||||
length_type (name, t->subtype, variable, tname);
|
||||
/*
|
||||
* XXX See the comments in gen_encode() about this.
|
||||
*/
|
||||
/* See the comments in encode_type() about IMPLICIT tags */
|
||||
if (t->tag.tagenv == TE_IMPLICIT && !prim &&
|
||||
t->subtype->type != TSequenceOf && t->subtype->type != TSetOf &&
|
||||
t->subtype->type != TChoice) {
|
||||
@@ -270,7 +268,18 @@ length_type (const char *name, const Type *t,
|
||||
replace_tag = 1;
|
||||
} else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol)
|
||||
replace_tag = 1;
|
||||
if (!replace_tag)
|
||||
if (replace_tag)
|
||||
/*
|
||||
* We're replacing the tag of the underlying type. If that type is
|
||||
* imported, then we don't know its tag, so we rely on the
|
||||
* asn1_tag_tag_<TypeName> enum value we generated for it, and we
|
||||
* use the asn1_tag_length_<TypeName> enum value to avoid having to
|
||||
* call der_length_tag() at run-time.
|
||||
*/
|
||||
fprintf(codefile, "ret += %lu - asn1_tag_length_%s;\n",
|
||||
(unsigned long)length_tag(t->tag.tagvalue),
|
||||
t->subtype->symbol->gen_name);
|
||||
else
|
||||
fprintf(codefile, "ret += %lu + der_length_len (ret);\n",
|
||||
(unsigned long)length_tag(t->tag.tagvalue));
|
||||
free(tname);
|
||||
|
@@ -165,3 +165,9 @@ emitted_definition(const Symbol *s)
|
||||
{
|
||||
((Symbol *)(uintptr_t)s)->emitted_definition = 1;
|
||||
}
|
||||
|
||||
void
|
||||
emitted_tag_enums(const Symbol *s)
|
||||
{
|
||||
((Symbol *)(uintptr_t)s)->emitted_tag_enums = 1;
|
||||
}
|
||||
|
@@ -159,6 +159,7 @@ struct symbol {
|
||||
HEIM_TAILQ_ENTRY(symbol) symlist;
|
||||
unsigned int emitted_declaration:1;
|
||||
unsigned int emitted_definition:1;
|
||||
unsigned int emitted_tag_enums:1;
|
||||
};
|
||||
|
||||
typedef struct symbol Symbol;
|
||||
@@ -179,4 +180,5 @@ int checkundefined(void);
|
||||
void generate_types(void);
|
||||
void emitted_declaration(const Symbol *);
|
||||
void emitted_definition(const Symbol *);
|
||||
void emitted_tag_enums(const Symbol *);
|
||||
#endif
|
||||
|
@@ -74,9 +74,10 @@ TESTImplicit ::= SEQUENCE {
|
||||
}
|
||||
|
||||
TESTImplicit2 ::= SEQUENCE {
|
||||
ti1[0] IMPLICIT TESTInteger,
|
||||
-- ti2[1] IMPLICIT TESTLargeTag, this is disabled since the IMPLICT encoder does't get the types right when stepping inside an structure --
|
||||
ti3[2] IMPLICIT TESTInteger3
|
||||
ti1[0] IMPLICIT TESTInteger,
|
||||
-- ti2[1] IMPLICIT TESTLargeTag, this is disabled since the IMPLICT encoder does't get the types right when stepping inside an structure --
|
||||
ti3[2] IMPLICIT TESTInteger3,
|
||||
ti4[51] IMPLICIT TESTInteger OPTIONAL
|
||||
}
|
||||
|
||||
TESTAllocInner ::= SEQUENCE {
|
||||
|
Reference in New Issue
Block a user