else isopt = seqtt->flags & ASN1_TFLG_OPTIONAL;
else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL);
int ASN1_item_ex_d2i(ASN1_VALUE **pval, unsigned char **in, long len, const ASN1_ITEM *it,				int tag, int aclass, char opt, ASN1_TLC *ctx){	const ASN1_TEMPLATE *tt, *errtt = NULL;	const ASN1_COMPAT_FUNCS *cf;	const ASN1_EXTERN_FUNCS *ef;	const ASN1_AUX *aux = it->funcs;	ASN1_aux_cb *asn1_cb;	unsigned char *p, *q, imphack = 0, oclass;	char seq_eoc, seq_nolen, cst, isopt;	long tmplen;	int i;	int otag;	int ret = 0;	ASN1_VALUE *pchval, **pchptr, *ptmpval;	if(!pval) return 0;	if(aux && aux->asn1_cb) asn1_cb = aux->asn1_cb;	else asn1_cb = 0;	switch(it->itype) {		case ASN1_ITYPE_PRIMITIVE:		if(it->templates)			return asn1_template_ex_d2i(pval, in, len, it->templates, opt, ctx);		return asn1_d2i_ex_primitive(pval, in, len, it, tag, aclass, opt, ctx);		break;		case ASN1_ITYPE_MSTRING:		p = *in;		/* Just read in tag and class */		ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, &p, len, -1, 0, 1, ctx);		if(!ret) {			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);			goto err;		} 		/* Must be UNIVERSAL class */		if(oclass != V_ASN1_UNIVERSAL) {			/* If OPTIONAL, assume this is OK */			if(opt) return -1;			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_NOT_UNIVERSAL);			goto err;		} 		/* Check tag matches bit map */		if(!(ASN1_tag2bit(otag) & it->utype)) {			/* If OPTIONAL, assume this is OK */			if(opt) return -1;			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MSTRING_WRONG_TAG);			goto err;		} 		return asn1_d2i_ex_primitive(pval, in, len, it, otag, 0, 0, ctx);		case ASN1_ITYPE_EXTERN:		/* Use new style d2i */		ef = it->funcs;		return ef->asn1_ex_d2i(pval, in, len, it, tag, aclass, opt, ctx);		case ASN1_ITYPE_COMPAT:		/* we must resort to old style evil hackery */		cf = it->funcs;		/* If OPTIONAL see if it is there */		if(opt) {			int exptag;			p = *in;			if(tag == -1) exptag = it->utype;			else exptag = tag;			/* Don't care about anything other than presence of expected tag */			ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, &p, len, exptag, aclass, 1, ctx);			if(!ret) {				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);				goto err;			}			if(ret == -1) return -1;		}		/* This is the old style evil hack IMPLICIT handling:		 * since the underlying code is expecting a tag and		 * class other than the one present we change the		 * buffer temporarily then change it back afterwards.		 * This doesn't and never did work for tags > 30.		 *		 * Yes this is *horrible* but it is only needed for		 * old style d2i which will hopefully not be around		 * for much longer.		 * FIXME: should copy the buffer then modify it so		 * the input buffer can be const: we should *always*		 * copy because the old style d2i might modify the		 * buffer.		 */		if(tag != -1) {			p = *in;			imphack = *p;			*p = (*p & V_ASN1_CONSTRUCTED) | it->utype;		}		ptmpval = cf->asn1_d2i(pval, in, len);		if(tag != -1) *p = imphack;		if(ptmpval) return 1;		ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);		goto err;		case ASN1_ITYPE_CHOICE:		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))				goto auxerr;		/* CHOICE type, try each possibility in turn */		pchval = NULL;		p = *in;		for(i = 0, tt=it->templates; i < it->tcount; i++, tt++) {			/* We mark field as OPTIONAL so its absence			 * can be recognised.			 */			ret = asn1_template_ex_d2i(&pchval, &p, len, tt, 1, ctx);			/* If field not present, try the next one */			if(ret == -1) continue;			/* If positive return, read OK, break loop */			if(ret > 0) break;			/* Otherwise must be an ASN1 parsing error */			errtt = tt;			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);			return 0;		}		/* Did we fall off the end without reading anything? */		if(i == it->tcount) {			/* If OPTIONAL, this is OK */			if(opt) return -1;			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_NO_MATCHING_CHOICE_TYPE);			return 0;		}		/* Otherwise we got a match, allocate structure and populate it */		if(!*pval) {			if(!ASN1_item_ex_new(pval, it)) {				errtt = tt;				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);				return 0;			}		}		pchptr = asn1_get_field_ptr(pval, tt);		*pchptr = pchval;		asn1_set_choice_selector(pval, i, it);		*in = p;		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))				goto auxerr;		return 1;		case ASN1_ITYPE_SEQUENCE:		p = *in;		tmplen = len;		/* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */		if(tag == -1) {			tag = V_ASN1_SEQUENCE;			aclass = V_ASN1_UNIVERSAL;		}		/* Get SEQUENCE length and update len, p */		ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, &p, len, tag, aclass, opt, ctx);		if(!ret) {			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);			goto err;		} else if(ret == -1) return -1;		if(aux && (aux->flags & ASN1_AFLG_BROKEN)) {			len = tmplen - (p - *in);			seq_nolen = 1;		} else seq_nolen = seq_eoc;	/* If indefinite we don't do a length check */		if(!cst) {			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_NOT_CONSTRUCTED);			goto err;		}		if(!*pval) {			if(!ASN1_item_ex_new(pval, it)) {				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ERR_R_NESTED_ASN1_ERROR);				goto err;			}		}		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it))				goto auxerr;		/* Get each field entry */		for(i = 0, tt = it->templates; i < it->tcount; i++, tt++) {			const ASN1_TEMPLATE *seqtt;			ASN1_VALUE **pseqval;			seqtt = asn1_do_adb(pval, tt, 1);			if(!seqtt) goto err;			pseqval = asn1_get_field_ptr(pval, seqtt);			/* Have we ran out of data? */			if(!len) break;			q = p;			if(asn1_check_eoc(&p, len)) {				if(!seq_eoc) {					ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_UNEXPECTED_EOC);					goto err;				}				len -= p - q;				seq_eoc = 0;				q = p;				break;			}			/* This determines the OPTIONAL flag value. The field cannot			 * be omitted if it is the last of a SEQUENCE and there is			 * still data to be read. This isn't strictly necessary but			 * it increases efficiency in some cases.			 */			if(i == (it->tcount - 1)) isopt = 0;			else isopt = seqtt->flags & ASN1_TFLG_OPTIONAL;			/* attempt to read in field, allowing each to be OPTIONAL */			ret = asn1_template_ex_d2i(pseqval, &p, len, seqtt, isopt, ctx);			if(!ret) {				errtt = seqtt;				goto err;			} else if(ret == -1) {				/* OPTIONAL component absent. Free and zero the field				 */				ASN1_template_free(pseqval, seqtt);				continue;			}			/* Update length */			len -= p - q;		}		/* Check for EOC if expecting one */		if(seq_eoc && !asn1_check_eoc(&p, len)) {			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_MISSING_EOC);			goto err;		}		/* Check all data read */		if(!seq_nolen && len) {			ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_SEQUENCE_LENGTH_MISMATCH);			goto err;		}		/* If we get here we've got no more data in the SEQUENCE,		 * however we may not have read all fields so check all		 * remaining are OPTIONAL and clear any that are.		 */		for(; i < it->tcount; tt++, i++) {			const ASN1_TEMPLATE *seqtt;			seqtt = asn1_do_adb(pval, tt, 1);			if(!seqtt) goto err;			if(seqtt->flags & ASN1_TFLG_OPTIONAL) {				ASN1_VALUE **pseqval;				pseqval = asn1_get_field_ptr(pval, seqtt);				ASN1_template_free(pseqval, seqtt);			} else {				errtt = seqtt;				ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_FIELD_MISSING);				goto err;			}		}		/* Save encoding */		if(!asn1_enc_save(pval, *in, p - *in, it)) goto auxerr;		*in = p;		if(asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it))				goto auxerr;		return 1;		default:		return 0;	}	auxerr:	ASN1err(ASN1_F_ASN1_ITEM_EX_D2I, ASN1_R_AUX_ERROR);	err:	ASN1_item_ex_free(pval, it);	if(errtt) ERR_add_error_data(4, "Field=", errtt->field_name, ", Type=", it->sname);	else ERR_add_error_data(2, "Type=", it->sname);	return 0;}