1 /*-
2  * Copyright (c) 2004, 2007 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 /*
6  * Read the NativeInteger.h for the explanation wrt. differences between
7  * INTEGER and NativeInteger.
8  * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this
9  * implementation deals with the standard (machine-specific) representation
10  * of them instead of using the platform-independent buffer.
11  */
12 #include <asn_internal.h>
13 #include <NativeEnumerated.h>
14 
15 /*
16  * NativeEnumerated basic type description.
17  */
18 static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = {
19 	(ASN_TAG_CLASS_UNIVERSAL | (10 << 2))
20 };
21 asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = {
22 	"ENUMERATED",			/* The ASN.1 type is still ENUMERATED */
23 	"ENUMERATED",
24 	NativeInteger_free,
25 	NativeInteger_print,
26 	asn_generic_no_constraint,
27 	NativeInteger_decode_ber,
28 	NativeInteger_encode_der,
29 	NativeInteger_decode_xer,
30 	NativeEnumerated_encode_xer,
31 	NativeEnumerated_decode_uper,
32 	NativeEnumerated_encode_uper,
33 	0, /* Use generic outmost tag fetcher */
34 	asn_DEF_NativeEnumerated_tags,
35 	sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]),
36 	asn_DEF_NativeEnumerated_tags,	/* Same as above */
37 	sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]),
38 	0,	/* No PER visible constraints */
39 	0, 0,	/* No members */
40 	0	/* No specifics */
41 };
42 
43 asn_enc_rval_t
NativeEnumerated_encode_xer(asn_TYPE_descriptor_t * td,void * sptr,int ilevel,enum xer_encoder_flags_e flags,asn_app_consume_bytes_f * cb,void * app_key)44 NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
45         int ilevel, enum xer_encoder_flags_e flags,
46                 asn_app_consume_bytes_f *cb, void *app_key) {
47 	asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
48         asn_enc_rval_t er;
49         const long *native = (const long *)sptr;
50 	const asn_INTEGER_enum_map_t *el;
51 
52         (void)ilevel;
53         (void)flags;
54 
55         if(!native) _ASN_ENCODE_FAILED;
56 
57 	el = INTEGER_map_value2enum(specs, *native);
58 	if(el) {
59 		size_t srcsize = el->enum_len + 5;
60 		char *src = (char *)alloca(srcsize);
61 
62 		er.encoded = snprintf(src, srcsize, "<%s/>", el->enum_name);
63 		assert(er.encoded > 0 && (size_t)er.encoded < srcsize);
64 		if(cb(src, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED;
65 		_ASN_ENCODED_OK(er);
66 	} else {
67 		ASN_DEBUG("ASN.1 forbids dealing with "
68 			"unknown value of ENUMERATED type");
69 		_ASN_ENCODE_FAILED;
70 	}
71 }
72 
73 asn_dec_rval_t
NativeEnumerated_decode_uper(asn_codec_ctx_t * opt_codec_ctx,asn_TYPE_descriptor_t * td,asn_per_constraints_t * constraints,void ** sptr,asn_per_data_t * pd)74 NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
75 	asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
76 	void **sptr, asn_per_data_t *pd) {
77 	asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics;
78 	asn_dec_rval_t rval = { RC_OK, 0 };
79 	long *native = (long *)*sptr;
80 	asn_per_constraint_t *ct;
81 	long value;
82 
83 	(void)opt_codec_ctx;
84 
85 	if(constraints) ct = &constraints->value;
86 	else if(td->per_constraints) ct = &td->per_constraints->value;
87 	else _ASN_DECODE_FAILED;	/* Mandatory! */
88 	if(!specs) _ASN_DECODE_FAILED;
89 
90 	if(!native) {
91 		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
92 		if(!native) _ASN_DECODE_FAILED;
93 	}
94 
95 	ASN_DEBUG("Decoding %s as NativeEnumerated", td->name);
96 
97 	if(ct->flags & APC_EXTENSIBLE) {
98 		int inext = per_get_few_bits(pd, 1);
99 		if(inext < 0) _ASN_DECODE_STARVED;
100 		if(inext) ct = 0;
101 	}
102 
103 	if(ct && ct->range_bits >= 0) {
104 		value = per_get_few_bits(pd, ct->range_bits);
105 		if(value < 0) _ASN_DECODE_STARVED;
106 		if(value >= (specs->extension
107 			? specs->extension - 1 : specs->map_count))
108 			_ASN_DECODE_FAILED;
109 	} else {
110 		if(!specs->extension)
111 			_ASN_DECODE_FAILED;
112 		/*
113 		 * X.691, #10.6: normally small non-negative whole number;
114 		 */
115 		value = uper_get_nsnnwn(pd);
116 		if(value < 0) _ASN_DECODE_STARVED;
117 		value += specs->extension - 1;
118 		if(value >= specs->map_count)
119 			_ASN_DECODE_FAILED;
120 	}
121 
122 	*native = specs->value2enum[value].nat_value;
123 	ASN_DEBUG("Decoded %s = %ld", td->name, *native);
124 
125 	return rval;
126 }
127 
128 static int
NativeEnumerated__compar_value2enum(const void * ap,const void * bp)129 NativeEnumerated__compar_value2enum(const void *ap, const void *bp) {
130 	const asn_INTEGER_enum_map_t *a = ap;
131 	const asn_INTEGER_enum_map_t *b = bp;
132 	if(a->nat_value == b->nat_value)
133 		return 0;
134 	if(a->nat_value < b->nat_value)
135 		return -1;
136 	return 1;
137 }
138 
139 asn_enc_rval_t
NativeEnumerated_encode_uper(asn_TYPE_descriptor_t * td,asn_per_constraints_t * constraints,void * sptr,asn_per_outp_t * po)140 NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td,
141 	asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
142 	asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics;
143 	asn_enc_rval_t er;
144 	long native, value;
145 	asn_per_constraint_t *ct;
146 	int inext = 0;
147 	asn_INTEGER_enum_map_t key;
148 	asn_INTEGER_enum_map_t *kf;
149 
150 	if(!sptr) _ASN_ENCODE_FAILED;
151 	if(!specs) _ASN_ENCODE_FAILED;
152 
153 	if(constraints) ct = &constraints->value;
154 	else if(td->per_constraints) ct = &td->per_constraints->value;
155 	else _ASN_ENCODE_FAILED;	/* Mandatory! */
156 
157 	ASN_DEBUG("Encoding %s as NativeEnumerated", td->name);
158 
159 	er.encoded = 0;
160 
161 	native = *(long *)sptr;
162 	if(native < 0) _ASN_ENCODE_FAILED;
163 
164 	key.nat_value = native;
165 	kf = bsearch(&key, specs->value2enum, specs->map_count,
166 		sizeof(key), NativeEnumerated__compar_value2enum);
167 	if(!kf) {
168 		ASN_DEBUG("No element corresponds to %ld", native);
169 		_ASN_ENCODE_FAILED;
170 	}
171 	value = kf - specs->value2enum;
172 
173 	if(ct->range_bits >= 0) {
174 		int cmpWith = specs->extension
175 				? specs->extension - 1 : specs->map_count;
176 		if(value >= cmpWith)
177 			inext = 1;
178 	}
179 	if(ct->flags & APC_EXTENSIBLE) {
180 		if(per_put_few_bits(po, inext, 1))
181 			_ASN_ENCODE_FAILED;
182 		if(inext) ct = 0;
183 	} else if(inext) {
184 		_ASN_ENCODE_FAILED;
185 	}
186 
187 	if(ct && ct->range_bits >= 0) {
188 		if(per_put_few_bits(po, value, ct->range_bits))
189 			_ASN_ENCODE_FAILED;
190 		_ASN_ENCODED_OK(er);
191 	}
192 
193 	if(!specs->extension)
194 		_ASN_ENCODE_FAILED;
195 
196 	/*
197 	 * X.691, #10.6: normally small non-negative whole number;
198 	 */
199 	ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld",
200 		value, specs->extension, inext,
201 		value - (inext ? (specs->extension - 1) : 0));
202 	if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0)))
203 		_ASN_ENCODE_FAILED;
204 
205 	_ASN_ENCODED_OK(er);
206 }
207 
208