Index: Branch_1-20-Viewer/indra/llimagej2coj/llimagej2coj.cpp
===================================================================
--- Branch_1-20-Viewer.orig/indra/llimagej2coj/llimagej2coj.cpp	2008-05-15 00:57:04.000000000 +0200
+++ Branch_1-20-Viewer/indra/llimagej2coj/llimagej2coj.cpp	2008-05-15 01:03:03.000000000 +0200
@@ -134,9 +134,15 @@
 	/* open a byte stream */
 	cio = opj_cio_open((opj_common_ptr)dinfo, base.getData(), base.getDataSize());
 
-	/* decode the stream and fill the image structure */
-	image = opj_decode(dinfo, cio);
 
+	/* decode the stream and fill the image structure, also fill in an additional
+	   structure to get the decoding result. This structure is a bit unusual in that
+	   it is not received through opj, but still has some dynamically allocated fields
+	   that need to be cleared up at the end by calling a destroy function. */
+	opj_codestream_info_t cinfo;
+	memset(&cinfo, 0, sizeof(opj_codestream_info_t));
+	image = opj_decode_with_info(dinfo, cio, &cinfo);
+	
 	/* close the byte stream */
 	opj_cio_close(cio);
 
@@ -146,30 +152,58 @@
 		opj_destroy_decompress(dinfo);
 	}
 
-	// The image decode failed if the return was NULL or the component
-	// count was zero.  The latter is just a sanity check before we
-	// dereference the array.
+	/* The image decode failed if the return was NULL or the component
+	   count was zero.  The latter is just a sanity check before we
+	   dereference the array. */
 	if(!image || !image->numcomps)
 	{
 		fprintf(stderr, "ERROR -> decodeImpl: failed to decode image!\n");
 		if (image)
+		{
+			opj_destroy_cstr_info(&cinfo);
 			opj_image_destroy(image);
+		}
 
 		return TRUE; // done
 	}
 
 	// sometimes we get bad data out of the cache - check to see if the decode succeeded
-	for (S32 i = 0; i < image->numcomps; i++)
-	{
-		if (image->comps[i].factor != base.getRawDiscardLevel())
+	int decompdifference = 0;
+	if (cinfo.numdecompos) // sanity
+	{	
+		for (int comp = 0; comp < image->numcomps; comp++)
+		{	/* get maximum decomposition level difference, first field is from the COD header and the second
+			   is what is actually met in the codestream, NB: if everything was ok, this calculation will
+			   return what was set in the cp_reduce value! */
+			decompdifference = std::max(decompdifference, cinfo.numdecompos[comp] - image->comps[comp].resno_decoded);
+		}
+		if (decompdifference < 0) // sanity
 		{
-			// if we didn't get the discard level we're expecting, fail
-			opj_image_destroy(image);
-			base.mDecoding = FALSE;
-			return TRUE;
+			decompdifference = 0;
 		}
 	}
+
+	/* if OpenJPEG failed to decode all requested decomposition levels 
+	   the difference will be greater than this level */
+	if (decompdifference > base.getRawDiscardLevel())
+	{
+		llwarns << "not enough data for requested discard level, setting mDecoding to FALSE, difference: " << (decompdifference - base.getRawDiscardLevel()) << llendl;
+		opj_destroy_cstr_info(&cinfo);
+		opj_image_destroy(image);
+			
+		base.mDecoding = FALSE;
+		return TRUE;
+	}
 	
+	if(image->numcomps <= first_channel)
+	{
+		// sanity
+		llwarns << "trying to decode more channels than are present in image: numcomps: " << image->numcomps << " first_channel: " << first_channel << llendl;
+		opj_destroy_cstr_info(&cinfo);
+		opj_image_destroy(image);			
+		return TRUE;
+	}
+
 	// Copy image data into our raw image format (instead of the separate channel format
 
 	S32 img_components = image->numcomps;
@@ -191,6 +225,7 @@
 	raw_image.resize(width, height, channels);
 	U8 *rawp = raw_image.getData();
 
+
 	// first_channel is what channel to start copying from
 	// dest is what channel to copy to.  first_channel comes from the
 	// argument, dest always starts writing at channel zero.
@@ -212,13 +247,15 @@
 		else // Some rare OpenJPEG versions have this bug.
 		{
 			fprintf(stderr, "ERROR -> decodeImpl: failed to decode image! (NULL comp data - OpenJPEG bug)\n");
+			opj_destroy_cstr_info(&cinfo);
 			opj_image_destroy(image);
 
 			return TRUE; // done
 		}
 	}
 
-	/* free image data structure */
+	/* free opj data structures */
+	opj_destroy_cstr_info(&cinfo);
 	opj_image_destroy(image);
 
 	return TRUE; // done
