+
+ /* Imct -> no need for other values, take the first, type is double with decorrelation x0000 1101 0000 0000*/
+ opj_read_bytes(p_header_data,&l_tmp,2); /* Imct */
+ p_header_data += 2;
+
+ l_indix = l_tmp & 0xff;
+ l_mct_data = l_tcp->m_mct_records;
+
+ for (i=0;i<l_tcp->m_nb_mct_records;++i) {
+ if (l_mct_data->m_index == l_indix) {
+ break;
+ }
+ ++l_mct_data;
+ }
+
+ /* NOT FOUND */
+ if (i == l_tcp->m_nb_mct_records) {
+ if (l_tcp->m_nb_mct_records == l_tcp->m_nb_max_mct_records) {
+ l_tcp->m_nb_max_mct_records += J2K_MCT_DEFAULT_NB_RECORDS;
+
+ l_tcp->m_mct_records = (opj_mct_data_t*)opj_realloc(l_tcp->m_mct_records,l_tcp->m_nb_max_mct_records * sizeof(opj_mct_data_t));
+ if(! l_tcp->m_mct_records) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n");
+ return OPJ_FALSE;
+ }
+
+ l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records;
+ memset(l_mct_data ,0,(l_tcp->m_nb_max_mct_records - l_tcp->m_nb_mct_records) * sizeof(opj_mct_data_t));
+ }
+
+ l_mct_data = l_tcp->m_mct_records + l_tcp->m_nb_mct_records;
+ }
+
+ if (l_mct_data->m_data) {
+ opj_free(l_mct_data->m_data);
+ l_mct_data->m_data = 00;
+ }
+
+ l_mct_data->m_index = l_indix;
+ l_mct_data->m_array_type = (J2K_MCT_ARRAY_TYPE)((l_tmp >> 8) & 3);
+ l_mct_data->m_element_type = (J2K_MCT_ELEMENT_TYPE)((l_tmp >> 10) & 3);
+
+ opj_read_bytes(p_header_data,&l_tmp,2); /* Ymct */
+ p_header_data+=2;
+ if (l_tmp != 0) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple MCT markers\n");
+ return OPJ_TRUE;
+ }
+
+ p_header_size -= 6;
+
+ l_mct_data->m_data = (OPJ_BYTE*)opj_malloc(p_header_size);
+ if (! l_mct_data->m_data) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCT marker\n");
+ return OPJ_FALSE;
+ }
+ memcpy(l_mct_data->m_data,p_header_data,p_header_size);
+
+ l_mct_data->m_data_size = p_header_size;
+ ++l_tcp->m_nb_mct_records;
+
+ return OPJ_TRUE;
+}
+
+/**
+ * Reads a MCC marker (Multiple Component Collection)
+ *
+ * @param p_header_data the data contained in the MCC box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the MCC marker.
+ * @param p_manager the user event manager.
+*/
+opj_bool j2k_read_mcc ( opj_j2k_v2_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ struct opj_event_mgr * p_manager )
+{
+ OPJ_UINT32 i,j;
+ OPJ_UINT32 l_tmp;
+ OPJ_UINT32 l_indix;
+ opj_tcp_v2_t * l_tcp;
+ opj_simple_mcc_decorrelation_data_t * l_mcc_record;
+ opj_mct_data_t * l_mct_data;
+ OPJ_UINT32 l_nb_collections;
+ OPJ_UINT32 l_nb_comps;
+ OPJ_UINT32 l_nb_bytes_by_comp;
+
+
+ /* preconditions */
+ assert(p_header_data != 00);
+ assert(p_j2k != 00);
+ assert(p_manager != 00);
+
+ l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ?
+ &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] :
+ p_j2k->m_specific_param.m_decoder.m_default_tcp;
+
+ if (p_header_size < 2) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+
+ /* first marker */
+ opj_read_bytes(p_header_data,&l_tmp,2); /* Zmcc */
+ p_header_data += 2;
+ if (l_tmp != 0) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n");
+ return OPJ_TRUE;
+ }
+
+ if (p_header_size < 7) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+
+ opj_read_bytes(p_header_data,&l_indix,1); /* Imcc -> no need for other values, take the first */
+ ++p_header_data;
+
+ l_mcc_record = l_tcp->m_mcc_records;
+
+ for(i=0;i<l_tcp->m_nb_mcc_records;++i) {
+ if (l_mcc_record->m_index == l_indix) {
+ break;
+ }
+ ++l_mcc_record;
+ }
+
+ /** NOT FOUND */
+ if (i == l_tcp->m_nb_mcc_records) {
+ if (l_tcp->m_nb_mcc_records == l_tcp->m_nb_max_mcc_records) {
+ l_tcp->m_nb_max_mcc_records += J2K_MCC_DEFAULT_NB_RECORDS;
+
+ l_tcp->m_mcc_records = (opj_simple_mcc_decorrelation_data_t*)
+ opj_realloc(l_tcp->m_mcc_records,l_tcp->m_nb_max_mcc_records * sizeof(opj_simple_mcc_decorrelation_data_t));
+ if (! l_tcp->m_mcc_records) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+ l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records;
+ memset(l_mcc_record,0,(l_tcp->m_nb_max_mcc_records-l_tcp->m_nb_mcc_records) * sizeof(opj_simple_mcc_decorrelation_data_t));
+ }
+ l_mcc_record = l_tcp->m_mcc_records + l_tcp->m_nb_mcc_records;
+ }
+ l_mcc_record->m_index = l_indix;
+
+ /* only one marker atm */
+ opj_read_bytes(p_header_data,&l_tmp,2); /* Ymcc */
+ p_header_data+=2;
+ if (l_tmp != 0) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple data spanning\n");
+ return OPJ_TRUE;
+ }
+
+ opj_read_bytes(p_header_data,&l_nb_collections,2); /* Qmcc -> number of collections -> 1 */
+ p_header_data+=2;
+
+ if (l_nb_collections > 1) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple collections\n");
+ return OPJ_TRUE;
+ }
+
+ p_header_size -= 7;
+
+ for (i=0;i<l_nb_collections;++i) {
+ if (p_header_size < 3) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+
+ opj_read_bytes(p_header_data,&l_tmp,1); /* Xmcci type of component transformation -> array based decorrelation */
+ ++p_header_data;
+
+ if (l_tmp != 1) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections other than array decorrelation\n");
+ return OPJ_TRUE;
+ }
+
+ opj_read_bytes(p_header_data,&l_nb_comps,2);
+
+ p_header_data+=2;
+ p_header_size-=3;
+
+ l_nb_bytes_by_comp = 1 + (l_nb_comps>>15);
+ l_mcc_record->m_nb_comps = l_nb_comps & 0x7fff;
+
+ if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2)) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+
+ p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 2);
+
+ for (j=0;j<l_mcc_record->m_nb_comps;++j) {
+ opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Cmccij Component offset*/
+ p_header_data+=l_nb_bytes_by_comp;
+
+ if (l_tmp != j) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n");
+ return OPJ_TRUE;
+ }
+ }
+
+ opj_read_bytes(p_header_data,&l_nb_comps,2);
+ p_header_data+=2;
+
+ l_nb_bytes_by_comp = 1 + (l_nb_comps>>15);
+ l_nb_comps &= 0x7fff;
+
+ if (l_nb_comps != l_mcc_record->m_nb_comps) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections without same number of indixes\n");
+ return OPJ_TRUE;
+ }
+
+ if (p_header_size < (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3)) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+
+ p_header_size -= (l_nb_bytes_by_comp * l_mcc_record->m_nb_comps + 3);
+
+ for (j=0;j<l_mcc_record->m_nb_comps;++j) {
+ opj_read_bytes(p_header_data,&l_tmp,l_nb_bytes_by_comp); /* Wmccij Component offset*/
+ p_header_data+=l_nb_bytes_by_comp;
+
+ if (l_tmp != j) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge collections with indix shuffle\n");
+ return OPJ_TRUE;
+ }
+ }
+
+ opj_read_bytes(p_header_data,&l_tmp,3); /* Wmccij Component offset*/
+ p_header_data += 3;
+
+ l_mcc_record->m_is_irreversible = ! ((l_tmp>>16) & 1);
+ l_mcc_record->m_decorrelation_array = 00;
+ l_mcc_record->m_offset_array = 00;
+
+ l_indix = l_tmp & 0xff;
+ if (l_indix != 0) {
+ l_mct_data = l_tcp->m_mct_records;
+ for (j=0;j<l_tcp->m_nb_mct_records;++j) {
+ if (l_mct_data->m_index == l_indix) {
+ l_mcc_record->m_decorrelation_array = l_mct_data;
+ break;
+ }
+ ++l_mct_data;
+ }
+
+ if (l_mcc_record->m_decorrelation_array == 00) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+ }
+
+ l_indix = (l_tmp >> 8) & 0xff;
+ if (l_indix != 0) {
+ l_mct_data = l_tcp->m_mct_records;
+ for (j=0;j<l_tcp->m_nb_mct_records;++j) {
+ if (l_mct_data->m_index == l_indix) {
+ l_mcc_record->m_offset_array = l_mct_data;
+ break;
+ }
+ ++l_mct_data;
+ }
+
+ if (l_mcc_record->m_offset_array == 00) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+ }
+ }
+
+ if (p_header_size != 0) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCC marker\n");
+ return OPJ_FALSE;
+ }
+
+ ++l_tcp->m_nb_mcc_records;
+
+ return OPJ_TRUE;
+}
+
+/**
+ * Reads a MCO marker (Multiple Component Transform Ordering)
+ *
+ * @param p_header_data the data contained in the MCO box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the MCO marker.
+ * @param p_manager the user event manager.
+*/
+opj_bool j2k_read_mco ( opj_j2k_v2_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ struct opj_event_mgr * p_manager )
+{
+ OPJ_UINT32 l_tmp, i;
+ OPJ_UINT32 l_nb_stages;
+ opj_tcp_v2_t * l_tcp;
+ opj_tccp_t * l_tccp;
+ opj_image_t * l_image;
+ opj_image_comp_t * l_img_comp;
+
+ /* preconditions */
+ assert(p_header_data != 00);
+ assert(p_j2k != 00);
+ assert(p_manager != 00);
+
+ l_image = p_j2k->m_private_image;
+ l_tcp = p_j2k->m_specific_param.m_decoder.m_state == J2K_STATE_TPH ?
+ &p_j2k->m_cp.tcps[p_j2k->m_current_tile_number] :
+ p_j2k->m_specific_param.m_decoder.m_default_tcp;
+
+ if (p_header_size < 1) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Error reading MCO marker\n");
+ return OPJ_FALSE;
+ }
+
+ opj_read_bytes(p_header_data,&l_nb_stages,1); /* Nmco : only one tranform stage*/
+ ++p_header_data;
+
+ if (l_nb_stages > 1) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Cannot take in charge multiple transformation stages.\n");
+ return OPJ_TRUE;
+ }
+
+ if (p_header_size != l_nb_stages + 1) {
+ opj_event_msg_v2(p_manager, EVT_WARNING, "Error reading MCO marker\n");
+ return OPJ_FALSE;
+ }
+
+ l_tccp = l_tcp->tccps;
+ l_img_comp = l_image->comps;
+
+ for (i=0;i<l_image->numcomps;++i) {
+ l_tccp->m_dc_level_shift = 0;
+ ++l_tccp;
+ }
+
+ if (l_tcp->m_mct_decoding_matrix) {
+ opj_free(l_tcp->m_mct_decoding_matrix);
+ l_tcp->m_mct_decoding_matrix = 00;
+ }
+
+ for (i=0;i<l_nb_stages;++i) {
+ opj_read_bytes(p_header_data,&l_tmp,1);
+ ++p_header_data;
+
+ if (! j2k_add_mct(l_tcp,p_j2k->m_private_image,l_tmp)) {
+ return OPJ_FALSE;
+ }
+ }
+
+ return OPJ_TRUE;
+}
+
+opj_bool j2k_add_mct(opj_tcp_v2_t * p_tcp, opj_image_t * p_image, OPJ_UINT32 p_index)
+{
+ OPJ_UINT32 i;
+ opj_simple_mcc_decorrelation_data_t * l_mcc_record;
+ opj_mct_data_t * l_deco_array, * l_offset_array;
+ OPJ_UINT32 l_data_size,l_mct_size, l_offset_size;
+ OPJ_UINT32 l_nb_elem;
+ OPJ_UINT32 * l_offset_data, * l_current_offset_data;
+ opj_tccp_t * l_tccp;
+
+ /* preconditions */
+ assert(p_tcp != 00);
+
+ l_mcc_record = p_tcp->m_mcc_records;
+
+ for (i=0;i<p_tcp->m_nb_mcc_records;++i) {
+ if (l_mcc_record->m_index == p_index) {
+ break;
+ }
+ }
+
+ if (i==p_tcp->m_nb_mcc_records) {
+ /** element discarded **/
+ return OPJ_TRUE;
+ }
+
+ if (l_mcc_record->m_nb_comps != p_image->numcomps) {
+ /** do not support number of comps != image */
+ return OPJ_TRUE;
+ }
+
+ l_deco_array = l_mcc_record->m_decorrelation_array;
+
+ if (l_deco_array) {
+ l_data_size = MCT_ELEMENT_SIZE[l_deco_array->m_element_type] * p_image->numcomps * p_image->numcomps;
+ if (l_deco_array->m_data_size != l_data_size) {
+ return OPJ_FALSE;
+ }
+
+ l_nb_elem = p_image->numcomps * p_image->numcomps;
+ l_mct_size = l_nb_elem * sizeof(OPJ_FLOAT32);
+ p_tcp->m_mct_decoding_matrix = (OPJ_FLOAT32*)opj_malloc(l_mct_size);
+
+ if (! p_tcp->m_mct_decoding_matrix ) {
+ return OPJ_FALSE;
+ }
+
+ j2k_mct_read_functions_to_float[l_deco_array->m_element_type](l_deco_array->m_data,p_tcp->m_mct_decoding_matrix,l_nb_elem);
+ }
+
+ l_offset_array = l_mcc_record->m_offset_array;
+
+ if (l_offset_array) {
+ l_data_size = MCT_ELEMENT_SIZE[l_offset_array->m_element_type] * p_image->numcomps;
+ if (l_offset_array->m_data_size != l_data_size) {
+ return OPJ_FALSE;
+ }
+
+ l_nb_elem = p_image->numcomps;
+ l_offset_size = l_nb_elem * sizeof(OPJ_UINT32);
+ l_offset_data = (OPJ_UINT32*)opj_malloc(l_offset_size);
+
+ if (! l_offset_data ) {
+ return OPJ_FALSE;
+ }
+
+ j2k_mct_read_functions_to_int32[l_offset_array->m_element_type](l_offset_array->m_data,l_offset_data,l_nb_elem);
+
+ l_tccp = p_tcp->tccps;
+ l_current_offset_data = l_offset_data;
+
+ for (i=0;i<p_image->numcomps;++i) {
+ l_tccp->m_dc_level_shift = *(l_current_offset_data++);
+ ++l_tccp;
+ }
+
+ opj_free(l_offset_data);
+ }
+
+ return OPJ_TRUE;
+}
+
+/**
+ * Reads a CBD marker (Component bit depth definition)
+ * @param p_header_data the data contained in the CBD box.
+ * @param p_j2k the jpeg2000 codec.
+ * @param p_header_size the size of the data contained in the CBD marker.
+ * @param p_manager the user event manager.
+*/
+opj_bool j2k_read_cbd ( opj_j2k_v2_t *p_j2k,
+ OPJ_BYTE * p_header_data,
+ OPJ_UINT32 p_header_size,
+ struct opj_event_mgr * p_manager)
+{
+ OPJ_UINT32 l_nb_comp,l_num_comp;
+ OPJ_UINT32 l_comp_def;
+ OPJ_UINT32 i;
+ opj_image_comp_t * l_comp = 00;
+
+ /* preconditions */
+ assert(p_header_data != 00);
+ assert(p_j2k != 00);
+ assert(p_manager != 00);
+
+ l_num_comp = p_j2k->m_private_image->numcomps;
+
+ if (p_header_size != (p_j2k->m_private_image->numcomps + 2)) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Crror reading CBD marker\n");
+ return OPJ_FALSE;
+ }
+
+ opj_read_bytes(p_header_data,&l_nb_comp,2); /* Ncbd */
+ p_header_data+=2;
+
+ if (l_nb_comp != l_num_comp) {
+ opj_event_msg_v2(p_manager, EVT_ERROR, "Crror reading CBD marker\n");
+ return OPJ_FALSE;
+ }
+
+ l_comp = p_j2k->m_private_image->comps;
+ for (i=0;i<l_num_comp;++i) {
+ opj_read_bytes(p_header_data,&l_comp_def,1); /* Component bit depth */
+ ++p_header_data;
+ l_comp->sgnd = (l_comp_def>>7) & 1;
+ l_comp->prec = (l_comp_def&0x7f) + 1;
+ ++l_comp;
+ }
+
+ return OPJ_TRUE;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* J2K / JPT decoder interface */
+/* ----------------------------------------------------------------------- */
+
+opj_j2k_t* j2k_create_decompress(opj_common_ptr cinfo) {
+ opj_j2k_t *j2k = (opj_j2k_t*) opj_calloc(1, sizeof(opj_j2k_t));
+ if(!j2k)
+ return NULL;
+
+ j2k->default_tcp = (opj_tcp_t*) opj_calloc(1, sizeof(opj_tcp_t));
+ if(!j2k->default_tcp) {
+ opj_free(j2k);
+ return NULL;
+ }
+
+ j2k->cinfo = cinfo;
+ j2k->tile_data = NULL;
+
+ return j2k;
+}
+
+void j2k_destroy_decompress(opj_j2k_t *j2k) {
+ int i = 0;
+
+ if(j2k->tile_len != NULL) {
+ opj_free(j2k->tile_len);
+ }
+ if(j2k->tile_data != NULL) {
+ opj_free(j2k->tile_data);