Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

[75b405]: cg / casn / casn_num.c Maximize Restore History

Download this file

casn_num.c    163 lines (146 with data), 4.9 kB

  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
/* $Id$ */
/*****************************************************************************
File: casn_num.c
Contents: Functions to handle numeris ASN.1 objects.
System: Compact ASN development.
Created:
Author: Charles W. Gardiner <gardiner@bbn.com>
Remarks:
*****************************************************************************/
char casn_num_sfcsid[] = "@(#)casn_num.c 854P";
#include "casn.h"
extern struct casn *_go_up(struct casn *);
extern void _clear_casn(struct casn *, ushort);
extern int _casn_obj_err(struct casn *, int),
_check_filled(struct casn *casnp, int),
_clear_error(struct casn *),
_fill_upward(struct casn *, int),
_write_casn(struct casn *casnp, uchar *c, int lth);
int _table_op(struct casn *casnp),
_write_casn_num(struct casn *casnp, long val);
/*
* IMPORTANT: diff_casn_num can return error (-2)! And this WILL
* happen when the ASN.1 integer lands outside of the range of a C
* long integer.
*/
int diff_casn_num(struct casn *casnp, long val)
{
long tmp;
if (read_casn_num(casnp, &tmp) < 0)
return -2;
if (tmp > val)
return 1;
else if (tmp < val)
return -1;
else
return 0;
}
int read_casn_num(struct casn *casnp, long *valp)
{
struct casn *tcasnp;
int ansr, err = 0;
uchar *c;
if (_clear_error(casnp) < 0) return -1;
if (casnp->type == ASN_NOTYPE)
{
if (!(tcasnp = _go_up(casnp))) err = ASN_TYPE_ERR;
}
else tcasnp = casnp;
if (!err)
{
if ((ansr = _check_filled(tcasnp, 1)) < 0 ||
(!ansr && !(tcasnp->flags & ASN_DEFAULT_FLAG))) return ansr; // looks wrong, but we left it (AC, DM): may return 0 instead of error if not filled
if (tcasnp->type != ASN_INTEGER && tcasnp->type != ASN_ENUMERATED &&
tcasnp->type != ASN_BOOLEAN)
err = ASN_TYPE_ERR;
else if (tcasnp->lth > sizeof(*valp) || tcasnp->lth < 0)
err = ASN_LENGTH_ERR;
}
if (err) return _casn_obj_err(casnp, err);
// if not filled but has default
if ((tcasnp->flags & (ASN_FILLED_FLAG | ASN_DEFAULT_FLAG)) ==
ASN_DEFAULT_FLAG)
{
if (tcasnp->type == ASN_BOOLEAN)
{
uchar buf[8];
memset(buf, 0, sizeof(buf));
read_casn(tcasnp, buf);
*valp = buf[0];
return 1;
}
*valp = 0; // DEFINITELY WRONG
return 0; // MIGHT BE WRONG (depends on intended semantics when not filled in)
// *valp = (int)tcasnp->ptr;
// if ((ansr = *valp) < 0) ansr = -ansr;
// for (c = casnp->startp; ansr; ansr >>= 8, c++);
}
else
{
if (tcasnp->lth <= 0)
return _casn_obj_err(tcasnp, ASN_LENGTH_ERR);
if ((*tcasnp->startp & 0x80) && tcasnp->type == ASN_INTEGER)
*valp = -1;
else *valp = 0;
for (c = casnp->startp; c < &casnp->startp[casnp->lth];
*valp = (*valp << 8) + (long)*c++);
return (c - casnp->startp);
}
}
int write_casn_num(struct casn *casnp, long val)
{
struct casn *tcasnp;
int ansr, err = 0;
if (_clear_error(casnp) < 0) return -1;
if (casnp->tag == ASN_NOTYPE)
{
if (!(tcasnp = _go_up(casnp)) || !(tcasnp->flags & ASN_ENUM_FLAG) ||
(tcasnp->type != ASN_INTEGER && tcasnp->type != ASN_ENUMERATED))
return -1;
return _write_casn(tcasnp, casnp->startp, casnp->lth);
}
if ((casnp->type != ASN_INTEGER && casnp->type != ASN_ENUMERATED &&
casnp->type != ASN_BOOLEAN) || (val < 0 && casnp->type != ASN_INTEGER))
err = ASN_TYPE_ERR;
else
{
ansr = _write_casn_num(casnp, val);
if (casnp->max)
{
if ((casnp->flags & ASN_RANGE_FLAG))
{
if (val > casnp->max || val < casnp->min) err = ASN_BOUNDS_ERR;
}
else if (ansr < casnp->min || ansr > casnp->max)
err = ASN_BOUNDS_ERR;
}
}
if (err)
{
_clear_casn(casnp, ~(ASN_FILLED_FLAG));
return _casn_obj_err(casnp, err);
}
return ansr;
}
int _write_casn_num(struct casn *casnp, long val)
{
long tmp;
int err = 0, siz;
uchar *c;
struct casn *tcasnp;
_clear_casn(casnp, ~(ASN_FILLED_FLAG)); // don't clear CHOSEN flag
tmp = val;
if (tmp > 0) for (siz = 1; tmp > 0x7F; siz++, tmp >>= 8);
else for (siz = 1; tmp < -128; siz++, tmp >>= 8);
casnp->startp = (uchar *)dbcalloc(1, siz + 1);
for (c = &casnp->startp[siz]; val != 0 && val != -1;
*(--c) = (val & 0xFF), val >>= 8);
if (val < 0 && !*casnp->startp) *casnp->startp = 0xFF;
casnp->lth = siz;
tcasnp = _go_up(casnp);
if (tcasnp && (tcasnp->flags & ASN_ENUM_FLAG) > 0) casnp->flags |= ASN_FILLED_FLAG;
else if ((err = _fill_upward(casnp, ASN_FILLED_FLAG)) < 0)
return _casn_obj_err(casnp, -err);
if ((casnp->flags & ASN_TABLE_FLAG) && _table_op(casnp) < 0) return -1;
return siz;
}