BOOLEAN.c 7.2 KB
Newer Older
Lev Walkin's avatar
Lev Walkin committed
1
/*-
Lev Walkin's avatar
Lev Walkin committed
2
 * Copyright (c) 2003, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved.
Lev Walkin's avatar
Lev Walkin committed
3 4
 * Redistribution and modifications are permitted subject to BSD license.
 */
Lev Walkin's avatar
Lev Walkin committed
5
#include <asn_internal.h>
Lev Walkin's avatar
Lev Walkin committed
6
#include <asn_codecs_prim.h>
Lev Walkin's avatar
Lev Walkin committed
7 8 9 10 11
#include <BOOLEAN.h>

/*
 * BOOLEAN basic type description.
 */
12
static const ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = {
Lev Walkin's avatar
Lev Walkin committed
13 14
	(ASN_TAG_CLASS_UNIVERSAL | (1 << 2))
};
15
asn_TYPE_operation_t asn_OP_BOOLEAN = {
Lev Walkin's avatar
Lev Walkin committed
16 17
	BOOLEAN_free,
	BOOLEAN_print,
18
	BOOLEAN_compare,
Lev Walkin's avatar
Lev Walkin committed
19 20
	BOOLEAN_decode_ber,
	BOOLEAN_encode_der,
Lev Walkin's avatar
Lev Walkin committed
21
	BOOLEAN_decode_xer,
Lev Walkin's avatar
Lev Walkin committed
22
	BOOLEAN_encode_xer,
Lev Walkin's avatar
Lev Walkin committed
23 24 25 26 27 28 29
#ifdef	ASN_DISABLE_OER_SUPPORT
	0,
	0,
#else
	0,
	0,
#endif  /* ASN_DISABLE_OER_SUPPORT */
Lev Walkin's avatar
Lev Walkin committed
30 31 32 33 34 35 36
#ifdef	ASN_DISABLE_PER_SUPPORT
	0,
	0,
#else
	BOOLEAN_decode_uper,	/* Unaligned PER decoder */
	BOOLEAN_encode_uper,	/* Unaligned PER encoder */
#endif	/* ASN_DISABLE_PER_SUPPORT */
37 38 39 40 41 42 43
	0	/* Use generic outmost tag fetcher */
};
asn_TYPE_descriptor_t asn_DEF_BOOLEAN = {
	"BOOLEAN",
	"BOOLEAN",
	&asn_OP_BOOLEAN,
	asn_generic_no_constraint,
Lev Walkin's avatar
Lev Walkin committed
44 45 46 47
	asn_DEF_BOOLEAN_tags,
	sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]),
	asn_DEF_BOOLEAN_tags,	/* Same as above */
	sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]),
Lev Walkin's avatar
Lev Walkin committed
48
	0,	/* No OER visible constraints */
Lev Walkin's avatar
Lev Walkin committed
49
	0,	/* No PER visible constraints */
Lev Walkin's avatar
Lev Walkin committed
50
	0, 0,	/* No members */
51
	0	/* No specifics */
Lev Walkin's avatar
Lev Walkin committed
52 53 54 55 56
};

/*
 * Decode BOOLEAN type.
 */
Lev Walkin's avatar
Lev Walkin committed
57
asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
58
BOOLEAN_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
Lev Walkin's avatar
Lev Walkin committed
59
		asn_TYPE_descriptor_t *td,
Lev Walkin's avatar
Lev Walkin committed
60
		void **bool_value, const void *buf_ptr, size_t size,
Lev Walkin's avatar
Lev Walkin committed
61
		int tag_mode) {
62
	BOOLEAN_t *st = (BOOLEAN_t *)*bool_value;
Lev Walkin's avatar
Lev Walkin committed
63
	asn_dec_rval_t rval;
Lev Walkin's avatar
Lev Walkin committed
64 65 66 67
	ber_tlv_len_t length;
	ber_tlv_len_t lidx;

	if(st == NULL) {
68
		st = (BOOLEAN_t *)(*bool_value = CALLOC(1, sizeof(*st)));
Lev Walkin's avatar
Lev Walkin committed
69 70 71 72 73 74 75 76 77 78 79 80 81
		if(st == NULL) {
			rval.code = RC_FAIL;
			rval.consumed = 0;
			return rval;
		}
	}

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

	/*
	 * Check tags.
	 */
Lev Walkin's avatar
Lev Walkin committed
82 83
	rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size,
		tag_mode, 0, &length, 0);
Lev Walkin's avatar
Lev Walkin committed
84 85 86 87 88
	if(rval.code != RC_OK)
		return rval;

	ASN_DEBUG("Boolean length is %d bytes", (int)length);

Lev Walkin's avatar
Lev Walkin committed
89
	buf_ptr = ((const char *)buf_ptr) + rval.consumed;
Lev Walkin's avatar
Lev Walkin committed
90
	size -= rval.consumed;
91
	if(length > (ber_tlv_len_t)size) {
Lev Walkin's avatar
Lev Walkin committed
92 93 94 95 96 97 98 99
		rval.code = RC_WMORE;
		rval.consumed = 0;
		return rval;
	}

	/*
	 * Compute boolean value.
	 */
100 101
	for(*st = 0, lidx = 0;
		(lidx < length) && *st == 0; lidx++) {
Lev Walkin's avatar
Lev Walkin committed
102 103 104 105 106
		/*
		 * Very simple approach: read bytes until the end or
		 * value is already TRUE.
		 * BOOLEAN is not supposed to contain meaningful data anyway.
		 */
Lev Walkin's avatar
Lev Walkin committed
107
		*st |= ((const uint8_t *)buf_ptr)[lidx];
Lev Walkin's avatar
Lev Walkin committed
108 109 110 111 112
	}

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

113
	ASN_DEBUG("Took %ld/%ld bytes to encode %s, value=%d",
Lev Walkin's avatar
Lev Walkin committed
114
		(long)rval.consumed, (long)length,
115
		td->name, *st);
Lev Walkin's avatar
Lev Walkin committed
116 117 118 119
	
	return rval;
}

Lev Walkin's avatar
Lev Walkin committed
120
asn_enc_rval_t
Lev Walkin's avatar
Lev Walkin committed
121
BOOLEAN_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin's avatar
Lev Walkin committed
122 123
	int tag_mode, ber_tlv_tag_t tag,
	asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin's avatar
Lev Walkin committed
124
	asn_enc_rval_t erval;
Lev Walkin's avatar
Lev Walkin committed
125
	BOOLEAN_t *st = (BOOLEAN_t *)sptr;
Lev Walkin's avatar
Lev Walkin committed
126

127
	erval.encoded = der_write_tags(td, 1, tag_mode, 0, tag, cb, app_key);
Lev Walkin's avatar
Lev Walkin committed
128 129 130 131 132 133 134 135 136
	if(erval.encoded == -1) {
		erval.failed_type = td;
		erval.structure_ptr = sptr;
		return erval;
	}

	if(cb) {
		uint8_t bool_value;

137 138 139
		bool_value = *st ? 0xff : 0; /* 0xff mandated by DER */

		if(cb(&bool_value, 1, app_key) < 0) {
Lev Walkin's avatar
Lev Walkin committed
140 141 142 143 144 145 146 147 148
			erval.encoded = -1;
			erval.failed_type = td;
			erval.structure_ptr = sptr;
			return erval;
		}
	}

	erval.encoded += 1;

149
	ASN__ENCODED_OK(erval);
Lev Walkin's avatar
Lev Walkin committed
150 151
}

Lev Walkin's avatar
Lev Walkin committed
152 153 154 155

/*
 * Decode the chunk of XML text encoding INTEGER.
 */
156 157
static enum xer_pbd_rval
BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
Lev Walkin's avatar
Lev Walkin committed
158
	BOOLEAN_t *st = (BOOLEAN_t *)sptr;
159
	const char *p = (const char *)chunk_buf;
Lev Walkin's avatar
Lev Walkin committed
160

Lev Walkin's avatar
Lev Walkin committed
161 162
	(void)td;

163
	if(chunk_size && p[0] == 0x3c /* '<' */) {
Lev Walkin's avatar
Lev Walkin committed
164 165 166 167 168
		switch(xer_check_tag(chunk_buf, chunk_size, "false")) {
		case XCT_BOTH:
			/* "<false/>" */
			*st = 0;
			break;
Lev Walkin's avatar
Lev Walkin committed
169
		case XCT_UNKNOWN_BO:
Lev Walkin's avatar
Lev Walkin committed
170 171
			if(xer_check_tag(chunk_buf, chunk_size, "true")
					!= XCT_BOTH)
172
				return XPBD_BROKEN_ENCODING;
Lev Walkin's avatar
Lev Walkin committed
173 174 175 176
			/* "<true/>" */
			*st = 1;	/* Or 0xff as in DER?.. */
			break;
		default:
177
			return XPBD_BROKEN_ENCODING;
Lev Walkin's avatar
Lev Walkin committed
178
		}
179
		return XPBD_BODY_CONSUMED;
Lev Walkin's avatar
Lev Walkin committed
180
	} else {
181
		return XPBD_BROKEN_ENCODING;
Lev Walkin's avatar
Lev Walkin committed
182 183 184 185 186
	}
}


asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
187
BOOLEAN_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 193 194 195

	return xer_decode_primitive(opt_codec_ctx, td,
		sptr, sizeof(BOOLEAN_t), opt_mname, buf_ptr, size,
		BOOLEAN__xer_body_decode);
}

Lev Walkin's avatar
Lev Walkin committed
196
asn_enc_rval_t
Lev Walkin's avatar
Lev Walkin committed
197
BOOLEAN_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkin's avatar
Lev Walkin committed
198 199 200 201 202 203 204 205
	int ilevel, enum xer_encoder_flags_e flags,
		asn_app_consume_bytes_f *cb, void *app_key) {
	const BOOLEAN_t *st = (const BOOLEAN_t *)sptr;
	asn_enc_rval_t er;

	(void)ilevel;
	(void)flags;

206
	if(!st) ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
207 208

	if(*st) {
209
		ASN__CALLBACK("<true/>", 7);
Lev Walkin's avatar
Lev Walkin committed
210 211
		er.encoded = 7;
	} else {
212
		ASN__CALLBACK("<false/>", 8);
Lev Walkin's avatar
Lev Walkin committed
213 214 215
		er.encoded = 8;
	}

216
	ASN__ENCODED_OK(er);
Lev Walkin's avatar
Lev Walkin committed
217
cb_failed:
218
	ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
219 220
}

Lev Walkin's avatar
Lev Walkin committed
221
int
Lev Walkin's avatar
Lev Walkin committed
222
BOOLEAN_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkin's avatar
Lev Walkin committed
223
	asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin's avatar
Lev Walkin committed
224
	const BOOLEAN_t *st = (const BOOLEAN_t *)sptr;
225 226
	const char *buf;
	size_t buflen;
Lev Walkin's avatar
Lev Walkin committed
227

228 229 230
	(void)td;	/* Unused argument */
	(void)ilevel;	/* Unused argument */

Lev Walkin's avatar
Lev Walkin committed
231
	if(st) {
232 233 234 235 236 237 238
		if(*st) {
			buf = "TRUE";
			buflen = 4;
		} else {
			buf = "FALSE";
			buflen = 5;
		}
Lev Walkin's avatar
Lev Walkin committed
239
	} else {
240 241
		buf = "<absent>";
		buflen = 8;
Lev Walkin's avatar
Lev Walkin committed
242
	}
243 244

	return (cb(buf, buflen, app_key) < 0) ? -1 : 0;
Lev Walkin's avatar
Lev Walkin committed
245 246 247
}

void
248 249 250 251 252 253 254 255 256 257 258 259 260 261
BOOLEAN_free(const asn_TYPE_descriptor_t *td, void *ptr,
             enum asn_struct_free_method method) {
    if(td && 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(BOOLEAN_t));
            break;
        }
    }
Lev Walkin's avatar
Lev Walkin committed
262 263
}

Lev Walkin's avatar
Lev Walkin committed
264
asn_dec_rval_t
Lev Walkin's avatar
Lev Walkin committed
265
BOOLEAN_decode_uper(const asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
Lev Walkin's avatar
Lev Walkin committed
266 267 268
                    const asn_per_constraints_t *constraints, void **sptr,
                    asn_per_data_t *pd) {
    asn_dec_rval_t rv;
Lev Walkin's avatar
Lev Walkin committed
269 270 271
	BOOLEAN_t *st = (BOOLEAN_t *)*sptr;

	(void)opt_codec_ctx;
Lev Walkin's avatar
Lev Walkin committed
272
    (void)td;
Lev Walkin's avatar
Lev Walkin committed
273 274 275 276
	(void)constraints;

	if(!st) {
		st = (BOOLEAN_t *)(*sptr = MALLOC(sizeof(*st)));
277
		if(!st) ASN__DECODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
278 279 280 281 282 283 284 285
	}

	/*
	 * Extract a single bit
	 */
	switch(per_get_few_bits(pd, 1)) {
	case 1: *st = 1; break;
	case 0: *st = 0; break;
286
	case -1: default: ASN__DECODE_STARVED;
Lev Walkin's avatar
Lev Walkin committed
287 288 289 290 291 292 293 294 295
	}

	ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE");

	rv.code = RC_OK;
	rv.consumed = 1;
	return rv;
}

Lev Walkin's avatar
Lev Walkin committed
296 297 298

asn_enc_rval_t
BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td,
Lev Walkin's avatar
Lev Walkin committed
299 300 301
                    const asn_per_constraints_t *constraints, void *sptr,
                    asn_per_outp_t *po) {
    const BOOLEAN_t *st = (const BOOLEAN_t *)sptr;
Lev Walkin's avatar
Lev Walkin committed
302
	asn_enc_rval_t er = { 0, 0, 0 };
Lev Walkin's avatar
Lev Walkin committed
303 304 305

	(void)constraints;

306
	if(!st) ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
307

Lev Walkin's avatar
Lev Walkin committed
308
	if(per_put_few_bits(po, *st ? 1 : 0, 1))
309
		ASN__ENCODE_FAILED;
Lev Walkin's avatar
Lev Walkin committed
310

311
	ASN__ENCODED_OK(er);
Lev Walkin's avatar
Lev Walkin committed
312
}
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336


int
BOOLEAN_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
                const void *bptr) {
    const BOOLEAN_t *a = aptr;
    const BOOLEAN_t *b = bptr;

    (void)td;

    if(a && b) {
        if(*a == *b) {
            return 0;
        } else if(!*a) {
            return -1;
        } else {
            return 1;
        }
    } else if(!a) {
        return -1;
    } else {
        return 1;
    }
}