📄 decode.cpp
字号:
}
tobjp = pobjp->_ptr;
}
}
while (tobjp &&
(tobjp->_tag == ASN_CHOICE || (tobjp->_flags & ASN_POINTER_FLAG)));
c[1] = 0;
return tobjp;
}
/* char_table masks defined in asn.h
#define ASN_NUMERIC_MASK 1
#define ASN_PRINTABLE_MASK 4
#define ASN_T61_MASK 8
*/
static char char_table[] = "\
@@@@@@@@H@H@HHHH@@@@@@@@@HHH@H@@\
MHHHHHHHLLHHMMMMMMMMMMMMMMHHHHHH\
LNNNNNNNNNNNNNNNNNNNNNNNNNNHHH@H\
@LLLLLLLLLLLLLLLLLLLLLLLLLLHH@@@\
@@@@@@@@@@@HH@@@@@@@@@@@@@@H@@@@\
@HHHHHHHH@@H@@@@HHHHHHHHH@@HHHHH\
@HHHHHHHHHHHHHHH@@@@@@@@@@@H@@@@\
HHHHH@HHHHHHHHHHHHHHHHHHHHHHHHH@";
int AsnObj::write(const uchar *from, ulong lth)
{
/**
Procedure:
1. IF it's an object identifier (tables are only derived), call that write
ELSE IF it's a bit string, call that write
ELSE IF it's forbidden, return error
ELSE return what _write returns
**/
AsnObjectIdentifier *objp;
AsnObj *tobjp = this;
int ansr;
if (!from) return asn_obj_err(ASN_NULL_PTR);
if ((_flags & ASN_DEFINED_FLAG) && !(tobjp = check_defined(tobjp)))
return asn_obj_err(ASN_NO_DEF_ERR);
objp = (AsnObjectIdentifier *)tobjp;
if (tobjp->_type == ASN_OBJ_ID) ansr = objp->write((const char *)from, lth);
else if (tobjp->_type == ASN_BITSTRING)
ansr = ((AsnBitString *)tobjp)->write(from, lth, 0);
else if (tobjp->_type == ASN_NONE) ansr = asn_obj_err(ASN_NONE_ERR);
else ansr = tobjp->_write(from, lth);
return ansr;
}
int AsnObj::_write(const uchar *from, ulong lth)
{
/**
Procedure:
1. IF it or any ancestor is the last member of a SET/SEQUENCE OF
Return error
IF it's a NULL or a NONE, report invalid type
IF it's a choice or defined
IF it's defined
Search for the defined item
IF none, return -1
IF it's (still) a choice
IF there's no mask in the first sub-object, return -1
Scan the input to find the type
Scan the choices to find the best fit
1a. IF any higher object is a 'defined' but isn't defined yet, return -1
2. IF it's primitive OR it has no sub (an ANY)
IF it's a BOOLEAN AND it's more than one octet, return -1
IF there's a mask, check the contents of 'from'
IF the size is out of range, return -1
IF there's a table
Search the table for this string
IF none found, return -1
Save the index into the table
IF this is an INTEGER, delete leading non-significant bytes
IF this is an ENUMERATED OR an INTEGER with defined values
IF the value to be put in isn't defined
Return -1 with undefined-value message
IF it's an enumerated type
IF parent is a bit string
IF it's empty, make a big enough _valp (including leading byte)
ELSE IF it's too small
Get a big enough buffer
Read the string into the buffer
Write it to the parent
Put value into requested bit
ELSE IF parent is an integer
Return result of writing value of tag into parent
ELSE
IF there is already a valp, delete it
Make a new valp
Fill it
IF it's a time AND its value is bad, return error
Mark this filled
3. Mark all higher objects filled in and clear non-chosen choices
IF object is a time AND it is invalid, report error
4. IF there's a table, mark the defined member chosen and clear any others
Return the length written
5. FOR all objects in this chain
Decode them, advancing the pointer
Return count of what was written
**/
int i, table_index, map_num;
long tmp;
const uchar *c, *e = &from[lth];
AsnObj *objp = this, *subp, *superp, *tobjp;
AsnTableObj *ntablep;
/* step 1 */
if ((i = check_of(objp)) < 0) return i;
if (_type == ASN_NONE || (_type == ASN_NULL && lth > 0))
return asn_obj_err((_type == ASN_NONE)? ASN_NONE_ERR: ASN_TYPE_ERR);
if (objp->_type == ASN_CHOICE)
{
if ((_flags & ASN_DEFINED_FLAG) && !(objp = check_defined(objp)))
return asn_obj_err(ASN_NO_DEF_ERR);
if (objp->_type == ASN_CHOICE)
{
if (!objp->_sub->_mask) return asn_obj_err(ASN_CHOICE_ERR);
for (i = 0xFF, c = from; c < e; i &= (char_table[*c++]));
for (tobjp = objp->_sub; tobjp && !(tobjp->_mask & i); tobjp =
tobjp->_next);
if (c < e || !tobjp)
{
asn_obj_err(ASN_NO_CHOICE_ERR);
return -1;
}
for (subp = objp->_sub; subp; subp->clear(), subp = subp->_next);
objp = tobjp;
}
}
for(superp = objp->_supra; superp; superp = superp->_supra) /* step 1a */
{
if (superp->_type == ASN_CHOICE && (superp->_flags & ASN_DEFINED_FLAG) )
{
for (tobjp = superp->_sub; tobjp && !(tobjp->_flags & ASN_CHOSEN_FLAG);
tobjp = tobjp->_next);
if (!tobjp) return asn_obj_err(ASN_NO_DEF_ERR);
}
}
/* step 2 */
if (!(objp->_type & ASN_CONSTRUCTED) || !objp->_sub) // use _type, not _tag
{ // in case of explicit tagging
if (objp->_type == ASN_BOOLEAN && lth != 1)
return asn_obj_err(ASN_BOUNDS_ERR);
if (objp->_mask && (i = check_mask(objp, from, lth)) < 0)
return i;
if (objp->_max && (lth > objp->_max || lth < objp->_min))
return asn_obj_err(ASN_BOUNDS_ERR);
if ((objp->_flags & ASN_TABLE_FLAG))
{
for(table_index = 0, ntablep = (AsnTableObj *)objp->_sub;
ntablep && compare(ntablep, from, (int)lth);
ntablep = (AsnTableObj *)ntablep->_next, table_index++);
if (!ntablep) return asn_obj_err(ASN_DEFINER_ERR);
}
if (objp->_type == ASN_INTEGER)
{
while (lth > 1 && ((!*from && !(from[1] & 0x80)) ||
(*from == 0xFF && (from[1] & 0x80))))
{
from++;
lth--;
}
}
if (objp->_sub && (objp->_sub->_flags & ASN_ENUM_FLAG) &&
(objp->_tag == ASN_INTEGER || objp->_tag == ASN_ENUMERATED))
{
long tmp;
for (tmp = 0, i = lth, c = from; i--; tmp = (tmp << 8) + *c++);
for (subp = objp->_sub; subp && subp->_tag != tmp; subp =
subp->_next);
if (!subp) return asn_obj_err(ASN_UNDEF_VALUE);
}
if ((objp->_flags & ASN_ENUM_FLAG))
{
superp = objp->_supra;
if (superp->_type == ASN_BITSTRING)
{
int j, newsize = ((objp->_tag + 8) >> 3) + 1;
if (!superp->_valp)
superp->_valp = new UcharArray(newsize);
else if ((j = (*superp->_valp)[0]) ||
newsize > superp->_valp->size())
{
uchar *tmpc;
i = superp->size();
tmpc = (uchar *)calloc(((newsize > i)? newsize: i), 1);
i = ((AsnBitString *)superp)->read(tmpc, &j);
((AsnBitString *)superp)->write((const uchar *)tmpc, (ulong)i, 0);
free(tmpc);
}
for (j = (objp->_tag & 7), i = 0x80; j--; i >>= 1);
j = 1 + (objp->_tag >> 3 );
if (*from) (*superp->_valp)[j] |= i;
else (*superp->_valp)[j] &= ~i;
superp->_flags |= ASN_FILLED_FLAG;
}
else if (superp->_type == ASN_INTEGER ||
superp->_type == ASN_ENUMERATED) return superp->write(objp->_tag);
else return asn_obj_err(ASN_GEN_ERR);
}
else
{
if (objp->_valp)
{
delete objp->_valp;
objp->_valp = (UcharArray *)0;
}
objp->_valp = new UcharArray(from, lth);
}
objp->fill_upward(ASN_FILLED_FLAG); /* step 3 */
if ((objp->_type == ASN_UTCTIME || objp->_type == ASN_GENTIME) &&
objp->read(&tmp) < 0)
{
delete objp->_valp;
objp->_valp = (UcharArray *)0;
objp->_flags &= ~(ASN_FILLED_FLAG);
return asn_obj_err(ASN_TIME_ERR);
}
subp = objp; /* step 3 */
if ((objp->_flags & ASN_TABLE_FLAG) && /* step 4 */
((AsnTableObj *)objp)->set_definees(table_index) < 0) return -1;
return lth;
}
/* step 5 */
int of = (objp->_flags & ASN_OF_FLAG);
objp->clear();
for(map_num = 0, c = from, subp = objp->_sub; (subp || of) && c < e; subp =
subp->_next, map_num++)
{
i = subp->decode(c);
if (!of) /* in case decode skipped some empty optional items */
for ( ; subp->_next && !(subp->_flags & ASN_FILLED_FLAG);
subp = subp->_next, map_num++);
else /* because decode inserted the object ahead of subp */
for (tobjp = subp, subp = objp->_sub, map_num = 0; subp != tobjp &&
subp->_next != tobjp; subp = subp->_next, map_num++);
if (i < 0)
{
stuff(map_num);
return (i - (c - from));
}
c += i;
}
return (c - from);
}
int AsnObj::write(long val)
{
/**
Procedure:
1. IF this is ANY DEFINED BY, find which one is defined
IF current object is neither boolean NOR integer NOR enumerated NOR time
return -1 with type error msg
2. IF it's either type of time
Convert the val to a char string for GMT
ELSE IF it's a boolean
Set length to 1
Put val into buf
ELSE convert val into a string
Return the length written
**/
int i;
AsnObj *objp = this;
char buf[20], *c;
/* step 1 */
if ((_flags & ASN_DEFINED_FLAG) && !(objp = check_defined(objp)))
return asn_obj_err(ASN_NO_DEF_ERR);
if (!objp) return asn_obj_err(ASN_NO_DEF_ERR);
if (objp->_type != ASN_BOOLEAN && objp->_type != ASN_INTEGER &&
objp->_type != ASN_ENUMERATED && objp->_type != ASN_UTCTIME &&
objp->_type != ASN_GENTIME) return asn_obj_err(ASN_TYPE_ERR);
/* step 2 */
if (objp->_type == ASN_UTCTIME || objp->_type == ASN_GENTIME)
{
if (val < 0) return asn_obj_err(ASN_TIME_ERR);
c = (objp->_type == ASN_GENTIME)? &buf[2]: buf;
i = put_asn_time(c, (ulong)val);
if (c > buf) /* make Gen time out of UTC time from put_asn_time() */
{
memcpy(buf, ((*c >= 7)? "19": "20"), 2);
i += 2;
}
}
else if (objp->_type == ASN_BOOLEAN)
{
i = 1;
*buf = (val != 0);
}
else
{
long tmp = val;
if (val < 0) for (i = 0; tmp != -1; tmp >>= 8, i++)
{ /* force 0x80 in MSbyte of integer*/
if (tmp < -0x80 && tmp > -0x100) i++;
}
else for (i = 0; tmp; tmp >>= 8, i++)
{ /* prevent 0x80 in MSbyte of integer */
if (tmp >= 0x80 && tmp < 0x100) i++;
}
if (!i) i++;
for (c = &buf[i - 1]; c >= buf; *c-- = val & 0xFF, val >>= 8);
}
return objp->_write((const uchar *)buf, i); /* to do the table stuff etc. */
}
int AsnBitString::write(const uchar *from, ulong lth, int shift)
{
short box;
int i;
if (!from) return asn_obj_err(ASN_NULL_PTR);
if ((i = check_of(this)) < 0) return i;
if (_valp)
{
delete _valp;
_valp = (UcharArray *)0;
}
_valp = new UcharArray(++lth);
(*_valp)[0] = shift;
if (!shift) for (i = 1; i < lth; (*_valp)[i++] = *from++);
else for (i = 1; i < lth; from++)
{
box = (short)*from;
box <<= shift;
(*_valp)[i++] |= (box >> 8);
(*_valp)[i] = (box & 0xFF);
}
fill_upward(ASN_FILLED_FLAG);
return (lth - 1);
}
int AsnObjectIdentifier::write(const char *from, ulong lth)
{
/**
Procedure:
1. Form first field
Find out how much space that requires
2. Find out how much space the remaining fields need
3. Convert the dot notation to binary
Call _write to do the table stuff etc.
**/
const char *c = from, *e = &from[lth];
uchar *buf, *b, *a;
long val, tmp;
int siz, i;
AsnObj *objp = this;
/* step 1 */
if (!from) return asn_obj_err(ASN_NULL_PTR);
for (val = 0; c < e && *c != '.'; val = (val * 10) + *c++ - '0');
val *= 40;
for(c++, tmp = 0; c < e && *c != '.'; tmp = (tmp * 10) + *c++ - '0');
tmp += val;
for (val = tmp, siz = 0; tmp; siz++) tmp >>= 7;
/* step 2 */
for (c++; c < e && *c; c++)
{
for (tmp = 0; *c && c < e && *c != '.'; tmp = (tmp * 10) + *c++ - '0');
if (!tmp) siz++;
else for ( ; tmp; siz++) tmp >>= 7;
}
for(c = from; c < e && *c && *c != '.'; c++);
for(c++; c < e && *c && *c != '.'; c++); /* c at 2nd dot */
buf = (uchar *)calloc(siz, 1);
/* step 3 */
for (tmp = val, siz = 0; tmp; siz++) tmp >>= 7; /* siz of first field */
/* put it into buf */
for (i = siz, tmp = val, b = &buf[siz]; siz--; val >>= 7)
*(--b) = (uchar)(val & 0x7F) | ((tmp != val)? 0x80: 0);
for (c++; c < e && *c; c++) /* now do next fields */
{
for (val = 0; c < e && *c && *c != '.'; val = (val * 10) + *c++ - '0');
if (!val) siz = 1;
else for (tmp = val, siz = 0; tmp; siz++) tmp >>= 7;
for(a = &buf[i], i += siz, tmp = val, b = &a[siz]; siz--; val >>= 7)
*(--b) = (uchar)(val & 0x7F) | ((tmp != val)? 0x80: 0);
}
lth = objp->_write(buf, i);
free(buf);
return lth;
}
int AsnObj::_append(const uchar *from, ulong lth)
{
int i;
if (_max && vsize() + lth > _max) return asn_obj_err(ASN_BOUNDS_ERR);
if (_mask && (i = check_mask(this, from, lth)) < 0) return i;
_valp->append(from, lth);
return lth;
}
static AsnObj *check_defined(AsnObj *objp)
{
AsnObj *subp;
for (subp = objp->_sub; subp && !(subp->_flags & ASN_CHOSEN_FLAG);
subp = subp->_next);
return subp;
}
static int check_mask(AsnObj *objp, const uchar *from, int lth)
{
const uchar *c;
for(c = from; lth-- && (char_table[*c] & objp->_mask); c++);
if (lth >= 0)
{
asn_obj_err(ASN_MASK_ERR);
return (from - c);
}
return 1;
}
static int check_of(AsnObj *objp)
{
for( ; objp; objp = objp->_supra)
{
if (objp->_supra && (objp->_supra->_flags & ASN_OF_FLAG) &&
!objp->_next) return asn_obj_err(ASN_OF_BOUNDS_ERR);
}
return 1;
}
static int compare(AsnObj *objp, const uchar *from, int lth)
{
uchar *c = &(*objp->_valp)[0], *e;
if (objp->_valp->size() == 2 && c[0] == 0xFF && c[1] == 0xFF) return 0;
if (lth != objp->_valp->size()) return -1;
for (e = &c[lth]; c < e && *c == *from++; c++);
if (c < e) return -1;
return 0;
}
static ulong put_num (char *to, ulong val, int lth)
{
char *c;
for (c = &to[lth]; c > to; )
{
*(--c) = (val % 10) + '0';
val /= 10;
}
return val;
}
static int put_asn_time(char *to, ulong time)
{
ushort *mop;
long da, min, sec;
char *c = to;
sec = (time % 60);
time /= 60;
min = (time % 60);
time /= 60;
da = (time % 24);
put_num (&c[UTCSE],(ulong)sec,UTCSESIZ);
put_num (&c[UTCMI],(ulong)min,UTCMISIZ);
put_num (&c[UTCHR],(ulong)da,UTCHRSIZ);
time /= 24; /* day number */
time += (((UTCBASE - 1) % 4) * 365); /* days since leap year before base year */
da = time % 1461; /* da # in quadrenniad */
time /= 1461; /* quadrenniads since prior leap yr */
sec = ((time * 4) + ((da == 1460)? 3 : (da / 365)) - ((UTCBASE - 1) % 4));
/* yrs since base yr */
if (da == 1460) da = 365;
else da %= 365;
for (mop = _mos; da >= *mop; mop++);
if (mop > &_mos[12]) mop--;
if ((sec % 4) == (UTCBASE % 4)) /* leap year */
{
if (da == 59) mop--; /* Feb 29 */
else if (da > 59 && (da -= 1) < mop[-1]) mop--;
}
put_num (&c[UTCDA],(ulong)(da + 1 - mop[-1]),UTCDASIZ);
put_num (&c[UTCMO],(ulong)(mop - _mos),UTCMOSIZ);
put_num (&c[UTCYR],(ulong)(sec + UTCBASE),UTCYRSIZ);
c += UTCSE + UTCSESIZ;
*c++ = 'Z';
return (c - to);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -