XER decoding and asn_long2INTEGER()

git-svn-id: https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk@521 59561ff5-6e30-0410-9f3c-9617f08c8826
This commit is contained in:
vlm 2004-10-21 11:21:25 +00:00
parent c4436cf916
commit a4799a6d15
2 changed files with 130 additions and 4 deletions

View File

@ -1,10 +1,10 @@
/*-
* Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
#include <asn_internal.h>
#include <INTEGER.h>
#include <ber_codec_prim.h> /* Encoder and decoder of a primitive */
#include <asn_codecs_prim.h> /* Encoder and decoder of a primitive type */
#include <assert.h>
#include <errno.h>
@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_INTEGER = {
asn_generic_no_constraint,
ber_decode_primitive,
INTEGER_encode_der,
0, /* Not implemented yet */
INTEGER_decode_xer,
INTEGER_encode_xer,
0, /* Use generic outmost tag fetcher */
asn_DEF_INTEGER_tags,
@ -176,6 +176,84 @@ INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
return (ret < 0) ? -1 : 0;
}
/*
* Decode the chunk of XML text encoding INTEGER.
*/
static ssize_t
INTEGER__xer_body_decode(INTEGER_t *st, void *chunk_buf, size_t chunk_size) {
long sign = 1;
long value;
char *lstart = (char *)chunk_buf;
char *lstop = chunk_buf + chunk_size;
enum {
ST_SKIPSPACE,
ST_WAITDIGITS,
ST_DIGITS,
} state = ST_SKIPSPACE;
/*
* We may receive a tag here. But we aren't ready to deal with it yet.
* So, just use stroul()-like code and serialize the result.
*/
for(value = 0; lstart < lstop; lstart++) {
int lv = *lstart;
switch(lv) {
case 0x09: case 0x0a: case 0x0d: case 0x20:
if(state == ST_SKIPSPACE) continue;
break;
case 0x2d: /* '-' */
if(state == ST_SKIPSPACE) {
sign = -1;
state = ST_WAITDIGITS;
continue;
}
break;
case 0x2b: /* '+' */
if(state == ST_SKIPSPACE) {
state = ST_WAITDIGITS;
continue;
}
break;
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
if(state != ST_DIGITS) state = ST_DIGITS;
value = value * 10 + (lv - 0x30);
/* Check for two's complement overflow */
if(value < 0) {
/* Check whether it is a LONG_MIN */
if(sign == -1
&& value == ~((unsigned long)-1 >> 1)) {
sign = 0;
} else {
/* Overflow */
return -1;
}
}
continue;
}
}
if(state != ST_DIGITS)
return -1; /* No digits */
value *= sign; /* Change sign, if needed */
if(asn_long2INTEGER(st, value))
return -1;
return lstop - lstart;
}
asn_dec_rval_t
INTEGER_decode_xer(asn_codec_ctx_t *opt_codec_ctx,
asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
void *buf_ptr, size_t size) {
return xer_decode_primitive(opt_codec_ctx, td,
(ASN__PRIMITIVE_TYPE_t **)sptr, opt_mname,
buf_ptr, size, INTEGER__xer_body_decode);
}
asn_enc_rval_t
INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
int ilevel, enum xer_encoder_flags_e flags,
@ -254,3 +332,48 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
*lptr = l;
return 0;
}
int
asn_long2INTEGER(INTEGER_t *st, long value) {
uint8_t *buf, *bp;
uint8_t *p;
uint8_t *pstart;
uint8_t *pend1;
if(!st) {
errno = EINVAL;
return -1;
}
buf = MALLOC(sizeof(value));
if(!buf) return -1;
pstart = (uint8_t *)&value;
pend1 = pstart + sizeof(value) - 1;
/*
* If the contents octet consists of more than one octet,
* then bits of the first octet and bit 8 of the second octet:
* a) shall not all be ones; and
* b) shall not all be zero.
*/
for(p = pstart; p < pend1; p++) {
switch(*p) {
case 0x00: if((p[1] & 0x80) == 0)
continue;
break;
case 0xff: if((p[1] & 0x80))
continue;
break;
}
break;
}
/* Copy the integer body */
for(pstart = p, bp = buf; p <= pend1;)
*bp++ = *p++;
if(st->buf) FREEMEM(st->buf);
st->buf = buf;
st->size = p - pstart;
return 0;
}

View File

@ -6,7 +6,7 @@
#define _INTEGER_H_
#include <asn_application.h>
#include <ber_codec_prim.h>
#include <asn_codecs_prim.h>
typedef ASN__PRIMITIVE_TYPE_t INTEGER_t;
@ -15,6 +15,7 @@ extern asn_TYPE_descriptor_t asn_DEF_INTEGER;
asn_struct_print_f INTEGER_print;
ber_type_decoder_f INTEGER_decode_ber;
der_type_encoder_f INTEGER_encode_der;
xer_type_decoder_f INTEGER_decode_xer;
xer_type_encoder_f INTEGER_encode_xer;
/***********************************
@ -25,7 +26,9 @@ xer_type_encoder_f INTEGER_encode_xer;
* Returns 0 if it was possible to convert, -1 otherwise.
* -1/EINVAL: Mandatory argument missing
* -1/ERANGE: Value encoded is out of range for long representation
* -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()).
*/
int asn_INTEGER2long(const INTEGER_t *i, long *l);
int asn_long2INTEGER(INTEGER_t *i, long l);
#endif /* _INTEGER_H_ */