blob: 9b0c0d3a365d5438fa8f0b9749d16ba8b902d24c [file] [log] [blame]
Lev Walkinf9f3e062017-08-27 20:34:58 -07001/*
2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
4 * Redistribution and modifications are permitted subject to BSD license.
5 */
6#ifndef ASN_DISABLE_OER_SUPPORT
7
8#include <asn_internal.h>
9#include <NativeEnumerated.h>
10#include <errno.h>
11
Lev Walkin758aead2017-10-10 00:12:02 -070012static long
Lev Walkinc346f902017-10-09 20:24:40 -070013asn__nativeenumerated_convert(const uint8_t *b, const uint8_t *end) {
Lev Walkin758aead2017-10-10 00:12:02 -070014 unsigned long value;
Lev Walkina9e63372017-09-17 23:24:56 -070015
16 /* Perform the sign initialization */
17 /* Actually value = -(*b >> 7); gains nothing, yet unreadable! */
18 if((*b >> 7)) {
Lev Walkin758aead2017-10-10 00:12:02 -070019 value = (unsigned long)(-1);
Lev Walkina9e63372017-09-17 23:24:56 -070020 } else {
21 value = 0;
22 }
23
24 /* Conversion engine */
25 for(; b < end; b++) {
26 value = (value << 8) | *b;
27 }
28
29 return value;
30}
31
Lev Walkinf9f3e062017-08-27 20:34:58 -070032asn_dec_rval_t
Lev Walkinafbf2a92017-09-12 23:30:27 -070033NativeEnumerated_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkinf9f3e062017-08-27 20:34:58 -070034 asn_TYPE_descriptor_t *td,
35 const asn_oer_constraints_t *constraints,
36 void **nint_ptr, const void *ptr, size_t size) {
37 asn_dec_rval_t rval = {RC_OK, 0};
38 long *native = (long *)*nint_ptr;
39 const uint8_t *b = ptr;
40
41 (void)opt_codec_ctx;
42 (void)constraints;
43
44 if(size < 1) {
45 ASN__DECODE_STARVED;
46 }
47
48 if((*b & 0x80) == 0) {
49 /*
50 * X.696 (08/2015) #11.2 Short form for Enumerated.
51 */
52 if(!native) {
53 native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
54 if(!native) ASN__DECODE_FAILED;
55 }
56
57 *native = *b;
58 rval.consumed = 1;
59 } else {
60 /*
61 * X.696 (08/2015) #11.4 Long form for Enumerated.
62 */
63 size_t length = *b & 0x7f;
64 const uint8_t *bend;
Lev Walkin758aead2017-10-10 00:12:02 -070065 long value;
Lev Walkinf9f3e062017-08-27 20:34:58 -070066
67 if(length < 1 || length > sizeof(*native)) {
68 ASN__DECODE_FAILED;
69 }
70 if((1 + length) > size) {
71 ASN__DECODE_STARVED;
72 }
73 b++;
74 bend = b + length;
Lev Walkinf9f3e062017-08-27 20:34:58 -070075
Lev Walkinc346f902017-10-09 20:24:40 -070076 value = asn__nativeenumerated_convert(b, bend);
Lev Walkinf9f3e062017-08-27 20:34:58 -070077 if(value < 0) {
78 const asn_INTEGER_specifics_t *specs =
79 (const asn_INTEGER_specifics_t *)td->specifics;
80 if(specs && specs->field_unsigned) {
81 ASN__DECODE_FAILED;
82 }
83 }
84
85 if(!native) {
86 native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native)));
87 if(!native) ASN__DECODE_FAILED;
88 }
89
90 *native = value;
91
92 rval.consumed = (1 + length);
93 }
94
95 return rval;
96}
97
98/*
99 * Encode as Canonical OER.
100 */
101asn_enc_rval_t
102NativeEnumerated_encode_oer(asn_TYPE_descriptor_t *td,
103 const asn_oer_constraints_t *constraints,
104 void *sptr, asn_app_consume_bytes_f *cb,
105 void *app_key) {
Lev Walkin0cfc8652017-09-11 15:45:36 +0000106 asn_enc_rval_t er;
Lev Walkinf9f3e062017-08-27 20:34:58 -0700107 long native;
108
109 (void)constraints;
110
111 if(!sptr) ASN__ENCODE_FAILED;
112
113 native = *(const long *)sptr;
114
115 if(native >= 0 && native <= 127) {
116 /* #11.2 Short form */
117 uint8_t b = native;
118 er.encoded = 1;
119 if(cb(&b, er.encoded, app_key) < 0) {
120 ASN__ENCODE_FAILED;
121 }
122 ASN__ENCODED_OK(er);
123 } else {
124 /* #11.2 Long form */
125 uint8_t buf[1 + sizeof(native)];
126 uint8_t *b = &buf[sizeof(native)]; /* Last addressable */
127 long final_pattern = -1 * (native < 0);
128
129 for(;;) {
130 *b-- = native;
131 native >>= 8;
132 if(native == final_pattern) {
133 if(final_pattern) {
134 if((b[1] & 0x80)) break;
135 } else {
136 if(!(b[1] & 0x80)) break;
137 }
138 }
139 }
140 *b = 0x80 | (&buf[sizeof(native)] - b);
141 er.encoded = 1 + (&buf[sizeof(native)] - b);
142 if(cb(b, er.encoded, app_key) < 0) {
143 ASN__ENCODE_FAILED;
144 }
145 ASN__ENCODED_OK(er);
146 }
147}
148
149#endif /* ASN_DISABLE_OER_SUPPORT */