Commit message: Fixed an integral type promotion problem by adding a JAS_CAST.
Modified the jpc_tsfb_synthesize function so that it will be a noop for
an empty sequence (in order to avoid dereferencing a null pointer).
CVE: CVE-2016-10248
CWE: CWE-476
Vulnerability description: The jpc_tsfb_synthesize function in jpc_tsfb.c in JasPer before 1.900.9 allows remote attackers to cause a denial of service (NULL pointer dereference) via vectors involving an empty sequence.

Project: jasper
File: jpc_dec.c

static void calcstepsizes(uint_fast16_t refstepsize, int numrlvls,
  uint_fast16_t *stepsizes)
{
	int bandno;
	int numbands;
	uint_fast16_t expn;
	uint_fast16_t mant;
	expn = JPC_QCX_GETEXPN(refstepsize);
	mant = JPC_QCX_GETMANT(refstepsize);
	numbands = 3 * numrlvls - 2;
	for (bandno = 0; bandno < numbands; ++bandno) {
		stepsizes[bandno] = JPC_QCX_MANT(mant) | JPC_QCX_EXPN(expn +
		  (numrlvls - 1) - (numrlvls - 1 - ((bandno > 0) ? ((bandno + 2) / 3) : (0))));
	}
}

Project: jasper
File: jpc_dec.c

static jpc_fix_t jpc_calcabsstepsize(int stepsize, int numbits)
{
	jpc_fix_t absstepsize;
	int n;

	absstepsize = jpc_inttofix(1);
	n = JPC_FIX_FRACBITS - 11;
	absstepsize |= (n >= 0) ? (JPC_QCX_GETMANT(stepsize) << n) :
	  (JPC_QCX_GETMANT(stepsize) >> (-n));
	n = numbits - JPC_QCX_GETEXPN(stepsize);
	absstepsize = (n >= 0) ? (absstepsize << n) : (absstepsize >> (-n));
	return absstepsize;
}

Project: jasper
File: jpc_dec.c

static jpc_dec_cp_t *jpc_dec_cp_copy(jpc_dec_cp_t *cp)
{
	jpc_dec_cp_t *newcp;
	jpc_dec_ccp_t *newccp;
	jpc_dec_ccp_t *ccp;
	int compno;

	if (!(newcp = jpc_dec_cp_create(cp->numcomps))) {
		return 0;
	}
	newcp->flags = cp->flags;
	newcp->prgord = cp->prgord;
	newcp->numlyrs = cp->numlyrs;
	newcp->mctid = cp->mctid;
	newcp->csty = cp->csty;
	jpc_pchglist_destroy(newcp->pchglist);
	newcp->pchglist = 0;
	if (!(newcp->pchglist = jpc_pchglist_copy(cp->pchglist))) {
		jas_free(newcp);
		return 0;
	}
	for (compno = 0, newccp = newcp->ccps, ccp = cp->ccps;
	  compno < cp->numcomps;
	  ++compno, ++newccp, ++ccp) {
		*newccp = *ccp;
	}
	return newcp;
}

Project: jasper
File: jpc_dec.c

static jpc_dec_cp_t *jpc_dec_cp_create(uint_fast16_t numcomps)
{
	jpc_dec_cp_t *cp;
	jpc_dec_ccp_t *ccp;
	int compno;

	if (!(cp = jas_malloc(sizeof(jpc_dec_cp_t)))) {
		return 0;
	}
	cp->flags = 0;
	cp->numcomps = numcomps;
	cp->prgord = 0;
	cp->numlyrs = 0;
	cp->mctid = 0;
	cp->csty = 0;
	if (!(cp->ccps = jas_alloc2(cp->numcomps, sizeof(jpc_dec_ccp_t)))) {
		goto error;
	}
	if (!(cp->pchglist = jpc_pchglist_create())) {
		goto error;
	}
	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
	  ++compno, ++ccp) {
		ccp->flags = 0;
		ccp->numrlvls = 0;
		ccp->cblkwidthexpn = 0;
		ccp->cblkheightexpn = 0;
		ccp->qmfbid = 0;
		ccp->numstepsizes = 0;
		ccp->numguardbits = 0;
		ccp->roishift = 0;
		ccp->cblkctx = 0;
	}
	return cp;
error:
	if (cp) {
		jpc_dec_cp_destroy(cp);
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static void jpc_dec_cp_destroy(jpc_dec_cp_t *cp)
{
	if (cp->ccps) {
		jas_free(cp->ccps);
	}
	if (cp->pchglist) {
		jpc_pchglist_destroy(cp->pchglist);
	}
	jas_free(cp);
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_isvalid(jpc_dec_cp_t *cp)
{
	uint_fast16_t compcnt;
	jpc_dec_ccp_t *ccp;

	if (!(cp->flags & JPC_CSET) || !(cp->flags & JPC_QSET)) {
		return 0;
	}
	for (compcnt = cp->numcomps, ccp = cp->ccps; compcnt > 0; --compcnt,
	  ++ccp) {
		/* Is there enough step sizes for the number of bands? */
		if ((ccp->qsty != JPC_QCX_SIQNT && JAS_CAST(int, ccp->numstepsizes) < 3 *
		  ccp->numrlvls - 2) || (ccp->qsty == JPC_QCX_SIQNT &&
		  ccp->numstepsizes != 1)) {
			return 0;
		}
	}
	return 1;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_prepare(jpc_dec_cp_t *cp)
{
	jpc_dec_ccp_t *ccp;
	int compno;
	int i;
	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
	  ++compno, ++ccp) {
		if (!(ccp->csty & JPC_COX_PRT)) {
			for (i = 0; i < JPC_MAXRLVLS; ++i) {
				ccp->prcwidthexpns[i] = 15;
				ccp->prcheightexpns[i] = 15;
			}
		}
		if (ccp->qsty == JPC_QCX_SIQNT) {
			calcstepsizes(ccp->stepsizes[0], ccp->numrlvls, ccp->stepsizes);
		}
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static void jpc_dec_cp_resetflags(jpc_dec_cp_t *cp)
{
	int compno;
	jpc_dec_ccp_t *ccp;
	cp->flags &= (JPC_CSET | JPC_QSET);
	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
	  ++compno, ++ccp) {
		ccp->flags = 0;
	}
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_setfromcoc(jpc_dec_cp_t *cp, jpc_coc_t *coc)
{
	jpc_dec_cp_setfromcox(cp, &cp->ccps[coc->compno], &coc->compparms, JPC_COC);
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_setfrompoc(jpc_dec_cp_t *cp, jpc_poc_t *poc, int reset)
{
	int pchgno;
	jpc_pchg_t *pchg;
	if (reset) {
		while (jpc_pchglist_numpchgs(cp->pchglist) > 0) {
			pchg = jpc_pchglist_remove(cp->pchglist, 0);
			jpc_pchg_destroy(pchg);
		}
	}
	for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) {
		if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) {
			return -1;
		}
		if (jpc_pchglist_insert(cp->pchglist, -1, pchg)) {
			return -1;
		}
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_setfromqcc(jpc_dec_cp_t *cp, jpc_qcc_t *qcc)
{
	return jpc_dec_cp_setfromqcx(cp, &cp->ccps[qcc->compno], &qcc->compparms, JPC_QCC);
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_setfromqcd(jpc_dec_cp_t *cp, jpc_qcd_t *qcd)
{
	int compno;
	jpc_dec_ccp_t *ccp;
	for (compno = 0, ccp = cp->ccps; compno < cp->numcomps;
	  ++compno, ++ccp) {
		jpc_dec_cp_setfromqcx(cp, ccp, &qcd->compparms, 0);
	}
	cp->flags |= JPC_QSET;
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_cp_setfromqcx(jpc_dec_cp_t *cp, jpc_dec_ccp_t *ccp,
  jpc_qcxcp_t *compparms, int flags)
{
	int bandno;

	/* Eliminate compiler warnings about unused variables. */
	cp = 0;

	if ((flags & JPC_QCC) || !(ccp->flags & JPC_QCC)) {
		ccp->flags |= flags | JPC_QSET;
		for (bandno = 0; bandno < compparms->numstepsizes; ++bandno) {
			ccp->stepsizes[bandno] = compparms->stepsizes[bandno];
		}
		ccp->numstepsizes = compparms->numstepsizes;
		ccp->numguardbits = compparms->numguard;
		ccp->qsty = compparms->qntsty;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static jpc_dec_t *jpc_dec_create(jpc_dec_importopts_t *impopts, jas_stream_t *in)
{
	jpc_dec_t *dec;

	if (!(dec = jas_malloc(sizeof(jpc_dec_t)))) {
		return 0;
	}

	dec->image = 0;
	dec->xstart = 0;
	dec->ystart = 0;
	dec->xend = 0;
	dec->yend = 0;
	dec->tilewidth = 0;
	dec->tileheight = 0;
	dec->tilexoff = 0;
	dec->tileyoff = 0;
	dec->numhtiles = 0;
	dec->numvtiles = 0;
	dec->numtiles = 0;
	dec->tiles = 0;
	dec->curtile = 0;
	dec->numcomps = 0;
	dec->in = in;
	dec->cp = 0;
	dec->maxlyrs = impopts->maxlyrs;
	dec->maxpkts = impopts->maxpkts;
dec->numpkts = 0;
	dec->ppmseqno = 0;
	dec->state = 0;
	dec->cmpts = 0;
	dec->pkthdrstreams = 0;
	dec->ppmstab = 0;
	dec->curtileendoff = 0;

	return dec;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_decode(jpc_dec_t *dec)
{
	jpc_ms_t *ms;
	jpc_dec_mstabent_t *mstabent;
	int ret;
	jpc_cstate_t *cstate;

	if (!(cstate = jpc_cstate_create())) {
		return -1;
	}
	dec->cstate = cstate;

	/* Initially, we should expect to encounter a SOC marker segment. */
	dec->state = JPC_MHSOC;

	for (;;) {

		/* Get the next marker segment in the code stream. */
		if (!(ms = jpc_getms(dec->in, cstate))) {
			jas_eprintf("cannot get marker segment\n");
			return -1;
		}

		mstabent = jpc_dec_mstab_lookup(ms->id);
		assert(mstabent);

		/* Ensure that this type of marker segment is permitted
		  at this point in the code stream. */
		if (!(dec->state & mstabent->validstates)) {
			jas_eprintf("unexpected marker segment type\n");
			jpc_ms_destroy(ms);
			return -1;
		}

		/* Process the marker segment. */
		if (mstabent->action) {
			ret = (*mstabent->action)(dec, ms);
		} else {
			/* No explicit action is required. */
			ret = 0;
		}

		/* Destroy the marker segment. */
		jpc_ms_destroy(ms);

		if (ret < 0) {
			return -1;
		} else if (ret > 0) {
			break;
		}

	}

	return 0;
}

Project: jasper
File: jpc_dec.c

static void jpc_dec_destroy(jpc_dec_t *dec)
{
	if (dec->cstate) {
		jpc_cstate_destroy(dec->cstate);
	}
	if (dec->pkthdrstreams) {
		jpc_streamlist_destroy(dec->pkthdrstreams);
	}
	if (dec->image) {
		jas_image_destroy(dec->image);
	}

	if (dec->cp) {
		jpc_dec_cp_destroy(dec->cp);
	}

	if (dec->cmpts) {
		jas_free(dec->cmpts);
	}

	if (dec->tiles) {
		jas_free(dec->tiles);
	}

	jas_free(dec);
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_dump(jpc_dec_t *dec, FILE *out)
{
	jpc_dec_tile_t *tile;
	int tileno;
	jpc_dec_tcomp_t *tcomp;
	int compno;
	jpc_dec_rlvl_t *rlvl;
	int rlvlno;
	jpc_dec_band_t *band;
	int bandno;
	jpc_dec_prc_t *prc;
	int prcno;
	jpc_dec_cblk_t *cblk;
	int cblkno;

	for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles;
	  ++tileno, ++tile) {
		for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
		  ++compno, ++tcomp) {
			for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno <
			  tcomp->numrlvls; ++rlvlno, ++rlvl) {
fprintf(out, "RESOLUTION LEVEL %d\n", rlvlno);
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
  rlvl->xstart, rlvl->ystart, rlvl->xend, rlvl->yend, rlvl->xend -
  rlvl->xstart, rlvl->yend - rlvl->ystart);
				for (bandno = 0, band = rlvl->bands;
				  bandno < rlvl->numbands; ++bandno, ++band) {
fprintf(out, "BAND %d\n", bandno);
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
  jas_seq2d_xstart(band->data), jas_seq2d_ystart(band->data), jas_seq2d_xend(band->data),
  jas_seq2d_yend(band->data), jas_seq2d_xend(band->data) - jas_seq2d_xstart(band->data),
  jas_seq2d_yend(band->data) - jas_seq2d_ystart(band->data));
					for (prcno = 0, prc = band->prcs;
					  prcno < rlvl->numprcs; ++prcno,
					  ++prc) {
fprintf(out, "CODE BLOCK GROUP %d\n", prcno);
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
  prc->xstart, prc->ystart, prc->xend, prc->yend, prc->xend -
  prc->xstart, prc->yend - prc->ystart);
						for (cblkno = 0, cblk =
						  prc->cblks; cblkno <
						  prc->numcblks; ++cblkno,
						  ++cblk) {
fprintf(out, "CODE BLOCK %d\n", cblkno);
fprintf(out, "xs =%d, ys = %d, xe = %d, ye = %d, w = %d, h = %d\n",
  jas_seq2d_xstart(cblk->data), jas_seq2d_ystart(cblk->data), jas_seq2d_xend(cblk->data),
  jas_seq2d_yend(cblk->data), jas_seq2d_xend(cblk->data) - jas_seq2d_xstart(cblk->data),
  jas_seq2d_yend(cblk->data) - jas_seq2d_ystart(cblk->data));
						}
					}
				}
			}
		}
	}

	return 0;
}

Project: jasper
File: jpc_dec.c

static jpc_dec_mstabent_t *jpc_dec_mstab_lookup(uint_fast16_t id)
{
	jpc_dec_mstabent_t *mstabent;
	for (mstabent = jpc_dec_mstab; mstabent->id != 0; ++mstabent) {
		if (mstabent->id == id) {
			break;
		}
	}
	return mstabent;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_parseopts(char *optstr, jpc_dec_importopts_t *opts)
{
	jas_tvparser_t *tvp;

	opts->debug = 0;
	opts->maxlyrs = JPC_MAXLYRS;
	opts->maxpkts = -1;

	if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
		return -1;
	}

	while (!jas_tvparser_next(tvp)) {
		switch (jas_taginfo_nonull(jas_taginfos_lookup(decopts,
		  jas_tvparser_gettag(tvp)))->id) {
		case OPT_MAXLYRS:
			opts->maxlyrs = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_DEBUG:
			opts->debug = atoi(jas_tvparser_getval(tvp));
			break;
		case OPT_MAXPKTS:
			opts->maxpkts = atoi(jas_tvparser_getval(tvp));
			break;
		default:
			jas_eprintf("warning: ignoring invalid option %s\n",
			  jas_tvparser_gettag(tvp));
			break;
		}
	}

	jas_tvparser_destroy(tvp);

	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_cod(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_cod_t *cod = &ms->parms.cod;
	jpc_dec_tile_t *tile;

	switch (dec->state) {
	case JPC_MH:
		jpc_dec_cp_setfromcod(dec->cp, cod);
		break;
	case JPC_TPH:
		if (!(tile = dec->curtile)) {
			return -1;
		}
		if (tile->partno != 0) {
			return -1;
		}
		jpc_dec_cp_setfromcod(tile->cp, cod);
		break;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_com(jpc_dec_t *dec, jpc_ms_t *ms)
{
	/* Eliminate compiler warnings about unused variables. */
	dec = 0;
	ms = 0;

	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_crg(jpc_dec_t *dec, jpc_ms_t *ms)
{
	int cmptno;
	jpc_dec_cmpt_t *cmpt;
	jpc_crg_t *crg;

	crg = &ms->parms.crg;
	for (cmptno = 0, cmpt = dec->cmpts; cmptno < dec->numcomps; ++cmptno,
	  ++cmpt) {
		/* Ignore the information in the CRG marker segment for now.
		  This information serves no useful purpose for decoding anyhow.
		  Some other parts of the code need to be changed if these lines
		  are uncommented.
		cmpt->hsubstep = crg->comps[cmptno].hoff;
		cmpt->vsubstep = crg->comps[cmptno].voff;
		*/
	}
	return 0;
}

Project: jasper

static int jpc_dec_process_eoc(jpc_dec_t *dec, jpc_ms_t *ms)
{
	int tileno;
	jpc_dec_tile_t *tile;

	/* Eliminate compiler warnings about unused variables. */
	ms = 0;

	for (tileno = 0, tile = dec->tiles; tileno < dec->numtiles; ++tileno,
	  ++tile) {
		if (tile->state == JPC_TILE_ACTIVE) {
			if (jpc_dec_tiledecode(dec, tile)) {
				return -1;
			}
		}
		/* If the tile has not yet been finalized, finalize it. */
		if (tile->state != JPC_TILE_DONE) {
			jpc_dec_tilefini(dec, tile);
		}
	}

	/* We are done processing the code stream. */
	dec->state = JPC_MT;

	return 1;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_poc(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_poc_t *poc = &ms->parms.poc;
	jpc_dec_tile_t *tile;
	switch (dec->state) {
	case JPC_MH:
		if (jpc_dec_cp_setfrompoc(dec->cp, poc, 1)) {
			return -1;
		}
		break;
	case JPC_TPH:
		if (!(tile = dec->curtile)) {
			return -1;
		}
		if (!tile->partno) {
			if (jpc_dec_cp_setfrompoc(tile->cp, poc, (!tile->partno))) {
				return -1;
			}
		} else {
			jpc_pi_addpchgfrompoc(tile->pi, poc);
		}
		break;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_ppm(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_ppm_t *ppm = &ms->parms.ppm;
	jpc_ppxstabent_t *ppmstabent;

	if (!dec->ppmstab) {
		if (!(dec->ppmstab = jpc_ppxstab_create())) {
			return -1;
		}
	}

	if (!(ppmstabent = jpc_ppxstabent_create())) {
		return -1;
	}
	ppmstabent->ind = ppm->ind;
	ppmstabent->data = ppm->data;
	ppm->data = 0;
	ppmstabent->len = ppm->len;
	if (jpc_ppxstab_insert(dec->ppmstab, ppmstabent)) {
		return -1;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_ppt(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_ppt_t *ppt = &ms->parms.ppt;
	jpc_dec_tile_t *tile;
	jpc_ppxstabent_t *pptstabent;

	tile = dec->curtile;
	if (!tile->pptstab) {
		if (!(tile->pptstab = jpc_ppxstab_create())) {
			return -1;
		}
	}
	if (!(pptstabent = jpc_ppxstabent_create())) {
		return -1;
	}
	pptstabent->ind = ppt->ind;
	pptstabent->data = ppt->data;
	ppt->data = 0;
	pptstabent->len = ppt->len;
	if (jpc_ppxstab_insert(tile->pptstab, pptstabent)) {
		return -1;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_qcc(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_qcc_t *qcc = &ms->parms.qcc;
	jpc_dec_tile_t *tile;

	if (JAS_CAST(int, qcc->compno) >= dec->numcomps) {
		jas_eprintf("invalid component number in QCC marker segment\n");
		return -1;
	}
	switch (dec->state) {
	case JPC_MH:
		jpc_dec_cp_setfromqcc(dec->cp, qcc);
		break;
	case JPC_TPH:
		if (!(tile = dec->curtile)) {
			return -1;
		}
		if (tile->partno > 0) {
			return -1;
		}
		jpc_dec_cp_setfromqcc(tile->cp, qcc);
		break;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_qcd(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_qcd_t *qcd = &ms->parms.qcd;
	jpc_dec_tile_t *tile;

	switch (dec->state) {
	case JPC_MH:
		jpc_dec_cp_setfromqcd(dec->cp, qcd);
		break;
	case JPC_TPH:
		if (!(tile = dec->curtile)) {
			return -1;
		}
		if (tile->partno > 0) {
			return -1;
		}
		jpc_dec_cp_setfromqcd(tile->cp, qcd);
		break;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_rgn(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_rgn_t *rgn = &ms->parms.rgn;
	jpc_dec_tile_t *tile;

	if (JAS_CAST(int, rgn->compno) >= dec->numcomps) {
		jas_eprintf("invalid component number in RGN marker segment\n");
		return -1;
	}
	switch (dec->state) {
	case JPC_MH:
		jpc_dec_cp_setfromrgn(dec->cp, rgn);
		break;
	case JPC_TPH:
		if (!(tile = dec->curtile)) {
			return -1;
		}
		if (tile->partno > 0) {
			return -1;
		}
		jpc_dec_cp_setfromrgn(tile->cp, rgn);
		break;
	}

	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_soc(jpc_dec_t *dec, jpc_ms_t *ms)
{
	/* Eliminate warnings about unused variables. */
	ms = 0;

	/* We should expect to encounter a SIZ marker segment next. */
	dec->state = JPC_MHSIZ;

	return 0;
}

Project: jasper
File: jpc_dec.c

static int jpc_dec_process_sod(jpc_dec_t *dec, jpc_ms_t *ms)
{
	jpc_dec_tile_t *tile;
	int pos;

	/* Eliminate compiler warnings about unused variables. */
	ms = 0;

	if (!(tile = dec->curtile)) {
		return -1;
	}

	if (!tile->partno) {
		if (!jpc_dec_cp_isvalid(tile->cp)) {
			return -1;
		}
		jpc_dec_cp_prepare(tile->cp);
		if (jpc_dec_tileinit(dec, tile)) {
			return -1;
		}
	}

	/* Are packet headers stored in the main header or tile-part header? */
	if (dec->pkthdrstreams) {
		/* Get the stream containing the packet header data for this
		  tile-part. */
		if (!(tile->pkthdrstream = jpc_streamlist_remove(dec->pkthdrstreams, 0))) {
			return -1;
		}
	}

	if (tile->pptstab) {
		if (!tile->pkthdrstream) {
			if (!(tile->pkthdrstream = jas_stream_memopen(0, 0))) {
				return -1;
			}
		}
		pos = jas_stream_tell(tile->pkthdrstream);
		jas_stream_seek(tile->pkthdrstream, 0, SEEK_END);
		if (jpc_pptstabwrite(tile->pkthdrstream, tile->pptstab)) {
			return -1;
		}
		jas_stream_seek(tile->pkthdrstream, pos, SEEK_SET);
		jpc_ppxstab_destroy(tile->pptstab);
		tile->pptstab = 0;
	}

	if (jas_getdbglevel() >= 10) {
		jpc_dec_dump(dec, stderr);
	}

	if (jpc_dec_decodepkts(dec, (tile->pkthdrstream) ? tile->pkthdrstream :
	  dec->in, dec->in)) {
		jas_eprintf("jpc_dec_decodepkts failed\n");
		return -1;
	}

	/* Gobble any unconsumed tile data. */
	if (dec->curtileendoff > 0) {
		long curoff;
		uint_fast32_t n;
		curoff = jas_stream_getrwcount(dec->in);
		if (curoff < dec->curtileendoff) {
			n = dec->curtileendoff - curoff;
			jas_eprintf("warning: ignoring trailing garbage (%lu bytes)\n",
			  (unsigned long) n);

			while (n-- > 0) {
				if (jas_stream_getc(dec->in) == EOF) {
					jas_eprintf("read error\n");
					return -1;
				}
			}
		} else if (curoff > dec->curtileendoff) {
			jas_eprintf("warning: not enough tile data (%lu bytes)\n",
			  (unsigned long) curoff - dec->curtileendoff);
		}

	}

	if (tile->numparts > 0 && tile->partno == tile->numparts - 1) {
		if (jpc_dec_tiledecode(dec, tile)) {
			return -1;
		}
		jpc_dec_tilefini(dec, tile);
	}

	dec->curtile = 0;

	/* Increment the expected tile-part number. */
	++tile->partno;

	/* We should expect to encounter a SOT marker segment next. */
	dec->state = JPC_TPHSOT;

	return 0;
}

Project: jasper

static int jpc_dec_tilefini(jpc_dec_t *dec, jpc_dec_tile_t *tile)
{
	jpc_dec_tcomp_t *tcomp;
	int compno;
	int bandno;
	int rlvlno;
	jpc_dec_band_t *band;
	jpc_dec_rlvl_t *rlvl;
	int prcno;
	jpc_dec_prc_t *prc;
	jpc_dec_seg_t *seg;
	jpc_dec_cblk_t *cblk;
	int cblkno;

	if (tile->tcomps) {

		for (compno = 0, tcomp = tile->tcomps; compno < dec->numcomps;
		  ++compno, ++tcomp) {
			for (rlvlno = 0, rlvl = tcomp->rlvls; rlvlno < tcomp->numrlvls;
			  ++rlvlno, ++rlvl) {
				if (!rlvl->bands) {
					continue;
				}
				for (bandno = 0, band = rlvl->bands; bandno < rlvl->numbands;
				  ++bandno, ++band) {
					if (band->prcs) {
						for (prcno = 0, prc = band->prcs; prcno <
						  rlvl->numprcs; ++prcno, ++prc) {
							if (!prc->cblks) {
								continue;
							}
							for (cblkno = 0, cblk = prc->cblks; cblkno <
							  prc->numcblks; ++cblkno, ++cblk) {

								while (cblk->segs.head) {
									seg = cblk->segs.head;
									jpc_seglist_remove(&cblk->segs, seg);
									jpc_seg_destroy(seg);
								}
								jas_matrix_destroy(cblk->data);
								if (cblk->mqdec) {
									jpc_mqdec_destroy(cblk->mqdec);
								}
								if (cblk->nulldec) {
									jpc_bitstream_close(cblk->nulldec);
								}
								if (cblk->flags) {
									jas_matrix_destroy(cblk->flags);
								}
							}
							if (prc->incltagtree) {
								jpc_tagtree_destroy(prc->incltagtree);
							}
							if (prc->numimsbstagtree) {
								jpc_tagtree_destroy(prc->numimsbstagtree);
							}
							if (prc->cblks) {
								jas_free(prc->cblks);
							}
						}
					}
					if (band->data) {
						jas_matrix_destroy(band->data);
					}
					if (band->prcs) {
						jas_free(band->prcs);
					}
				}
				if (rlvl->bands) {
					jas_free(rlvl->bands);
				}
			}
			if (tcomp->rlvls) {
				jas_free(tcomp->rlvls);
			}
			if (tcomp->data) {
				jas_matrix_destroy(tcomp->data);
			}
			if (tcomp->tsfb) {
				jpc_tsfb_destroy(tcomp->tsfb);
			}
		}
	}

	if (tile->cp) {
		jpc_dec_cp_destroy(tile->cp);
	}
	if (tile->tcomps) {
		jas_free(tile->tcomps);
	}
	if (tile->pi) {
		jpc_pi_destroy(tile->pi);
	}
	if (tile->pkthdrstream) {
		jas_stream_close(tile->pkthdrstream);
	}
	if (tile->pptstab) {
		jpc_ppxstab_destroy(tile->pptstab);
	}

	tile->state = JPC_TILE_DONE;

	return 0;
}

Project: jasper
File: jpc_dec.c

jas_image_t *jpc_decode(jas_stream_t *in, char *optstr)
{
	jpc_dec_importopts_t opts;
	jpc_dec_t *dec;
	jas_image_t *image;

	dec = 0;

	if (jpc_dec_parseopts(optstr, &opts)) {
		goto error;
	}

	jpc_initluts();

	if (!(dec = jpc_dec_create(&opts, in))) {
		goto error;
	}

	/* Do most of the work. */
	if (jpc_dec_decode(dec)) {
		goto error;
	}

	if (jas_image_numcmpts(dec->image) >= 3) {
		jas_image_setclrspc(dec->image, JAS_CLRSPC_SRGB);
		jas_image_setcmpttype(dec->image, 0,
		  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
		jas_image_setcmpttype(dec->image, 1,
		  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
		jas_image_setcmpttype(dec->image, 2,
		  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
	} else {
		jas_image_setclrspc(dec->image, JAS_CLRSPC_SGRAY);
		jas_image_setcmpttype(dec->image, 0,
		  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
	}

	/* Save the return value. */
	image = dec->image;

	/* Stop the image from being discarded. */
	dec->image = 0;

	/* Destroy decoder. */
	jpc_dec_destroy(dec);

	return image;

error:
	if (dec) {
		jpc_dec_destroy(dec);
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

static void jpc_dequantize(jas_matrix_t *x, jpc_fix_t absstepsize)
{
	int i;
	int j;
	int t;

	assert(absstepsize >= 0);
	if (absstepsize == jpc_inttofix(1)) {
		return;
	}

	for (i = 0; i < jas_matrix_numrows(x); ++i) {
		for (j = 0; j < jas_matrix_numcols(x); ++j) {
			t = jas_matrix_get(x, i, j);
			if (t) {
				t = jpc_fix_mul(t, absstepsize);
			} else {
				t = 0;
			}
			jas_matrix_set(x, i, j, t);
		}
	}

}

Project: jasper
File: jpc_dec.c

static int jpc_pi_addpchgfrompoc(jpc_pi_t *pi, jpc_poc_t *poc)
{
	int pchgno;
	jpc_pchg_t *pchg;
	for (pchgno = 0; pchgno < poc->numpchgs; ++pchgno) {
		if (!(pchg = jpc_pchg_copy(&poc->pchgs[pchgno]))) {
			return -1;
		}
		if (jpc_pchglist_insert(pi->pchglist, -1, pchg)) {
			return -1;
		}
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

jpc_ppxstab_t *jpc_ppxstab_create()
{
	jpc_ppxstab_t *tab;

	if (!(tab = jas_malloc(sizeof(jpc_ppxstab_t)))) {
		return 0;
	}
	tab->numents = 0;
	tab->maxents = 0;
	tab->ents = 0;
	return tab;
}

Project: jasper
File: jpc_dec.c

void jpc_ppxstab_destroy(jpc_ppxstab_t *tab)
{
	int i;
	for (i = 0; i < tab->numents; ++i) {
		jpc_ppxstabent_destroy(tab->ents[i]);
	}
	if (tab->ents) {
		jas_free(tab->ents);
	}
	jas_free(tab);
}

Project: jasper
File: jpc_dec.c

int jpc_ppxstab_grow(jpc_ppxstab_t *tab, int maxents)
{
	jpc_ppxstabent_t **newents;
	if (tab->maxents < maxents) {
		newents = (tab->ents) ? jas_realloc2(tab->ents, maxents,
		  sizeof(jpc_ppxstabent_t *)) : jas_alloc2(maxents, sizeof(jpc_ppxstabent_t *));
		if (!newents) {
			return -1;
		}
		tab->ents = newents;
		tab->maxents = maxents;
	}
	return 0;
}

Project: jasper
File: jpc_dec.c

int jpc_ppxstab_insert(jpc_ppxstab_t *tab, jpc_ppxstabent_t *ent)
{
	int inspt;
	int i;

	for (i = 0; i < tab->numents; ++i) {
		if (tab->ents[i]->ind > ent->ind) {
			break;
		}
	}
	inspt = i;

	if (tab->numents >= tab->maxents) {
		if (jpc_ppxstab_grow(tab, tab->maxents + 128)) {
			return -1;
		}
	}

	for (i = tab->numents; i > inspt; --i) {
		tab->ents[i] = tab->ents[i - 1];
	}
	tab->ents[i] = ent;
	++tab->numents;

	return 0;
}

Project: jasper
File: jpc_dec.c

jpc_ppxstabent_t *jpc_ppxstabent_create()
{
	jpc_ppxstabent_t *ent;
	if (!(ent = jas_malloc(sizeof(jpc_ppxstabent_t)))) {
		return 0;
	}
	ent->data = 0;
	ent->len = 0;
	ent->ind = 0;
	return ent;
}

Project: jasper
File: jpc_dec.c

void jpc_ppxstabent_destroy(jpc_ppxstabent_t *ent)
{
	if (ent->data) {
		jas_free(ent->data);
	}
	jas_free(ent);
}

Project: jasper
File: jpc_dec.c

jpc_dec_seg_t *jpc_seg_alloc()
{
	jpc_dec_seg_t *seg;

	if (!(seg = jas_malloc(sizeof(jpc_dec_seg_t)))) {
		return 0;
	}
	seg->prev = 0;
	seg->next = 0;
	seg->passno = -1;
	seg->numpasses = 0;
	seg->maxpasses = 0;
	seg->type = JPC_SEG_INVALID;
	seg->stream = 0;
	seg->cnt = 0;
	seg->complete = 0;
	seg->lyrno = -1;
	return seg;
}

Project: jasper
File: jpc_dec.c

void jpc_seg_destroy(jpc_dec_seg_t *seg)
{
	if (seg->stream) {
		jas_stream_close(seg->stream);
	}
	jas_free(seg);
}

Project: jasper
File: jpc_dec.c

void jpc_seglist_insert(jpc_dec_seglist_t *list, jpc_dec_seg_t *ins, jpc_dec_seg_t *node)
{
	jpc_dec_seg_t *prev;
	jpc_dec_seg_t *next;

	prev = ins;
	node->prev = prev;
	next = prev ? (prev->next) : 0;
	node->prev = prev;
	node->next = next;
	if (prev) {
		prev->next = node;
	} else {
		list->head = node;
	}
	if (next) {
		next->prev = node;
	} else {
		list->tail = node;
	}
}

Project: jasper
File: jpc_dec.c

void jpc_seglist_remove(jpc_dec_seglist_t *list, jpc_dec_seg_t *seg)
{
	jpc_dec_seg_t *prev;
	jpc_dec_seg_t *next;

	prev = seg->prev;
	next = seg->next;
	if (prev) {
		prev->next = next;
	} else {
		list->head = next;
	}
	if (next) {
		next->prev = prev;
	} else {
		list->tail = prev;
	}
	seg->prev = 0;
	seg->next = 0;
}

Project: jasper
File: jpc_dec.c

jpc_streamlist_t *jpc_streamlist_create()
{
	jpc_streamlist_t *streamlist;
	int i;

	if (!(streamlist = jas_malloc(sizeof(jpc_streamlist_t)))) {
		return 0;
	}
	streamlist->numstreams = 0;
	streamlist->maxstreams = 100;
	if (!(streamlist->streams = jas_alloc2(streamlist->maxstreams,
	  sizeof(jas_stream_t *)))) {
		jas_free(streamlist);
		return 0;
	}
	for (i = 0; i < streamlist->maxstreams; ++i) {
		streamlist->streams[i] = 0;
	}
	return streamlist;
}

Project: jasper
File: jpc_dec.c

jas_stream_t *jpc_streamlist_get(jpc_streamlist_t *streamlist, int streamno)
{
	assert(streamno < streamlist->numstreams);
	return streamlist->streams[streamno];
}

Project: jasper
File: jpc_dec.c

int jpc_streamlist_insert(jpc_streamlist_t *streamlist, int streamno,
  jas_stream_t *stream)
{
	jas_stream_t **newstreams;
	int newmaxstreams;
	int i;
	/* Grow the array of streams if necessary. */
	if (streamlist->numstreams >= streamlist->maxstreams) {
		newmaxstreams = streamlist->maxstreams + 1024;
		if (!(newstreams = jas_realloc2(streamlist->streams,
		  (newmaxstreams + 1024), sizeof(jas_stream_t *)))) {
			return -1;
		}
		for (i = streamlist->numstreams; i < streamlist->maxstreams; ++i) {
			streamlist->streams[i] = 0;
		}
		streamlist->maxstreams = newmaxstreams;
		streamlist->streams = newstreams;
	}
	if (streamno != streamlist->numstreams) {
		/* Can only handle insertion at start of list. */
		return -1;
	}
	streamlist->streams[streamno] = stream;
	++streamlist->numstreams;
	return 0;
}

Project: jasper
File: jpc_dec.c

int jpc_streamlist_numstreams(jpc_streamlist_t *streamlist)
{
	return streamlist->numstreams;
}

Project: jasper
File: jpc_dec.c

jas_stream_t *jpc_streamlist_remove(jpc_streamlist_t *streamlist, int streamno)
{
	jas_stream_t *stream;
	int i;
	if (streamno >= streamlist->numstreams) {
		abort();
	}
	stream = streamlist->streams[streamno];
	for (i = streamno + 1; i < streamlist->numstreams; ++i) {
		streamlist->streams[i - 1] = streamlist->streams[i];
	}
	--streamlist->numstreams;
	return stream;
}

Project: jasper

jpc_tsfb_t *jpc_cod_gettsfb(int qmfbid, int numlvls)
{
	jpc_tsfb_t *tsfb;

	if (!(tsfb = malloc(sizeof(jpc_tsfb_t))))
		return 0;

	if (numlvls > 0) {
		switch (qmfbid) {
		case JPC_COX_INS:
			tsfb->qmfb = &jpc_ns_qmfb2d;
			break;
		default:
		case JPC_COX_RFT:
			tsfb->qmfb = &jpc_ft_qmfb2d;
			break;
		}
	} else {
		tsfb->qmfb = 0;
	}
	tsfb->numlvls = numlvls;
	return tsfb;
}

Project: jasper

int jpc_tsfb_analyze(jpc_tsfb_t *tsfb, jas_seq2d_t *a)
{
	return (tsfb->numlvls > 0) ? jpc_tsfb_analyze2(tsfb, jas_seq2d_getref(a,
	  jas_seq2d_xstart(a), jas_seq2d_ystart(a)), jas_seq2d_xstart(a),
	  jas_seq2d_ystart(a), jas_seq2d_width(a),
	  jas_seq2d_height(a), jas_seq2d_rowstep(a), tsfb->numlvls - 1) : 0;
}

Project: jasper

int jpc_tsfb_analyze2(jpc_tsfb_t *tsfb, int *a, int xstart, int ystart,
  int width, int height, int stride, int numlvls)
{
	if (width > 0 && height > 0) {
		if ((*tsfb->qmfb->analyze)(a, xstart, ystart, width, height, stride))
			return -1;
		if (numlvls > 0) {
			if (jpc_tsfb_analyze2(tsfb, a, JPC_CEILDIVPOW2(xstart,
			  1), JPC_CEILDIVPOW2(ystart, 1), JPC_CEILDIVPOW2(
			  xstart + width, 1) - JPC_CEILDIVPOW2(xstart, 1),
			  JPC_CEILDIVPOW2(ystart + height, 1) -
			  JPC_CEILDIVPOW2(ystart, 1), stride, numlvls - 1)) {
				return -1;
			}
		}
	}
	return 0;
}

Project: jasper

void jpc_tsfb_destroy(jpc_tsfb_t *tsfb)
{
	free(tsfb);
}

Project: jasper

int jpc_tsfb_getbands(jpc_tsfb_t *tsfb, uint_fast32_t xstart,
  uint_fast32_t ystart, uint_fast32_t xend, uint_fast32_t yend,
  jpc_tsfb_band_t *bands)
{
	jpc_tsfb_band_t *band;

	band = bands;
	if (tsfb->numlvls > 0) {
		jpc_tsfb_getbands2(tsfb, xstart, ystart, xstart, ystart, xend, yend,
		  &band, tsfb->numlvls);
	} else {

		band->xstart = xstart;
		band->ystart = ystart;
		band->xend = xend;
		band->yend = yend;
		band->locxstart = xstart;
		band->locystart = ystart;
		band->locxend = band->locxstart + band->xend - band->xstart;
		band->locyend = band->locystart + band->yend - band->ystart;
		band->orient = JPC_TSFB_LL;
		band->synenergywt = JPC_FIX_ONE;
		++band;
	}
	return band - bands;
}

Project: jasper

int jpc_tsfb_synthesize2(jpc_tsfb_t *tsfb, int *a, int xstart, int ystart,
  int width, int height, int stride, int numlvls)
{
	if (numlvls > 0) {
		if (jpc_tsfb_synthesize2(tsfb, a, JPC_CEILDIVPOW2(xstart, 1),
		  JPC_CEILDIVPOW2(ystart, 1), JPC_CEILDIVPOW2(xstart + width,
		  1) - JPC_CEILDIVPOW2(xstart, 1), JPC_CEILDIVPOW2(ystart +
		  height, 1) - JPC_CEILDIVPOW2(ystart, 1), stride, numlvls -
		  1)) {
			return -1;
		}
	}
	if (width > 0 && height > 0) {
		if ((*tsfb->qmfb->synthesize)(a, xstart, ystart, width, height, stride)) {
			return -1;
		}
	}
	return 0;
}