NativeInteger.c 13.2 KB
Newer Older
Lev Walkin's avatar
Lev Walkin committed
1
/*-
Lev Walkin's avatar
Lev Walkin committed
2 3
 * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
 * All rights reserved.
Lev Walkin's avatar
Lev Walkin committed
4 5 6
 * Redistribution and modifications are permitted subject to BSD license.
 */
/*
Lev Walkin's avatar
Lev Walkin committed
7
 * Read the NativeInteger.h for the explanation wrt. differences between
Lev Walkin's avatar
Lev Walkin committed
8 9 10 11 12
 * INTEGER and NativeInteger.
 * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this
 * implementation deals with the standard (machine-specific) representation
 * of them instead of using the platform-independent buffer.
 */
Lev Walkin's avatar
Lev Walkin committed
13
#include <asn_internal.h>
Lev Walkin's avatar
Lev Walkin committed
14 15 16 17 18
#include <NativeInteger.h>

/*
 * NativeInteger basic type description.
 */
19
static const ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = {
Lev Walkin's avatar
Lev Walkin committed
20 21
	(ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
};
22
asn_TYPE_operation_t asn_OP_NativeInteger = {
Lev Walkin's avatar
Lev Walkin committed
23 24
	NativeInteger_free,
	NativeInteger_print,
25
	NativeInteger_compare,
Lev Walkin's avatar
Lev Walkin committed
26 27
	NativeInteger_decode_ber,
	NativeInteger_encode_der,
Lev Walkin's avatar
Lev Walkin committed
28
	NativeInteger_decode_xer,
Lev Walkin's avatar
Lev Walkin committed
29
	NativeInteger_encode_xer,
Lev Walkin's avatar
Lev Walkin committed
30 31 32 33
#ifdef	ASN_DISABLE_OER_SUPPORT
	0,
	0,
#else
Lev Walkin's avatar
Lev Walkin committed
34 35
	NativeInteger_decode_oer,	/* OER decoder */
	NativeInteger_encode_oer,	/* Canonical OER encoder */
Lev Walkin's avatar
Lev Walkin committed
36
#endif  /* ASN_DISABLE_OER_SUPPORT */
Lev Walkin's avatar
Lev Walkin committed
37 38 39 40 41 42 43
#ifdef	ASN_DISABLE_PER_SUPPORT
	0,
	0,
#else
	NativeInteger_decode_uper,	/* Unaligned PER decoder */
	NativeInteger_encode_uper,	/* Unaligned PER encoder */
#endif	/* ASN_DISABLE_PER_SUPPORT */
44
	NativeInteger_random_fill,
45 46 47 48 49 50
	0	/* Use generic outmost tag fetcher */
};
asn_TYPE_descriptor_t asn_DEF_NativeInteger = {
	"INTEGER",			/* The ASN.1 type is still INTEGER */
	"INTEGER",
	&asn_OP_NativeInteger,
Lev Walkin's avatar
Lev Walkin committed
51 52 53 54
	asn_DEF_NativeInteger_tags,
	sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]),
	asn_DEF_NativeInteger_tags,	/* Same as above */
	sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]),
55
	{ 0, 0, asn_generic_no_constraint },
Lev Walkin's avatar
Lev Walkin committed
56
	0, 0,	/* No members */
57
	0	/* No specifics */
Lev Walkin's avatar
Lev Walkin committed
58 59 60 61 62
};

/*
 * Decode INTEGER type.
 */
Lev Walkin's avatar
Lev Walkin committed
63
asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
64
NativeInteger_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin's avatar
Lev Walkin committed
65
	asn_TYPE_descriptor_t *td,
Lev Walkin's avatar
Lev Walkin committed
66
	void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) {
Lev Walkin's avatar
Lev Walkin committed
67 68 69
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    long *native = (long *)*nint_ptr;
Lev Walkin's avatar
Lev Walkin committed
70
	asn_dec_rval_t rval;
Lev Walkin's avatar
Lev Walkin committed
71 72 73 74 75
	ber_tlv_len_t length;

	/*
	 * If the structure is not there, allocate it.
	 */
Lev Walkin's avatar
Lev Walkin committed
76 77 78
	if(native == NULL) {
		native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
		if(native == NULL) {
Lev Walkin's avatar
Lev Walkin committed
79 80 81 82 83 84 85 86 87 88 89 90
			rval.code = RC_FAIL;
			rval.consumed = 0;
			return rval;
		}
	}

	ASN_DEBUG("Decoding %s as INTEGER (tm=%d)",
		td->name, tag_mode);

	/*
	 * Check tags.
	 */
Lev Walkin's avatar
Lev Walkin committed
91 92
	rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
			tag_mode, 0, &length, 0);
Lev Walkin's avatar
Lev Walkin committed
93 94 95 96 97 98 99 100
	if(rval.code != RC_OK)
		return rval;

	ASN_DEBUG("%s length is %d bytes", td->name, (int)length);

	/*
	 * Make sure we have this length.
	 */
Lev Walkin's avatar
Lev Walkin committed
101
	buf_ptr = ((const char *)buf_ptr) + rval.consumed;
Lev Walkin's avatar
Lev Walkin committed
102
	size -= rval.consumed;
103
	if(length > (ber_tlv_len_t)size) {
Lev Walkin's avatar
Lev Walkin committed
104 105 106 107 108 109 110
		rval.code = RC_WMORE;
		rval.consumed = 0;
		return rval;
	}

	/*
	 * ASN.1 encoded INTEGER: buf_ptr, length
Lev Walkin's avatar
Lev Walkin committed
111
	 * Fill the native, at the same time checking for overflow.
Lev Walkin's avatar
Lev Walkin committed
112 113 114 115
	 * If overflow occured, return with RC_FAIL.
	 */
	{
		INTEGER_t tmp;
116 117 118 119
		union {
			const void *constbuf;
			void *nonconstbuf;
		} unconst_buf;
Lev Walkin's avatar
Lev Walkin committed
120
		long l;
121 122 123

		unconst_buf.constbuf = buf_ptr;
		tmp.buf = (uint8_t *)unconst_buf.nonconstbuf;
Lev Walkin's avatar
Lev Walkin committed
124 125
		tmp.size = length;

126
		if((specs&&specs->field_unsigned)
Lev Walkin's avatar
Lev Walkin committed
127
			? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */
128
			: asn_INTEGER2long(&tmp, &l)) {
Lev Walkin's avatar
Lev Walkin committed
129 130 131 132 133
			rval.code = RC_FAIL;
			rval.consumed = 0;
			return rval;
		}

Lev Walkin's avatar
Lev Walkin committed
134
		*native = l;
Lev Walkin's avatar
Lev Walkin committed
135 136 137 138 139
	}

	rval.code = RC_OK;
	rval.consumed += length;

Lev Walkin's avatar
Lev Walkin committed
140 141
	ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)",
		(long)rval.consumed, (long)length, td->name, (long)*native);
Lev Walkin's avatar
Lev Walkin committed
142 143 144 145 146 147 148

	return rval;
}

/*
 * Encode the NativeInteger using the standard INTEGER type DER encoder.
 */
Lev Walkin's avatar
Lev Walkin committed
149
asn_enc_rval_t
Lev Walkin's avatar
Lev Walkin committed
150
NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr,
Lev Walkin's avatar
Lev Walkin committed
151 152
	int tag_mode, ber_tlv_tag_t tag,
	asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin's avatar
Lev Walkin committed
153
	unsigned long native = *(unsigned long *)ptr;	/* Disable sign ext. */
Lev Walkin's avatar
Lev Walkin committed
154
	asn_enc_rval_t erval;
Lev Walkin's avatar
Lev Walkin committed
155 156 157 158
	INTEGER_t tmp;

#ifdef	WORDS_BIGENDIAN		/* Opportunistic optimization */

Lev Walkin's avatar
Lev Walkin committed
159 160
	tmp.buf = (uint8_t *)&native;
	tmp.size = sizeof(native);
Lev Walkin's avatar
Lev Walkin committed
161 162

#else	/* Works even if WORDS_BIGENDIAN is not set where should've been */
Lev Walkin's avatar
Lev Walkin committed
163
	uint8_t buf[sizeof(native)];
Lev Walkin's avatar
Lev Walkin committed
164 165
	uint8_t *p;

Lev Walkin's avatar
Lev Walkin committed
166
	/* Prepare a fake INTEGER */
Lev Walkin's avatar
Lev Walkin committed
167
	for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8)
Lev Walkin's avatar
Lev Walkin committed
168
		*p = (uint8_t)native;
Lev Walkin's avatar
Lev Walkin committed
169 170 171 172 173 174 175 176 177 178 179 180 181 182

	tmp.buf = buf;
	tmp.size = sizeof(buf);
#endif	/* WORDS_BIGENDIAN */
	
	/* Encode fake INTEGER */
	erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key);
	if(erval.encoded == -1) {
		assert(erval.structure_ptr == &tmp);
		erval.structure_ptr = ptr;
	}
	return erval;
}

Lev Walkin's avatar
Lev Walkin committed
183 184 185 186
/*
 * Decode the chunk of XML text encoding INTEGER.
 */
asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
187
NativeInteger_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin's avatar
Lev Walkin committed
188
	asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
Lev Walkin's avatar
Lev Walkin committed
189
		const void *buf_ptr, size_t size) {
Lev Walkin's avatar
Lev Walkin committed
190 191 192
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    asn_dec_rval_t rval;
Lev Walkin's avatar
Lev Walkin committed
193
	INTEGER_t st;
Lev Walkin's avatar
Lev Walkin committed
194
	void *st_ptr = (void *)&st;
Lev Walkin's avatar
Lev Walkin committed
195
	long *native = (long *)*sptr;
Lev Walkin's avatar
Lev Walkin committed
196

Lev Walkin's avatar
Lev Walkin committed
197
	if(!native) {
Lev Walkin's avatar
Lev Walkin committed
198
		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
199
		if(!native) ASN__DECODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
200 201
	}

Lev Walkin's avatar
Lev Walkin committed
202 203
	memset(&st, 0, sizeof(st));
	rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, 
Lev Walkin's avatar
Lev Walkin committed
204
		opt_mname, buf_ptr, size);
Lev Walkin's avatar
Lev Walkin committed
205 206
	if(rval.code == RC_OK) {
		long l;
207
		if((specs&&specs->field_unsigned)
Lev Walkin's avatar
Lev Walkin committed
208
			? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */
209
			: asn_INTEGER2long(&st, &l)) {
Lev Walkin's avatar
Lev Walkin committed
210 211 212
			rval.code = RC_FAIL;
			rval.consumed = 0;
		} else {
Lev Walkin's avatar
Lev Walkin committed
213
			*native = l;
Lev Walkin's avatar
Lev Walkin committed
214 215
		}
	} else {
Lev Walkin's avatar
Lev Walkin committed
216 217 218 219 220
		/*
		 * Cannot restart from the middle;
		 * there is no place to save state in the native type.
		 * Request a continuation from the very beginning.
		 */
Lev Walkin's avatar
Lev Walkin committed
221 222
		rval.consumed = 0;
	}
Lev Walkin's avatar
Lev Walkin committed
223
	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st);
Lev Walkin's avatar
Lev Walkin committed
224 225 226 227
	return rval;
}


Lev Walkin's avatar
Lev Walkin committed
228
asn_enc_rval_t
Lev Walkin's avatar
Lev Walkin committed
229
NativeInteger_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin's avatar
Lev Walkin committed
230 231
	int ilevel, enum xer_encoder_flags_e flags,
		asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin's avatar
Lev Walkin committed
232 233 234
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    char scratch[32];	/* Enough for 64-bit int */
Lev Walkin's avatar
Lev Walkin committed
235
	asn_enc_rval_t er;
Lev Walkin's avatar
Lev Walkin committed
236
	const long *native = (const long *)sptr;
Lev Walkin's avatar
Lev Walkin committed
237 238 239 240

	(void)ilevel;
	(void)flags;

241
	if(!native) ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
242

243 244 245
	er.encoded = snprintf(scratch, sizeof(scratch),
			(specs && specs->field_unsigned)
			? "%lu" : "%ld", *native);
Lev Walkin's avatar
Lev Walkin committed
246 247
	if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch)
		|| cb(scratch, er.encoded, app_key) < 0)
248
		ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
249

250
	ASN__ENCODED_OK(er);
Lev Walkin's avatar
Lev Walkin committed
251 252
}

253 254
#ifndef  ASN_DISABLE_PER_SUPPORT

Lev Walkin's avatar
Lev Walkin committed
255
asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
256
NativeInteger_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin's avatar
Lev Walkin committed
257 258 259
                          asn_TYPE_descriptor_t *td,
                          const asn_per_constraints_t *constraints, void **sptr,
                          asn_per_data_t *pd) {
Lev Walkin's avatar
Lev Walkin committed
260 261 262
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    asn_dec_rval_t rval;
Lev Walkin's avatar
Lev Walkin committed
263 264 265 266 267 268 269 270 271
	long *native = (long *)*sptr;
	INTEGER_t tmpint;
	void *tmpintptr = &tmpint;

	(void)opt_codec_ctx;
	ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name);

	if(!native) {
		native = (long *)(*sptr = CALLOC(1, sizeof(*native)));
272
		if(!native) ASN__DECODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
273 274 275 276 277
	}

	memset(&tmpint, 0, sizeof tmpint);
	rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints,
				   &tmpintptr, pd);
Lev Walkin's avatar
Lev Walkin committed
278
	if(rval.code == RC_OK) {
279
		if((specs&&specs->field_unsigned)
Lev Walkin's avatar
Lev Walkin committed
280
			? asn_INTEGER2ulong(&tmpint, (unsigned long *)native)
281
			: asn_INTEGER2long(&tmpint, native))
Lev Walkin's avatar
Lev Walkin committed
282 283 284 285
			rval.code = RC_FAIL;
		else
			ASN_DEBUG("NativeInteger %s got value %ld",
				td->name, *native);
Lev Walkin's avatar
Lev Walkin committed
286
	}
Lev Walkin's avatar
Lev Walkin committed
287
	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
Lev Walkin's avatar
Lev Walkin committed
288 289

	return rval;
Lev Walkin's avatar
Lev Walkin committed
290 291
}

Lev Walkin's avatar
Lev Walkin committed
292 293
asn_enc_rval_t
NativeInteger_encode_uper(asn_TYPE_descriptor_t *td,
Lev Walkin's avatar
Lev Walkin committed
294 295
                          const asn_per_constraints_t *constraints, void *sptr,
                          asn_per_outp_t *po) {
Lev Walkin's avatar
Lev Walkin committed
296 297 298
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    asn_enc_rval_t er;
Lev Walkin's avatar
Lev Walkin committed
299 300 301
	long native;
	INTEGER_t tmpint;

302
	if(!sptr) ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
303 304 305 306 307 308

	native = *(long *)sptr;

	ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native);

	memset(&tmpint, 0, sizeof(tmpint));
309 310 311
	if((specs&&specs->field_unsigned)
		? asn_ulong2INTEGER(&tmpint, native)
		: asn_long2INTEGER(&tmpint, native))
312
		ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
313 314 315 316 317
	er = INTEGER_encode_uper(td, constraints, &tmpint, po);
	ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint);
	return er;
}

318 319
#endif  /* ASN_DISABLE_PER_SUPPORT */

Lev Walkin's avatar
Lev Walkin committed
320 321 322 323
/*
 * INTEGER specific human-readable output.
 */
int
Lev Walkin's avatar
Lev Walkin committed
324
NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
325
                    asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin's avatar
Lev Walkin committed
326 327 328
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    const long *native = (const long *)sptr;
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
    char scratch[32]; /* Enough for 64-bit int */
    int ret;

    (void)td;       /* Unused argument */
    (void)ilevel;   /* Unused argument */

    if(native) {
        long value = *native;
        ret = snprintf(scratch, sizeof(scratch),
                       (specs && specs->field_unsigned) ? "%lu" : "%ld", value);
        assert(ret > 0 && (size_t)ret < sizeof(scratch));
        if(cb(scratch, ret, app_key) < 0) return -1;
        if(specs && (value >= 0 || !specs->field_unsigned)) {
            const asn_INTEGER_enum_map_t *el =
                INTEGER_map_value2enum(specs, value);
            if(el) {
                if(cb(" (", 2, app_key) < 0) return -1;
                if(cb(el->enum_name, el->enum_len, app_key) < 0) return -1;
                if(cb(")", 1, app_key) < 0) return -1;
            }
        }
        return 0;
Lev Walkin's avatar
Lev Walkin committed
351
	} else {
352
		return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkin's avatar
Lev Walkin committed
353 354 355 356
	}
}

void
357
NativeInteger_free(const asn_TYPE_descriptor_t *td, void *ptr,
358
                   enum asn_struct_free_method method) {
359
    if(!td || !ptr)
Lev Walkin's avatar
Lev Walkin committed
360 361 362
		return;

	ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)",
363 364 365 366 367 368 369 370 371 372 373 374
		td->name, method, ptr);

    switch(method) {
    case ASFM_FREE_EVERYTHING:
        FREEMEM(ptr);
        break;
    case ASFM_FREE_UNDERLYING:
        break;
    case ASFM_FREE_UNDERLYING_AND_RESET:
        memset(ptr, 0, sizeof(long));
        break;
    }
Lev Walkin's avatar
Lev Walkin committed
375 376
}

377 378 379 380 381 382 383
int
NativeInteger_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) {
    (void)td;

    if(aptr && bptr) {
        const asn_INTEGER_specifics_t *specs =
            (const asn_INTEGER_specifics_t *)td->specifics;
384
        if(specs && specs->field_unsigned) {
385 386 387 388 389 390 391
            const unsigned long *a = aptr;
            const unsigned long *b = bptr;
            if(*a < *b) {
                return -1;
            } else if(*a > *b) {
                return 1;
            } else {
392
                return 0;
393 394 395 396 397 398 399 400 401
            }
        } else {
            const long *a = aptr;
            const long *b = bptr;
            if(*a < *b) {
                return -1;
            } else if(*a > *b) {
                return 1;
            } else {
402
                return 0;
403 404 405 406 407 408 409 410
            }
        }
    } else if(!aptr) {
        return -1;
    } else {
        return 1;
    }
}
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478

asn_random_fill_result_t
NativeInteger_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
                          const asn_encoding_constraints_t *constraints,
                          size_t max_length) {
    const asn_INTEGER_specifics_t *specs =
        (const asn_INTEGER_specifics_t *)td->specifics;
    asn_random_fill_result_t result_ok = {ARFILL_OK, 1};
    asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
    asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
    long *st = *sptr;
    const asn_INTEGER_enum_map_t *emap;
    size_t emap_len;
    intmax_t value;
    int find_inside_map;

    if(max_length == 0) return result_skipped;

    if(st == NULL) {
        st = (long *)CALLOC(1, sizeof(*st));
        if(st == NULL) {
            return result_failed;
        }
    }

    if(specs) {
        emap = specs->value2enum;
        emap_len = specs->map_count;
        if(specs->strict_enumeration) {
            find_inside_map = emap_len > 0;
        } else {
            find_inside_map = emap_len ? asn_random_between(0, 1) : 0;
        }
    } else {
        emap = 0;
        emap_len = 0;
        find_inside_map = 0;
    }

    if(find_inside_map) {
        assert(emap_len > 0);
        value = emap[asn_random_between(0, emap_len - 1)].nat_value;
    } else {
        const asn_per_constraint_t *ct;

        static const long variants[] = {
            -65536, -65535, -65534, -32769, -32768, -32767, -16385, -16384,
            -16383, -257,   -256,   -255,   -254,   -129,   -128,   -127,
            -126,   -1,     0,      1,      126,    127,    128,    129,
            254,    255,    256,    257,    16383,  16384,  16385,  32767,
            32768,  32769,  65534,  65535,  65536,  65537};
        if(specs && specs->field_unsigned) {
            assert(variants[18] == 0);
            value = variants[asn_random_between(
                18, sizeof(variants) / sizeof(variants[0]) - 1)];
        } else {
            value = variants[asn_random_between(
                0, sizeof(variants) / sizeof(variants[0]) - 1)];
        }

        if(!constraints) constraints = &td->encoding_constraints;
        ct = constraints ? &constraints->per_constraints->value : 0;
        (void)ct;
    }

    *st = value;
    return result_ok;
}