aboutsummaryrefslogtreecommitdiffstats
path: root/skeletons/NativeInteger.c
blob: 8f13a5913d144488f028a81a795d7023521d8854 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/*-
 * Copyright (c) 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
 * Redistribution and modifications are permitted subject to BSD license.
 */
/*
 * Please read the NativeInteger.h for the explanation wrt. differences between
 * 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.
 */
#include <NativeInteger.h>
#include <INTEGER.h>
#include <assert.h>

/*
 * NativeInteger basic type description.
 */
static ber_tlv_tag_t asn1_DEF_NativeInteger_tags[] = {
	(ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
};
asn1_TYPE_descriptor_t asn1_DEF_NativeInteger = {
	"INTEGER",			/* The ASN.1 type is still INTEGER */
	asn_generic_no_constraint,
	NativeInteger_decode_ber,
	NativeInteger_encode_der,
	NativeInteger_print,
	NativeInteger_free,
	0, /* Use generic outmost tag fetcher */
	asn1_DEF_NativeInteger_tags,
	sizeof(asn1_DEF_NativeInteger_tags)/sizeof(asn1_DEF_NativeInteger_tags[0]),
	1,	/* Single UNIVERSAL tag may be implicitly overriden */
	0,	/* Always in primitive form */
	0	/* No specifics */
};

/*
 * Decode INTEGER type.
 */
ber_dec_rval_t
NativeInteger_decode_ber(asn1_TYPE_descriptor_t *td,
	void **int_ptr, void *buf_ptr, size_t size, int tag_mode) {
	int *Int = *int_ptr;
	ber_dec_rval_t rval;
	ber_dec_ctx_t ctx = { 0, 0, 0, 0 };
	ber_tlv_len_t length;

	/*
	 * If the structure is not there, allocate it.
	 */
	if(Int == NULL) {
		Int = *int_ptr = CALLOC(1, sizeof(*Int));
		if(Int == NULL) {
			rval.code = RC_FAIL;
			rval.consumed = 0;
			return rval;
		}
	}

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

	/*
	 * Check tags.
	 */
	rval = ber_check_tags(td, &ctx,
		buf_ptr, size, tag_mode, &length, 0);
	if(rval.code != RC_OK)
		return rval;

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

	/*
	 * Make sure we have this length.
	 */
	buf_ptr += rval.consumed;
	size -= rval.consumed;
	if(length > (ber_tlv_len_t)size) {
		rval.code = RC_WMORE;
		rval.consumed = 0;
		return rval;
	}

	/*
	 * ASN.1 encoded INTEGER: buf_ptr, length
	 * Fill the Int, at the same time checking for overflow.
	 * If overflow occured, return with RC_FAIL.
	 */
	{
		INTEGER_t tmp;
		long l;
		tmp.buf = buf_ptr;
		tmp.size = length;

		if(asn1_INTEGER2long(&tmp, &l)) {
			rval.code = RC_FAIL;
			rval.consumed = 0;
			return rval;
		}

		*Int = l;

		/*
		 * Note that int might be shorter than long.
		 * This expression hopefully will be optimized away
		 * by compiler.
		 */
		if(sizeof(int) != sizeof(long) && (*Int != l)) {
			*Int = 0;	/* Safe value */
			rval.code = RC_FAIL;
			rval.consumed = 0;
			return rval;
		}
	}

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

	ASN_DEBUG("Took %ld/%ld bytes to encode %s (%d)",
		(long)rval.consumed, (long)length, td->name, *Int);

	return rval;
}

/*
 * Encode the NativeInteger using the standard INTEGER type DER encoder.
 */
der_enc_rval_t
NativeInteger_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
	int tag_mode, ber_tlv_tag_t tag,
	asn_app_consume_bytes_f *cb, void *app_key) {
	unsigned int Int = *(unsigned int *)ptr;	/* Disable sign ext. */
	der_enc_rval_t erval;
	INTEGER_t tmp;

#ifdef	WORDS_BIGENDIAN		/* Opportunistic optimization */

	tmp.buf = &Int;
	tmp.size = sizeof(Int);

#else	/* Works even if WORDS_BIGENDIAN is not set where should've been */
	uint8_t buf[sizeof(int)];
	uint8_t *p;

	/* Prepare fake INTEGER */
	for(p = buf + sizeof(buf) - 1; p >= buf; p--, Int >>= 8)
		*p = Int & 0xff;

	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;
}

/*
 * INTEGER specific human-readable output.
 */
int
NativeInteger_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
	asn_app_consume_bytes_f *cb, void *app_key) {
	const int *Int = sptr;
	char scratch[32];	/* Enough for 64-bit int */
	int ret;

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

	if(Int) {
		ret = snprintf(scratch, sizeof(scratch), "%d", *Int);
		assert(ret > 0 && ret < (int)sizeof(scratch));
		return cb(scratch, ret, app_key);
	} else {
		return cb("<absent>", 8, app_key);
	}
}

void
NativeInteger_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {

	if(!td || !ptr)
		return;

	ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)",
		td->name, contents_only, ptr);

	if(!contents_only) {
		FREEMEM(ptr);
	}
}