about summary refs log tree commit diff
path: root/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/jpeg2000/libjasper/jp2/jp2_dec.c')
-rw-r--r--converter/other/jpeg2000/libjasper/jp2/jp2_dec.c1032
1 files changed, 525 insertions, 507 deletions
diff --git a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
index 91ce6c51..a9463a57 100644
--- a/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
+++ b/converter/other/jpeg2000/libjasper/jp2/jp2_dec.c
@@ -110,16 +110,6 @@
  * __END_OF_JASPER_LICENSE__
  */
 
-/*
- * JP2 Library
- *
- * $Id$
- */
-
-/******************************************************************************\
-* Includes.
-\******************************************************************************/
-
 #include "jasper/jas_image.h"
 #include "jasper/jas_stream.h"
 #include "jasper/jas_math.h"
@@ -130,520 +120,548 @@
 #include "jp2_cod.h"
 #include "jp2_dec.h"
 
-#define	JP2_VALIDATELEN	(JAS_MIN(JP2_JP_LEN + 16, JAS_STREAM_MAXPUTBACK))
-
-static jp2_dec_t *jp2_dec_create(void);
-static void jp2_dec_destroy(jp2_dec_t *dec);
-static int jp2_getcs(jp2_colr_t *colr);
-static int jp2_getct(int colorspace, int type, int assoc);
-static int fromiccpcs(int cs);
-
-/******************************************************************************\
-* Functions.
-\******************************************************************************/
-
-jas_image_t *jp2_decode(jas_stream_t *in, char *optstr)
-{
-	jp2_box_t *box;
-	int found;
-	jas_image_t *image;
-	jp2_dec_t *dec;
-	bool samedtype;
-	int dtype;
-	int i;
-	jp2_cmap_t *cmapd;
-	jp2_pclr_t *pclrd;
-	jp2_cdef_t *cdefd;
-	int channo;
-	int newcmptno;
-	int_fast32_t *lutents;
-	jp2_cmapent_t *cmapent;
-	unsigned char *iccp;
-	int cs;
-
-	dec = 0;
-	box = 0;
-	image = 0;
-
-	if (!(dec = jp2_dec_create())) {
-		goto error;
-	}
-
-	/* Get the first box.  This should be a JP box. */
-	if (!(box = jp2_box_get(in))) {
-		jas_eprintf("error: cannot get box\n");
-		goto error;
-	}
-	if (box->type != JP2_BOX_JP) {
-		jas_eprintf("error: expecting signature box\n");
-		goto error;
-	}
-	if (box->data.jp.magic != JP2_JP_MAGIC) {
-		jas_eprintf("incorrect magic number\n");
-		goto error;
-	}
-	jp2_box_destroy(box);
-	box = 0;
-
-	/* Get the second box.  This should be a FTYP box. */
-	if (!(box = jp2_box_get(in))) {
-		goto error;
-	}
-	if (box->type != JP2_BOX_FTYP) {
-		jas_eprintf("expecting file type box\n");
-		goto error;
-	}
-	jp2_box_destroy(box);
-	box = 0;
-
-	/* Get more boxes... */
-	found = 0;
-	while ((box = jp2_box_get(in))) {
-		if (jas_getdbglevel() >= 1) {
-			fprintf(stderr, "box type %s\n", box->info->name);
-		}
-		switch (box->type) {
-		case JP2_BOX_JP2C:
-			found = 1;
-			break;
-		case JP2_BOX_IHDR:
-			if (!dec->ihdr) {
-				dec->ihdr = box;
-				box = 0;
-			}
-			break;
-		case JP2_BOX_BPCC:
-			if (!dec->bpcc) {
-				dec->bpcc = box;
-				box = 0;
-			}
-			break;
-		case JP2_BOX_CDEF:
-			if (!dec->cdef) {
-				dec->cdef = box;
-				box = 0;
-			}
-			break;
-		case JP2_BOX_PCLR:
-			if (!dec->pclr) {
-				dec->pclr = box;
-				box = 0;
-			}
-			break;
-		case JP2_BOX_CMAP:
-			if (!dec->cmap) {
-				dec->cmap = box;
-				box = 0;
-			}
-			break;
-		case JP2_BOX_COLR:
-			if (!dec->colr) {
-				dec->colr = box;
-				box = 0;
-			}
-			break;
-		}
-		if (box) {
-			jp2_box_destroy(box);
-			box = 0;
-		}
-		if (found) {
-			break;
-		}
-	}
-
-	if (!found) {
-		jas_eprintf("error: no code stream found\n");
-		goto error;
-	}
-
-	if (!(dec->image = jpc_decode(in, optstr))) {
-		jas_eprintf("error: cannot decode code stream\n");
-		goto error;
-	}
-
-	/* An IHDR box must be present. */
-	if (!dec->ihdr) {
-		jas_eprintf("error: missing IHDR box\n");
-		goto error;
-	}
-
-	/* Does the number of components indicated in the IHDR box match
-	  the value specified in the code stream? */
-	if (dec->ihdr->data.ihdr.numcmpts != jas_image_numcmpts(dec->image)) {
-		jas_eprintf("warning: number of components mismatch\n");
-	}
-
-	/* At least one component must be present. */
-	if (!jas_image_numcmpts(dec->image)) {
-		jas_eprintf("error: no components\n");
-		goto error;
-	}
-
-	/* Determine if all components have the same data type. */
-	samedtype = true;
-	dtype = jas_image_cmptdtype(dec->image, 0);
-	for (i = 1; i < jas_image_numcmpts(dec->image); ++i) {
-		if (jas_image_cmptdtype(dec->image, i) != dtype) {
-			samedtype = false;
-			break;
-		}
-	}
-
-	/* Is the component data type indicated in the IHDR box consistent
-	  with the data in the code stream? */
-	if ((samedtype && dec->ihdr->data.ihdr.bpc != JP2_DTYPETOBPC(dtype)) ||
-	  (!samedtype && dec->ihdr->data.ihdr.bpc != JP2_IHDR_BPCNULL)) {
-		jas_eprintf("warning: component data type mismatch\n");
-	}
-
-	/* Can we handle the compression type? */
-	if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
-		jas_eprintf("error: not capable of this compression type\n");
-		goto error;
-	}
-
-	if (dec->bpcc) {
-		/* Is the number of components indicated in the BPCC box
-		  consistent with the code stream data? */
-		if (dec->bpcc->data.bpcc.numcmpts != jas_image_numcmpts(
-		  dec->image)) {
-			jas_eprintf("warning: number of components mismatch\n");
-		}
-		/* Is the component data type information indicated in the BPCC
-		  box consistent with the code stream data? */
-		if (!samedtype) {
-			for (i = 0; i < jas_image_numcmpts(dec->image); ++i) {
-				if (jas_image_cmptdtype(dec->image, i) != JP2_BPCTODTYPE(dec->bpcc->data.bpcc.bpcs[i])) {
-					jas_eprintf("warning: component data type mismatch\n");
-				}
-			}
-		} else {
-			jas_eprintf("warning: superfluous BPCC box\n");
-		}
-	}
-
-	/* A COLR box must be present. */
-	if (!dec->colr) {
-		jas_eprintf("error: no COLR box\n");
-		goto error;
-	}
-
-	switch (dec->colr->data.colr.method) {
-	case JP2_COLR_ENUM:
-		jas_image_setcolorspace(dec->image, jp2_getcs(&dec->colr->data.colr));
-		break;
-	case JP2_COLR_ICC:
-		if (dec->colr->data.colr.iccplen < 128) {
-			abort();
-		}
-		iccp = dec->colr->data.colr.iccp;
-		cs = (iccp[16] << 24) | (iccp[17] << 16) | (iccp[18] << 8) |
-		  iccp[19];
-        if (jas_getdbglevel() > 1)
-            jas_eprintf("ICC Profile CS %08x\n", cs);
-		jas_image_setcolorspace(dec->image, fromiccpcs(cs));
-		break;
-	}
-
-	/* If a CMAP box is present, a PCLR box must also be present. */
-	if (dec->cmap && !dec->pclr) {
-		jas_eprintf("warning: missing PCLR box or superfluous CMAP box\n");
-		jp2_box_destroy(dec->cmap);
-		dec->cmap = 0;
-	}
-
-	/* If a CMAP box is not present, a PCLR box must not be present. */
-	if (!dec->cmap && dec->pclr) {
-		jas_eprintf("warning: missing CMAP box or superfluous PCLR box\n");
-		jp2_box_destroy(dec->pclr);
-		dec->pclr = 0;
-	}
-
-	/* Determine the number of channels (which is essentially the number
-	  of components after any palette mappings have been applied). */
-	dec->numchans = dec->cmap ? dec->cmap->data.cmap.numchans : jas_image_numcmpts(dec->image);
-
-	/* Perform a basic sanity check on the CMAP box if present. */
-	if (dec->cmap) {
-		for (i = 0; i < dec->numchans; ++i) {
-			/* Is the component number reasonable? */
-			if (dec->cmap->data.cmap.ents[i].cmptno >= jas_image_numcmpts(dec->image)) {
-				jas_eprintf("error: invalid component number in CMAP box\n");
-				goto error;
-			}
-			/* Is the LUT index reasonable? */
-			if (dec->cmap->data.cmap.ents[i].pcol >= dec->pclr->data.pclr.numchans) {
-				jas_eprintf("error: invalid CMAP LUT index\n");
-				goto error;
-			}
-		}
-	}
-
-	/* Allocate space for the channel-number to component-number LUT. */
-	if (!(dec->chantocmptlut = jas_malloc(dec->numchans * sizeof(uint_fast16_t)))) {
-		jas_eprintf("error: no memory\n");
-		goto error;
-	}
-
-	if (!dec->cmap) {
-		for (i = 0; i < dec->numchans; ++i) {
-			dec->chantocmptlut[i] = i;
-		}
-	} else {
-		cmapd = &dec->cmap->data.cmap;
-		pclrd = &dec->pclr->data.pclr;
-		cdefd = &dec->cdef->data.cdef;
-		for (channo = 0; channo < cmapd->numchans; ++channo) {
-			cmapent = &cmapd->ents[channo];
-			if (cmapent->map == JP2_CMAP_DIRECT) {
-				dec->chantocmptlut[channo] = channo;
-			} else if (cmapent->map == JP2_CMAP_PALETTE) {
-				lutents = jas_malloc(pclrd->numlutents * sizeof(int_fast32_t));
-				for (i = 0; i < pclrd->numlutents; ++i) {
-					lutents[i] = pclrd->lutdata[cmapent->pcol + i * pclrd->numchans];
-				}
-				newcmptno = jas_image_numcmpts(dec->image);
-				jas_image_depalettize(dec->image, cmapent->cmptno, pclrd->numlutents, lutents, JP2_BPCTODTYPE(pclrd->bpc[cmapent->pcol]), newcmptno);
-				dec->chantocmptlut[channo] = newcmptno;
-				jas_free(lutents);
-#if 0
-				if (dec->cdef) {
-					cdefent = jp2_cdef_lookup(cdefd, channo);
-					if (!cdefent) {
-						abort();
-					}
-				jas_image_setcmpttype(dec->image, newcmptno, jp2_getct(jas_image_colorspace(dec->image), cdefent->type, cdefent->assoc));
-				} else {
-				jas_image_setcmpttype(dec->image, newcmptno, jp2_getct(jas_image_colorspace(dec->image), 0, channo + 1));
-				}
-#endif
-			}
-		}
-	}
-
-	/* Mark all components as being of unknown type. */
-
-	for (i = 0; i < jas_image_numcmpts(dec->image); ++i) {
-		jas_image_setcmpttype(dec->image, i, JAS_IMAGE_CT_UNKNOWN);
-	}
-
-	/* Determine the type of each component. */
-	if (dec->cdef) {
-		for (i = 0; i < dec->numchans; ++i) {
-			jas_image_setcmpttype(dec->image,
-			  dec->chantocmptlut[dec->cdef->data.cdef.ents[i].channo],
-			  jp2_getct(jas_image_colorspace(dec->image),
-			  dec->cdef->data.cdef.ents[i].type, dec->cdef->data.cdef.ents[i].assoc));
-		}
-	} else {
-		for (i = 0; i < dec->numchans; ++i) {
-			jas_image_setcmpttype(dec->image, dec->chantocmptlut[i],
-			  jp2_getct(jas_image_colorspace(dec->image), 0, i + 1));
-		}
-	}
-
-	/* Delete any components that are not of interest. */
-	for (i = jas_image_numcmpts(dec->image) - 1; i >= 0; --i) {
-		if (jas_image_cmpttype(dec->image, i) == JAS_IMAGE_CT_UNKNOWN) {
-			jas_image_delcmpt(dec->image, i);
-		}
-	}
-
-	/* Ensure that some components survived. */
-	if (!jas_image_numcmpts(dec->image)) {
-		jas_eprintf("error: no components\n");
-		goto error;
-	}
-
-	/* Prevent the image from being destroyed later. */
-	image = dec->image;
-	dec->image = 0;
-
-	jp2_dec_destroy(dec);
-
-	return image;
+#define JP2_VALIDATELEN (JAS_MIN(JP2_JP_LEN + 16, JAS_STREAM_MAXPUTBACK))
 
-error:
-	if (box) {
-		jp2_box_destroy(box);
-	}
-	if (dec) {
-		jp2_dec_destroy(dec);
-	}
-	return 0;
+
+
+static jp2_dec_t *
+jp2_dec_create(void) {
+
+    jp2_dec_t *dec;
+
+    dec = jas_malloc(sizeof(jp2_dec_t));
+    if (dec) {
+        dec->ihdr = 0;
+        dec->bpcc = 0;
+        dec->cdef = 0;
+        dec->pclr = 0;
+        dec->image = 0;
+        dec->chantocmptlut = 0;
+        dec->cmap = 0;
+        dec->colr = 0;
+    }
+    return dec;
 }
 
-int jp2_validate(jas_stream_t *in)
-{
-	char buf[JP2_VALIDATELEN];
-	int i;
-	int n;
-
-	assert(JAS_STREAM_MAXPUTBACK >= JP2_VALIDATELEN);
-
-	/* Read the validation data (i.e., the data used for detecting
-	  the format). */
-	if ((n = jas_stream_read(in, buf, JP2_VALIDATELEN)) < 0) {
-		return -1;
-	}
-
-	/* Put the validation data back onto the stream, so that the
-	  stream position will not be changed. */
-	for (i = n - 1; i >= 0; --i) {
-		if (jas_stream_ungetc(in, buf[i]) == EOF) {
-			return -1;
-		}
-	}
-
-	/* Did we read enough data? */
-	if (n < JP2_VALIDATELEN) {
-		return -1;
-	}
-
-	/* Is the box type correct? */
-	if (((buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]) !=
-	  JP2_BOX_JP)
-	{
-		return -1;
-	}
-
-	return 0;
+
+
+static void
+jp2_dec_destroy(jp2_dec_t *dec) {
+
+    if (dec->ihdr)
+        jp2_box_destroy(dec->ihdr);
+
+    if (dec->bpcc)
+        jp2_box_destroy(dec->bpcc);
+
+    if (dec->cdef)
+        jp2_box_destroy(dec->cdef);
+
+    if (dec->pclr)
+        jp2_box_destroy(dec->pclr);
+
+    if (dec->image)
+        jas_image_destroy(dec->image);
+
+    if (dec->cmap)
+        jp2_box_destroy(dec->cmap);
+
+    if (dec->colr)
+        jp2_box_destroy(dec->colr);
+
+    if (dec->chantocmptlut)
+        jas_free(dec->chantocmptlut);
+
+    jas_free(dec);
 }
 
-static jp2_dec_t *jp2_dec_create(void)
-{
-	jp2_dec_t *dec;
-
-	if (!(dec = jas_malloc(sizeof(jp2_dec_t)))) {
-		return 0;
-	}
-	dec->ihdr = 0;
-	dec->bpcc = 0;
-	dec->cdef = 0;
-	dec->pclr = 0;
-	dec->image = 0;
-	dec->chantocmptlut = 0;
-	dec->cmap = 0;
-	dec->colr = 0;
-	return dec;
+
+
+static int
+jp2_getct(int colorspace, int type, int assoc) {
+
+    if (type == 1 && assoc == 0)
+        return JAS_IMAGE_CT_OPACITY;
+
+    if (type == 0 && assoc >= 1 && assoc <= 65534) {
+        switch (colorspace) {
+        case JAS_IMAGE_CS_RGB:
+            switch (assoc) {
+            case JP2_CDEF_RGB_R:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R);
+                break;
+            case JP2_CDEF_RGB_G:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G);
+                break;
+            case JP2_CDEF_RGB_B:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B);
+                break;
+            }
+            break;
+        case JAS_IMAGE_CS_YCBCR:
+            switch (assoc) {
+            case JP2_CDEF_YCBCR_Y:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_Y);
+                break;
+            case JP2_CDEF_YCBCR_CB:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CB);
+                break;
+            case JP2_CDEF_YCBCR_CR:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CR);
+                break;
+            }
+            break;
+        case JAS_IMAGE_CS_GRAY:
+            switch (assoc) {
+            case JP2_CDEF_GRAY_Y:
+                return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y);
+                break;
+            }
+            break;
+#if 0
+        case JAS_IMAGE_CS_ICC:
+#endif
+        default:
+            return JAS_IMAGE_CT_COLOR(assoc - 1);
+            break;
+        }
+    }
+    return JAS_IMAGE_CT_UNKNOWN;
 }
 
-static void jp2_dec_destroy(jp2_dec_t *dec)
-{
-	if (dec->ihdr) {
-		jp2_box_destroy(dec->ihdr);
-	}
-	if (dec->bpcc) {
-		jp2_box_destroy(dec->bpcc);
-	}
-	if (dec->cdef) {
-		jp2_box_destroy(dec->cdef);
-	}
-	if (dec->pclr) {
-		jp2_box_destroy(dec->pclr);
-	}
-	if (dec->image) {
-		jas_image_destroy(dec->image);
-	}
-	if (dec->cmap) {
-		jp2_box_destroy(dec->cmap);
-	}
-	if (dec->colr) {
-		jp2_box_destroy(dec->colr);
-	}
-	if (dec->chantocmptlut) {
-		jas_free(dec->chantocmptlut);
-	}
-	jas_free(dec);
+
+
+static int
+jp2_getcs(jp2_colr_t *colr) {
+
+    if (colr->method == JP2_COLR_ENUM) {
+        switch (colr->csid) {
+        case JP2_COLR_SRGB:
+            return JAS_IMAGE_CS_RGB;
+            break;
+        case JP2_COLR_SYCC:
+            return JAS_IMAGE_CS_YCBCR;
+            break;
+        case JP2_COLR_SGRAY:
+            return JAS_IMAGE_CS_GRAY;
+            break;
+        }
+    }
+    return JAS_IMAGE_CS_UNKNOWN;
 }
 
 
 
+static int
+fromiccpcs(int cs) {
+    
+    switch (cs) {
+    case ICC_CS_RGB:
+        return JAS_IMAGE_CS_RGB;
+        break;
+    case ICC_CS_YCBCR:
+        return JAS_IMAGE_CS_YCBCR;
+        break;
+    case ICC_CS_GRAY:
+        return JAS_IMAGE_CS_GRAY;
+        break;
+    }
+    return JAS_IMAGE_CS_UNKNOWN;
+}
 
 
 
-static int jp2_getct(int colorspace, int type, int assoc)
-{
-	if (type == 1 && assoc == 0) {
-		return JAS_IMAGE_CT_OPACITY;
-	}
-	if (type == 0 && assoc >= 1 && assoc <= 65534) {
-		switch (colorspace) {
-		case JAS_IMAGE_CS_RGB:
-			switch (assoc) {
-			case JP2_CDEF_RGB_R:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R);
-				break;
-			case JP2_CDEF_RGB_G:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G);
-				break;
-			case JP2_CDEF_RGB_B:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B);
-				break;
-			}
-			break;
-		case JAS_IMAGE_CS_YCBCR:
-			switch (assoc) {
-			case JP2_CDEF_YCBCR_Y:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_Y);
-				break;
-			case JP2_CDEF_YCBCR_CB:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CB);
-				break;
-			case JP2_CDEF_YCBCR_CR:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_YCBCR_CR);
-				break;
-			}
-			break;
-		case JAS_IMAGE_CS_GRAY:
-			switch (assoc) {
-			case JP2_CDEF_GRAY_Y:
-				return JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_GRAY_Y);
-				break;
-			}
-			break;
+jas_image_t *
+jp2_decode(jas_stream_t *in, char *optstr) {
+
+    jp2_box_t *box;
+    int found;
+    jas_image_t *image;
+    jp2_dec_t *dec;
+    bool samedtype;
+    int dtype;
+    int i;
+    jp2_cmap_t *cmapd;
+    jp2_pclr_t *pclrd;
+    int channo;
+    int newcmptno;
+    int_fast32_t *lutents;
+    jp2_cmapent_t *cmapent;
+    unsigned char *iccp;
+    int cs;
+
+    dec = 0;
+    box = 0;
+    image = 0;
+
+    if (!(dec = jp2_dec_create())) {
+        goto error;
+    }
+
+    /* Get the first box.  This should be a JP box. */
+    if (!(box = jp2_box_get(in))) {
+        jas_eprintf("error: cannot get box\n");
+        goto error;
+    }
+    if (box->type != JP2_BOX_JP) {
+        jas_eprintf("error: expecting signature box\n");
+        goto error;
+    }
+    if (box->data.jp.magic != JP2_JP_MAGIC) {
+        jas_eprintf("incorrect magic number\n");
+        goto error;
+    }
+    jp2_box_destroy(box);
+    box = 0;
+
+    /* Get the second box.  This should be a FTYP box. */
+    if (!(box = jp2_box_get(in))) {
+        goto error;
+    }
+    if (box->type != JP2_BOX_FTYP) {
+        jas_eprintf("expecting file type box\n");
+        goto error;
+    }
+    jp2_box_destroy(box);
+    box = 0;
+
+    /* Get more boxes... */
+    found = 0;
+    while ((box = jp2_box_get(in))) {
+        if (jas_getdbglevel() >= 1) {
+            fprintf(stderr, "box type %s\n", box->info->name);
+        }
+        switch (box->type) {
+        case JP2_BOX_JP2C:
+            found = 1;
+            break;
+        case JP2_BOX_IHDR:
+            if (!dec->ihdr) {
+                dec->ihdr = box;
+                box = 0;
+            }
+            break;
+        case JP2_BOX_BPCC:
+            if (!dec->bpcc) {
+                dec->bpcc = box;
+                box = 0;
+            }
+            break;
+        case JP2_BOX_CDEF:
+            if (!dec->cdef) {
+                dec->cdef = box;
+                box = 0;
+            }
+            break;
+        case JP2_BOX_PCLR:
+            if (!dec->pclr) {
+                dec->pclr = box;
+                box = 0;
+            }
+            break;
+        case JP2_BOX_CMAP:
+            if (!dec->cmap) {
+                dec->cmap = box;
+                box = 0;
+            }
+            break;
+        case JP2_BOX_COLR:
+            if (!dec->colr) {
+                dec->colr = box;
+                box = 0;
+            }
+            break;
+        }
+        if (box) {
+            jp2_box_destroy(box);
+            box = 0;
+        }
+        if (found) {
+            break;
+        }
+    }
+
+    if (!found) {
+        jas_eprintf("error: no code stream found\n");
+        goto error;
+    }
+
+    if (!(dec->image = jpc_decode(in, optstr))) {
+        jas_eprintf("error: cannot decode code stream\n");
+        goto error;
+    }
+
+    /* An IHDR box must be present. */
+    if (!dec->ihdr) {
+        jas_eprintf("error: missing IHDR box\n");
+        goto error;
+    }
+
+    /* Does the number of components indicated in the IHDR box match
+      the value specified in the code stream? */
+    if (dec->ihdr->data.ihdr.numcmpts != jas_image_numcmpts(dec->image)) {
+        jas_eprintf("warning: number of components mismatch\n");
+    }
+
+    /* At least one component must be present. */
+    if (!jas_image_numcmpts(dec->image)) {
+        jas_eprintf("error: no components\n");
+        goto error;
+    }
+
+    /* Determine if all components have the same data type. */
+    samedtype = true;
+    dtype = jas_image_cmptdtype(dec->image, 0);
+    for (i = 1; i < jas_image_numcmpts(dec->image); ++i) {
+        if (jas_image_cmptdtype(dec->image, i) != dtype) {
+            samedtype = false;
+            break;
+        }
+    }
+
+    /* Is the component data type indicated in the IHDR box consistent
+      with the data in the code stream? */
+    if ((samedtype && dec->ihdr->data.ihdr.bpc != JP2_DTYPETOBPC(dtype)) ||
+      (!samedtype && dec->ihdr->data.ihdr.bpc != JP2_IHDR_BPCNULL)) {
+        jas_eprintf("warning: component data type mismatch\n");
+    }
+
+    /* Can we handle the compression type? */
+    if (dec->ihdr->data.ihdr.comptype != JP2_IHDR_COMPTYPE) {
+        jas_eprintf("error: not capable of this compression type\n");
+        goto error;
+    }
+
+    if (dec->bpcc) {
+        /* Is the number of components indicated in the BPCC box
+          consistent with the code stream data? */
+        if (dec->bpcc->data.bpcc.numcmpts != jas_image_numcmpts(
+          dec->image)) {
+            jas_eprintf("warning: number of components mismatch\n");
+        }
+        /* Is the component data type information indicated in the BPCC
+          box consistent with the code stream data? */
+        if (!samedtype) {
+            for (i = 0; i < jas_image_numcmpts(dec->image); ++i) {
+                if (jas_image_cmptdtype(dec->image, i) !=
+                    JP2_BPCTODTYPE(dec->bpcc->data.bpcc.bpcs[i])) {
+                    jas_eprintf("warning: component data type mismatch\n");
+                }
+            }
+        } else {
+            jas_eprintf("warning: superfluous BPCC box\n");
+        }
+    }
+
+    /* A COLR box must be present. */
+    if (!dec->colr) {
+        jas_eprintf("error: no COLR box\n");
+        goto error;
+    }
+
+    switch (dec->colr->data.colr.method) {
+    case JP2_COLR_ENUM:
+        jas_image_setcolorspace(dec->image, jp2_getcs(&dec->colr->data.colr));
+        break;
+    case JP2_COLR_ICC:
+        if (dec->colr->data.colr.iccplen < 128) {
+            abort();
+        }
+        iccp = dec->colr->data.colr.iccp;
+        cs = (iccp[16] << 24) | (iccp[17] << 16) | (iccp[18] << 8) |
+          iccp[19];
+        if (jas_getdbglevel() > 1)
+            jas_eprintf("ICC Profile CS %08x\n", cs);
+        jas_image_setcolorspace(dec->image, fromiccpcs(cs));
+        break;
+    }
+
+    /* If a CMAP box is present, a PCLR box must also be present. */
+    if (dec->cmap && !dec->pclr) {
+        jas_eprintf("warning: missing PCLR box or superfluous CMAP box\n");
+        jp2_box_destroy(dec->cmap);
+        dec->cmap = 0;
+    }
+
+    /* If a CMAP box is not present, a PCLR box must not be present. */
+    if (!dec->cmap && dec->pclr) {
+        jas_eprintf("warning: missing CMAP box or superfluous PCLR box\n");
+        jp2_box_destroy(dec->pclr);
+        dec->pclr = 0;
+    }
+
+    /* Determine the number of channels (which is essentially the number
+      of components after any palette mappings have been applied). */
+    dec->numchans = dec->cmap ?
+        dec->cmap->data.cmap.numchans : 
+        jas_image_numcmpts(dec->image);
+
+    /* Perform a basic sanity check on the CMAP box if present. */
+    if (dec->cmap) {
+        for (i = 0; i < dec->numchans; ++i) {
+            /* Is the component number reasonable? */
+            if (dec->cmap->data.cmap.ents[i].cmptno >=
+                jas_image_numcmpts(dec->image)) {
+                jas_eprintf("error: invalid component number in CMAP box\n");
+                goto error;
+            }
+            /* Is the LUT index reasonable? */
+            if (dec->cmap->data.cmap.ents[i].pcol >=
+                dec->pclr->data.pclr.numchans) {
+                jas_eprintf("error: invalid CMAP LUT index\n");
+                goto error;
+            }
+        }
+    }
+
+    /* Allocate space for the channel-number to component-number LUT. */
+    dec->chantocmptlut = jas_malloc(dec->numchans * sizeof(uint_fast16_t));
+    if (!dec->chantocmptlut) {
+        jas_eprintf("error: no memory\n");
+        goto error;
+    }
+
+    if (!dec->cmap) {
+        for (i = 0; i < dec->numchans; ++i) {
+            dec->chantocmptlut[i] = i;
+        }
+    } else {
+        cmapd = &dec->cmap->data.cmap;
+        pclrd = &dec->pclr->data.pclr;
+        for (channo = 0; channo < cmapd->numchans; ++channo) {
+            cmapent = &cmapd->ents[channo];
+            if (cmapent->map == JP2_CMAP_DIRECT) {
+                dec->chantocmptlut[channo] = channo;
+            } else if (cmapent->map == JP2_CMAP_PALETTE) {
+                lutents = jas_malloc(pclrd->numlutents * sizeof(int_fast32_t));
+                for (i = 0; i < pclrd->numlutents; ++i) {
+                    lutents[i] =
+                        pclrd->lutdata[cmapent->pcol + i * pclrd->numchans];
+                }
+                newcmptno = jas_image_numcmpts(dec->image);
+                jas_image_depalettize(
+                    dec->image, cmapent->cmptno, pclrd->numlutents, lutents,
+                    JP2_BPCTODTYPE(pclrd->bpc[cmapent->pcol]), newcmptno);
+                dec->chantocmptlut[channo] = newcmptno;
+                jas_free(lutents);
 #if 0
-		case JAS_IMAGE_CS_ICC:
+                if (dec->cdef) {
+                    jp2_cdef_t * const cdefd = &dec->cdef->data.cdef;
+                    cdefent = jp2_cdef_lookup(cdefd, channo);
+                    if (!cdefent) {
+                        abort();
+                    }
+                jas_image_setcmpttype(
+                    dec->image, newcmptno,
+                    jp2_getct(jas_image_colorspace(dec->image),
+                              cdefent->type, cdefent->assoc));
+                } else {
+                    jas_image_setcmpttype(
+                        dec->image, newcmptno,
+                        jp2_getct(jas_image_colorspace(dec->image),
+                                  0,
+                                  channo + 1));
+                }
 #endif
-		default:
-			return JAS_IMAGE_CT_COLOR(assoc - 1);
-			break;
-		}
-	}
-	return JAS_IMAGE_CT_UNKNOWN;
-}
+            }
+        }
+    }
+
+    /* Mark all components as being of unknown type. */
+
+    for (i = 0; i < jas_image_numcmpts(dec->image); ++i) {
+        jas_image_setcmpttype(dec->image, i, JAS_IMAGE_CT_UNKNOWN);
+    }
+
+    /* Determine the type of each component. */
+    if (dec->cdef) {
+        unsigned int i;
+        for (i = 0; i < dec->numchans; ++i) {
+            jas_image_setcmpttype(
+                dec->image,
+                dec->chantocmptlut[dec->cdef->data.cdef.ents[i].channo],
+                jp2_getct(jas_image_colorspace(dec->image),
+                          dec->cdef->data.cdef.ents[i].type,
+                          dec->cdef->data.cdef.ents[i].assoc));
+        }
+    } else {
+        unsigned int i;
+        for (i = 0; i < dec->numchans; ++i) {
+            jas_image_setcmpttype(dec->image, dec->chantocmptlut[i],
+              jp2_getct(jas_image_colorspace(dec->image), 0, i + 1));
+        }
+    }
+
+    /* Delete any components that are not of interest. */
+    for (i = jas_image_numcmpts(dec->image) - 1; i >= 0; --i) {
+        if (jas_image_cmpttype(dec->image, i) == JAS_IMAGE_CT_UNKNOWN) {
+            jas_image_delcmpt(dec->image, i);
+        }
+    }
+
+    /* Ensure that some components survived. */
+    if (!jas_image_numcmpts(dec->image)) {
+        jas_eprintf("error: no components\n");
+        goto error;
+    }
+
+    /* Prevent the image from being destroyed later. */
+    image = dec->image;
+    dec->image = 0;
+
+    jp2_dec_destroy(dec);
+
+    return image;
 
-static int jp2_getcs(jp2_colr_t *colr)
-{
-	if (colr->method == JP2_COLR_ENUM) {
-		switch (colr->csid) {
-		case JP2_COLR_SRGB:
-			return JAS_IMAGE_CS_RGB;
-			break;
-		case JP2_COLR_SYCC:
-			return JAS_IMAGE_CS_YCBCR;
-			break;
-		case JP2_COLR_SGRAY:
-			return JAS_IMAGE_CS_GRAY;
-			break;
-		}
-	}
-	return JAS_IMAGE_CS_UNKNOWN;
+error:
+    if (box) {
+        jp2_box_destroy(box);
+    }
+    if (dec) {
+        jp2_dec_destroy(dec);
+    }
+    return 0;
 }
 
-static int fromiccpcs(int cs)
-{
-	switch (cs) {
-	case ICC_CS_RGB:
-		return JAS_IMAGE_CS_RGB;
-		break;
-	case ICC_CS_YCBCR:
-		return JAS_IMAGE_CS_YCBCR;
-		break;
-	case ICC_CS_GRAY:
-		return JAS_IMAGE_CS_GRAY;
-		break;
-	}
-	return JAS_IMAGE_CS_UNKNOWN;
+
+
+int
+jp2_validate(jas_stream_t *in) {
+
+    char buf[JP2_VALIDATELEN];
+    int i;
+    int n;
+
+    assert(JAS_STREAM_MAXPUTBACK >= JP2_VALIDATELEN);
+
+    /* Read the validation data (i.e., the data used for detecting
+      the format). */
+    if ((n = jas_stream_read(in, buf, JP2_VALIDATELEN)) < 0) {
+        return -1;
+    }
+
+    /* Put the validation data back onto the stream, so that the
+      stream position will not be changed. */
+    for (i = n - 1; i >= 0; --i) {
+        if (jas_stream_ungetc(in, buf[i]) == EOF) {
+            return -1;
+        }
+    }
+
+    /* Did we read enough data? */
+    if (n < JP2_VALIDATELEN) {
+        return -1;
+    }
+
+    /* Is the box type correct? */
+    if (((buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]) !=
+      JP2_BOX_JP)
+    {
+        return -1;
+    }
+
+    return 0;
 }
+
+
+