GF_Err video_sample_entry_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s;
	switch (a->type) {
	case GF_ISOM_BOX_TYPE_ESDS:
		BOX_FIELD_ASSIGN(esd, GF_ESDBox)
		break;
	case GF_ISOM_BOX_TYPE_RINF:
		BOX_FIELD_ASSIGN(rinf, GF_RestrictedSchemeInfoBox)
		break;
	case GF_ISOM_BOX_TYPE_AVCC:
		BOX_FIELD_ASSIGN(avc_config, GF_AVCConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_HVCC:
		BOX_FIELD_ASSIGN(hevc_config, GF_HEVCConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_VVCC:
		BOX_FIELD_ASSIGN(vvc_config, GF_VVCConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_SVCC:
		BOX_FIELD_ASSIGN(svc_config, GF_AVCConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_MVCC:
		BOX_FIELD_ASSIGN(mvc_config, GF_AVCConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_LHVC:
		BOX_FIELD_ASSIGN(lhvc_config, GF_HEVCConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_AV1C:
		BOX_FIELD_ASSIGN(av1_config, GF_AV1ConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_VPCC:
		BOX_FIELD_ASSIGN(vp_config, GF_VPConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_DVCC:
	case GF_ISOM_BOX_TYPE_DVVC:
		BOX_FIELD_ASSIGN(dovi_config, GF_DOVIConfigurationBox)
		break;
	case GF_ISOM_BOX_TYPE_UUID:
		if (! memcmp(((GF_UnknownUUIDBox*)a)->uuid, GF_ISOM_IPOD_EXT, 16)) {
			BOX_FIELD_ASSIGN(ipod_ext, GF_UnknownUUIDBox)
		} else {
			return GF_OK;
		}
		break;
	case GF_ISOM_BOX_TYPE_D263:
		BOX_FIELD_ASSIGN(cfg_3gpp, GF_3GPPConfigBox)
		/*for 3GP config, remember sample entry type in config*/
		if (ptr->cfg_3gpp)
			ptr->cfg_3gpp->cfg.type = ptr->type;
		break;

	case GF_ISOM_BOX_TYPE_JP2H:
		BOX_FIELD_ASSIGN(jp2h, GF_J2KHeaderBox)
		return GF_OK;

	case GF_ISOM_BOX_TYPE_PASP:
	case GF_ISOM_BOX_TYPE_CLAP:
	case GF_ISOM_BOX_TYPE_COLR:
	case GF_ISOM_BOX_TYPE_MDCV:
	case GF_ISOM_BOX_TYPE_CLLI:
	case GF_ISOM_BOX_TYPE_CCST:
	case GF_ISOM_BOX_TYPE_AUXI:
	case GF_ISOM_BOX_TYPE_RVCC:
	case GF_ISOM_BOX_TYPE_M4DS:
		if (!is_rem && !gf_isom_box_check_unique(s->child_boxes, a)) {
			ERROR_ON_DUPLICATED_BOX(a, ptr)
		}
		return GF_OK;
	}
	return GF_OK;
}

fixed #2092


GF_Box *ssix_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_SubsegmentIndexBox, GF_ISOM_BOX_TYPE_SSIX);
	return (GF_Box *)tmp;

fixed #2092


GF_Err trik_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	for (i=0; i < ptr->entry_count; i++ ) {
		gf_bs_write_int(bs, ptr->entries[i].pic_type, 2);
		gf_bs_write_int(bs, ptr->entries[i].dependency_level, 6);
	}
	return GF_OK;

fixed #2092


GF_Err prhd_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_ProjectionHeaderBox *ptr = (GF_ProjectionHeaderBox *)s;
	ISOM_DECREASE_SIZE(ptr, 12)
	ptr->yaw = (s32) gf_bs_read_u32(bs);
	ptr->pitch = (s32) gf_bs_read_u32(bs);
	ptr->roll = (s32) gf_bs_read_u32(bs);
	return GF_OK;

fixed #2092


void stsc_box_del(GF_Box *s)
{
	GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s;
	if (ptr == NULL) return;
	if (ptr->entries) gf_free(ptr->entries);
	gf_free(ptr);
}

fixed #2092


GF_Err def_parent_box_size(GF_Box *s)
{
	return GF_OK;
}

fixed #2092


GF_Err dvcC_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i;
	GF_DOVIConfigurationBox *ptr = (GF_DOVIConfigurationBox *)s;

	//GF_DOVIDecoderConfigurationRecord
	ISOM_DECREASE_SIZE(ptr, 24)
	ptr->DOVIConfig.dv_version_major = gf_bs_read_u8(bs);
	ptr->DOVIConfig.dv_version_minor = gf_bs_read_u8(bs);
	ptr->DOVIConfig.dv_profile = gf_bs_read_int(bs, 7);
	ptr->DOVIConfig.dv_level = gf_bs_read_int(bs, 6);
	ptr->DOVIConfig.rpu_present_flag = gf_bs_read_int(bs, 1);
	ptr->DOVIConfig.el_present_flag = gf_bs_read_int(bs, 1);
	ptr->DOVIConfig.bl_present_flag = gf_bs_read_int(bs, 1);
	ptr->DOVIConfig.dv_bl_signal_compatibility_id = gf_bs_read_int(bs, 4);
	if (gf_bs_read_int(bs, 28) != 0)
		GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] dvcC reserved bits are not zero\n"));

	for (i = 0; i < 4; i++) {
		if (gf_bs_read_u32(bs) != 0) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] dvcC reserved bits are not zero\n"));
		}
	}
	if (ptr->DOVIConfig.dv_profile==8) {
		if (!ptr->DOVIConfig.dv_bl_signal_compatibility_id || (ptr->DOVIConfig.dv_bl_signal_compatibility_id>2) ) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] dvcC profile 8 but compatibility ID %d is not 1 or 2, patching to 2\n", ptr->DOVIConfig.dv_bl_signal_compatibility_id));
			ptr->DOVIConfig.dv_bl_signal_compatibility_id = 2;
		}
	}
	return GF_OK;

fixed #2092


GF_Box *tssy_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_TimeStampSynchronyBox, GF_ISOM_BOX_TYPE_TSSY);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err stdp_box_size(GF_Box *s)
{
	GF_DegradationPriorityBox *ptr = (GF_DegradationPriorityBox *)s;

	ptr->size += (2 * ptr->nb_entries);
	return GF_OK;
}

fixed #2092


GF_Box *elng_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_MediaBox, GF_ISOM_BOX_TYPE_ELNG);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err sdp_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 length;
	GF_SDPBox *ptr = (GF_SDPBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;

	length = (u32) (ptr->size);

	if (length >= (u32)0xFFFFFFFF) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid length %lu in sdp box\n", length));
		return GF_ISOM_INVALID_FILE;
	}

	//sdp text has no delimiter !!!
	ptr->sdpText = (char*)gf_malloc(sizeof(char) * (length+1));
	if (!ptr->sdpText) return GF_OUT_OF_MEM;

	gf_bs_read_data(bs, ptr->sdpText, length);
	ptr->sdpText[length] = 0;
	return GF_OK;
}

fixed #2092


GF_Err moof_box_read(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_array_read(s, bs);
}

fixed #2092


GF_Err traf_box_size(GF_Box *s)
{
	u32 pos=0;
	GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *) s;

	//Header first
	gf_isom_check_position(s, (GF_Box *)ptr->tfhd, &pos);
	gf_isom_check_position_list(s, ptr->sub_samples, &pos);

	gf_isom_check_position(s, (GF_Box *)ptr->tfdt, &pos);

	//cmaf-like
	if (ptr->truns_first) {
		gf_isom_check_position_list(s, ptr->TrackRuns, &pos);
		gf_isom_check_position_list(s, ptr->sai_sizes, &pos);
		gf_isom_check_position_list(s, ptr->sai_offsets, &pos);
		//senc MUST be after saio in GPAC, as senc writing uses info from saio writing
		gf_isom_check_position(s, (GF_Box *)ptr->sample_encryption, &pos);
		gf_isom_check_position_list(s, ptr->sampleGroupsDescription, &pos);
		gf_isom_check_position_list(s, ptr->sampleGroups, &pos);
		//subsamples will be last
	} else {
		gf_isom_check_position_list(s, ptr->sampleGroupsDescription, &pos);
		gf_isom_check_position_list(s, ptr->sampleGroups, &pos);
		gf_isom_check_position_list(s, ptr->sai_sizes, &pos);
		gf_isom_check_position_list(s, ptr->sai_offsets, &pos);
		gf_isom_check_position(s, (GF_Box *)ptr->sample_encryption, &pos);
		gf_isom_check_position_list(s, ptr->TrackRuns, &pos);
	}

	//when sdtp is present (smooth-like) write it after the trun box
	gf_isom_check_position(s, (GF_Box *)ptr->sdtp, &pos);

	//tfxd should be last ...
	if (ptr->tfxd)
		gf_isom_check_position(s, (GF_Box *)ptr->tfxd, &pos);
	return GF_OK;
}

fixed #2092


GF_Err stsg_box_size(GF_Box *s)
{
	GF_SubTrackSampleGroupBox *ptr = (GF_SubTrackSampleGroupBox *)s;
	ptr->size += 6 + 4 * ptr->nb_groups;
	return GF_OK;

fixed #2092


GF_Err video_sample_entry_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_MPEGVisualSampleEntryBox *mp4v = (GF_MPEGVisualSampleEntryBox*)s;
	GF_Err e;
	e = gf_isom_video_sample_entry_read((GF_VisualSampleEntryBox *)s, bs);
	if (e) return e;
	e = gf_isom_box_array_read(s, bs);
	if (e) return e;
	/*this is an AVC sample desc*/
	if (mp4v->avc_config || mp4v->svc_config || mp4v->mvc_config)
		AVC_RewriteESDescriptor(mp4v);
	/*this is an HEVC sample desc*/
	if (mp4v->hevc_config || mp4v->lhvc_config || (mp4v->type==GF_ISOM_BOX_TYPE_HVT1))
		HEVC_RewriteESDescriptor(mp4v);
	/*this is an AV1 sample desc*/
	if (mp4v->av1_config)
		AV1_RewriteESDescriptor(mp4v);
	/*this is a VP8-9 sample desc*/
	if (mp4v->vp_config)
		VP9_RewriteESDescriptor(mp4v);

	if (s->type==GF_ISOM_BOX_TYPE_ENCV) {
		GF_ProtectionSchemeInfoBox *sinf = (GF_ProtectionSchemeInfoBox *) gf_isom_box_find_child(s->child_boxes, GF_ISOM_BOX_TYPE_SINF);

		if (sinf && sinf->original_format) {
			u32 type = sinf->original_format->data_format;
			switch (type) {
			case GF_ISOM_SUBTYPE_3GP_H263:
				if (mp4v->cfg_3gpp) mp4v->cfg_3gpp->cfg.type = type;
				break;
			}
		}
	}
	return GF_OK;
}

fixed #2092


GF_Err dimm_box_size(GF_Box *s)
{
	s->size += 8;
	return GF_OK;
}

fixed #2092


GF_Err minf_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
	GF_Err e;

	e = gf_isom_box_array_read(s, bs);

	if (!e && ! ptr->dataInformation) {
		GF_Box *url;
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing DataInformationBox\n"));
		//commented on purpose, we are still able to handle the file, we only throw an error but keep processing
//		e = GF_ISOM_INVALID_FILE;

		//add a dinf box to avoid any access to a null dinf
		ptr->dataInformation = (GF_DataInformationBox *) gf_isom_box_new_parent(&ptr->child_boxes, GF_ISOM_BOX_TYPE_DINF);
		if (!ptr->dataInformation) return GF_OUT_OF_MEM;

		ptr->dataInformation->dref = (GF_DataReferenceBox *) gf_isom_box_new_parent(&ptr->dataInformation->child_boxes, GF_ISOM_BOX_TYPE_DREF);
		if (!ptr->dataInformation->dref) return GF_OUT_OF_MEM;

		url = gf_isom_box_new_parent(&ptr->dataInformation->dref->child_boxes, GF_ISOM_BOX_TYPE_URL);
		if (!url) return GF_OUT_OF_MEM;
		((GF_FullBox*)url)->flags = 1;
	}
	return e;
}

fixed #2092


GF_Err rtpo_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_RTPOBox *ptr = (GF_RTPOBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;

	//here we have no pb, just remembed that some entries will have to
	//be 4-bytes aligned ...
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->timeOffset);
	return GF_OK;
}

fixed #2092


GF_Err tref_box_read(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_array_read_ex(s, bs, s->type);

fixed #2092


GF_Box *payt_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_PAYTBox, GF_ISOM_BOX_TYPE_PAYT);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Box *sbgp_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_SampleGroupBox, GF_ISOM_BOX_TYPE_SBGP);
	return (GF_Box *)tmp;

fixed #2092


GF_Err clap_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_CleanApertureBox *ptr = (GF_CleanApertureBox *)s;
	GF_Err e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->cleanApertureWidthN);
	gf_bs_write_u32(bs, ptr->cleanApertureWidthD);
	gf_bs_write_u32(bs, ptr->cleanApertureHeightN);
	gf_bs_write_u32(bs, ptr->cleanApertureHeightD);
	gf_bs_write_u32(bs, (u32) ptr->horizOffN);
	gf_bs_write_u32(bs, ptr->horizOffD);
	gf_bs_write_u32(bs, (u32) ptr->vertOffN);
	gf_bs_write_u32(bs, ptr->vertOffD);
	return GF_OK;

fixed #2092


void dfla_box_del(GF_Box *s)
{
	GF_FLACConfigBox *ptr = (GF_FLACConfigBox *) s;
	if (ptr->data) gf_free(ptr->data);
	gf_free(ptr);

fixed #2092


GF_Box *mvex_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_MovieExtendsBox, GF_ISOM_BOX_TYPE_MVEX);
	tmp->TrackExList = gf_list_new();
	if (!tmp->TrackExList) {
		gf_free(tmp);
		return NULL;
	}
	tmp->TrackExPropList = gf_list_new();
	if (!tmp->TrackExPropList) {
		gf_list_del(tmp->TrackExList);
		gf_free(tmp);
		return NULL;
	}
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err ccst_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	gf_bs_write_int(bs, ptr->all_ref_pics_intra, 1);
	gf_bs_write_int(bs, ptr->intra_pred_used, 1);
	gf_bs_write_int(bs, ptr->max_ref_per_pic, 4);
	gf_bs_write_int(bs, 0, 26);
	return GF_OK;
}

fixed #2092


GF_Err fdsa_box_size(GF_Box *s)
{
	return GF_OK;

fixed #2092


GF_Box *mfra_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_MovieFragmentRandomAccessBox, GF_ISOM_BOX_TYPE_MFRA);
	tmp->tfra_list = gf_list_new();
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err uuid_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 bytesToRead;
	GF_UnknownUUIDBox *ptr = (GF_UnknownUUIDBox *)s;
	if (ptr->size > 0xFFFFFFFF) return GF_ISOM_INVALID_FILE;
	bytesToRead = (u32) (ptr->size);

	if (bytesToRead) {
		ptr->data = (char*)gf_malloc(bytesToRead);
		if (ptr->data == NULL ) return GF_OUT_OF_MEM;
		ptr->dataSize = bytesToRead;
		gf_bs_read_data(bs, ptr->data, ptr->dataSize);
	}
	return GF_OK;
}

fixed #2092


void saio_box_del(GF_Box *s)
{
	GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox*)s;
	if (ptr == NULL) return;
	if (ptr->offsets) gf_free(ptr->offsets);
	if (ptr->cached_data) gf_free(ptr->cached_data);
	gf_free(ptr);

fixed #2092


GF_Err tfrf_box_size(GF_Box *s)
{
	GF_MSSTimeRefBox *ptr = (GF_MSSTimeRefBox*)s;
	s->size += 5;
	if (ptr->version) s->size += 16 * ptr->frags_count;
	else s->size += 8 * ptr->frags_count;
	return GF_OK;
}

fixed #2092


GF_Err sdp_box_size(GF_Box *s)
{
	GF_SDPBox *ptr = (GF_SDPBox *)s;
	//don't count the NULL char!!!
	if (ptr->sdpText)
		ptr->size += strlen(ptr->sdpText);
	return GF_OK;
}

fixed #2092


GF_Err fdpa_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_FDpacketBox *ptr = (GF_FDpacketBox *) s;
	if (!s) return GF_BAD_PARAM;

	e = gf_isom_box_write_header(s, bs);
	if (e) return e;

	gf_bs_write_int(bs, ptr->info.sender_current_time_present, 1);
	gf_bs_write_int(bs, ptr->info.expected_residual_time_present, 1);
	gf_bs_write_int(bs, ptr->info.session_close_bit, 1);
	gf_bs_write_int(bs, ptr->info.object_close_bit, 1);
	gf_bs_write_int(bs, 0, 4);
	gf_bs_write_u16(bs, ptr->info.transport_object_identifier);
	gf_bs_write_u16(bs, ptr->header_ext_count);
	for (i=0; i<ptr->header_ext_count; i++) {
		gf_bs_write_u8(bs, ptr->headers[i].header_extension_type);
		if (ptr->headers[i].header_extension_type > 127) {
			gf_bs_write_data(bs, (const char *) ptr->headers[i].content, 3);
		} else {
			gf_bs_write_u8(bs, ptr->headers[i].data_length ? (ptr->headers[i].data_length+2)/4 : 0);
			if (ptr->headers[i].data_length) {
				gf_bs_write_data(bs, ptr->headers[i].data, ptr->headers[i].data_length);
			}
		}
	}
	return GF_OK;

fixed #2092


GF_Err rtp_hnti_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_RTPBox *ptr = (GF_RTPBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->subType);
	//don't write the NULL char!!!
	gf_bs_write_data(bs, ptr->sdpText, (u32) strlen(ptr->sdpText));
	return GF_OK;
}

fixed #2092


GF_Err ccst_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_CodingConstraintsBox *ptr = (GF_CodingConstraintsBox *)s;

	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->all_ref_pics_intra = gf_bs_read_int(bs, 1);
	ptr->intra_pred_used = gf_bs_read_int(bs, 1);
	ptr->max_ref_per_pic = gf_bs_read_int(bs, 4);
	ptr->reserved = gf_bs_read_int(bs, 26);
	return GF_OK;
}

fixed #2092


GF_Err hinf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_HintInfoBox *hinf = (GF_HintInfoBox *)s;
	switch (a->type) {
	case GF_ISOM_BOX_TYPE_MAXR:
		if (!is_rem) {
			u32 i=0;
			GF_MAXRBox *maxR;
			while ((maxR = (GF_MAXRBox *)gf_list_enum(hinf->child_boxes, &i))) {
				if ((maxR->type==GF_ISOM_BOX_TYPE_MAXR) && (maxR->granularity == ((GF_MAXRBox *)a)->granularity))
					ERROR_ON_DUPLICATED_BOX(a, s)
			}
		}
		break;
	}
	return GF_OK;
}

fixed #2092


GF_Box *dref_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_DataReferenceBox, GF_ISOM_BOX_TYPE_DREF);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err trgr_box_size(GF_Box *s)
{
	u32 pos=0;
	GF_TrackGroupBox *ptr = (GF_TrackGroupBox *) s;
	gf_isom_check_position_list(s, ptr->groups, &pos);
	return GF_OK;

fixed #2092


GF_Err trgr_box_write(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_write_header(s, bs);

fixed #2092


void reftype_box_del(GF_Box *s)
{
	GF_TrackReferenceTypeBox *ptr = (GF_TrackReferenceTypeBox *)s;
	if (!ptr) return;
	if (ptr->trackIDs) gf_free(ptr->trackIDs);
	gf_free(ptr);

fixed #2092


GF_Err video_sample_entry_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_isom_video_sample_entry_write((GF_VisualSampleEntryBox *)s, bs);
	return GF_OK;
}

fixed #2092


}
GF_Err jp2h_box_read(GF_Box *s,GF_BitStream *bs)
{
	return gf_isom_box_array_read_ex(s, bs, s->type);

fixed #2092


GF_Err svhd_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_SphericalVideoInfoBox *ptr = (GF_SphericalVideoInfoBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	if (ptr->string)
		gf_bs_write_data(bs, ptr->string, (u32) strlen(ptr->string));
	gf_bs_write_u8(bs, 0);
	return GF_OK;

fixed #2092


GF_Box *hinf_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_HintInfoBox, GF_ISOM_BOX_TYPE_HINF);

	tmp->child_boxes = gf_list_new();
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err name_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_NameBox *ptr = (GF_NameBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	if (ptr->string) {
		gf_bs_write_data(bs, ptr->string, (u32) strlen(ptr->string) + 1);
	}
	return GF_OK;
}

fixed #2092


void padb_box_del(GF_Box *s)
{
	GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *) s;
	if (ptr == NULL) return;
	if (ptr->padbits) gf_free(ptr->padbits);
	gf_free(ptr);
}

fixed #2092


GF_Err tref_box_write(GF_Box *s, GF_BitStream *bs)
{
//	GF_TrackReferenceBox *ptr = (GF_TrackReferenceBox *)s;
	return gf_isom_box_write_header(s, bs);

fixed #2092


void lsr1_box_del(GF_Box *s)
{
	GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;
	if (ptr == NULL) return;
	gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);
	if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
	gf_free(ptr);

fixed #2092


GF_Box *tmax_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_TMAXBox, GF_ISOM_BOX_TYPE_TMAX);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Box *tfxd_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_MSSTimeExtBox, GF_ISOM_BOX_TYPE_UUID);
	tmp->internal_4cc = GF_ISOM_BOX_UUID_TFXD;
	tmp->version = 1;
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err payt_box_write(GF_Box *s, GF_BitStream *bs)
{
	u32 len;
	GF_Err e;
	GF_PAYTBox *ptr = (GF_PAYTBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->payloadCode);
    len = ptr->payloadString ? (u32) strlen(ptr->payloadString) : 0;
	gf_bs_write_u8(bs, len);
	if (len) gf_bs_write_data(bs, ptr->payloadString, len);
	return GF_OK;
}

fixed #2092


#ifdef GF_ENABLE_CTRN
static void ctrn_write_sample_flags(GF_BitStream *bs, u32 flags, u32 field_size)
{
	if (!field_size) return;

	if (field_size==8) flags = flags>>24;
	else if (field_size==16) flags = flags>>16;
	gf_bs_write_int(bs, flags, field_size);

fixed #2092


GF_Err nmhd_box_read(GF_Box *s, GF_BitStream *bs)
{
	return GF_OK;
}

fixed #2092


GF_Err trex_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *)s;

	ISOM_DECREASE_SIZE(ptr, 20);
	ptr->trackID = gf_bs_read_u32(bs);
	ptr->def_sample_desc_index = gf_bs_read_u32(bs);
	ptr->def_sample_duration = gf_bs_read_u32(bs);
	ptr->def_sample_size = gf_bs_read_u32(bs);
	ptr->def_sample_flags = gf_bs_read_u32(bs);
	return GF_OK;

fixed #2092


void video_sample_entry_box_del(GF_Box *s)
{
	GF_MPEGVisualSampleEntryBox *ptr = (GF_MPEGVisualSampleEntryBox *)s;
	if (ptr == NULL) return;
	gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);

	if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
	/*for publishing*/
	if (ptr->emul_esd) gf_odf_desc_del((GF_Descriptor *)ptr->emul_esd);
	gf_free(ptr);
}

fixed #2092


GF_Err mfro_box_size(GF_Box *s)
{
	s->size += 4;
	return GF_OK;
}

fixed #2092


GF_Box *dac3_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_AC3ConfigBox, GF_ISOM_BOX_TYPE_DAC3);
	return (GF_Box *)tmp;

fixed #2092


GF_Box *vwid_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_ViewIdentifierBox, GF_ISOM_BOX_TYPE_VWID);
	return (GF_Box *)tmp;

fixed #2092


GF_Err dOps_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_OpusSpecificBox *ptr = (GF_OpusSpecificBox *)s;
	if (!s) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u8(bs, ptr->version);
	gf_bs_write_u8(bs, ptr->OutputChannelCount);
	gf_bs_write_u16(bs, ptr->PreSkip);
	gf_bs_write_u32(bs, ptr->InputSampleRate);
	gf_bs_write_u16(bs, ptr->OutputGain);
	gf_bs_write_u8(bs, ptr->ChannelMappingFamily);
	if (ptr->ChannelMappingFamily) {
		gf_bs_write_u8(bs, ptr->StreamCount);
		gf_bs_write_u8(bs, ptr->CoupledCount);
		gf_bs_write_data(bs, (char *) ptr->ChannelMapping, ptr->OutputChannelCount);
	}
	return GF_OK;

fixed #2092


GF_Err lsr1_box_size(GF_Box *s)
{
	u32 pos=0;
	GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;
	s->size += 8;
	gf_isom_check_position(s, (GF_Box *)ptr->lsr_config, &pos);
	return GF_OK;

fixed #2092


void tssy_box_del(GF_Box *s)
{
	gf_free(s);
}

fixed #2092


GF_Err stsc_box_size(GF_Box *s)
{
	GF_SampleToChunkBox *ptr = (GF_SampleToChunkBox *)s;

	ptr->size += 4 + (12 * ptr->nb_entries);
	return GF_OK;
}

fixed #2092


GF_Err drep_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_DREPBox *ptr = (GF_DREPBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u64(bs, ptr->nbBytes);
	return GF_OK;
}

fixed #2092


void sgpd_box_del(GF_Box *a)
{
	GF_SampleGroupDescriptionBox *p = (GF_SampleGroupDescriptionBox *)a;
	while (gf_list_count(p->group_descriptions)) {
		void *ptr = gf_list_last(p->group_descriptions);
		sgpd_del_entry(p->grouping_type, ptr);
		gf_list_rem_last(p->group_descriptions);
	}
	gf_list_del(p->group_descriptions);
	gf_free(p);

fixed #2092


GF_Err tfhd_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s;

	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->trackID = gf_bs_read_u32(bs);

	//The rest depends on the flags
	if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) {
		ISOM_DECREASE_SIZE(ptr, 8);
		ptr->base_data_offset = gf_bs_read_u64(bs);
	}
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->sample_desc_index = gf_bs_read_u32(bs);
	}
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->def_sample_duration = gf_bs_read_u32(bs);
	}
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->def_sample_size = gf_bs_read_u32(bs);
	}
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->def_sample_flags = gf_bs_read_u32(bs);
	}
	return GF_OK;
}

fixed #2092


GF_Err tims_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TSHintEntryBox *ptr = (GF_TSHintEntryBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->timeScale = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #2092


GF_Err minf_box_size(GF_Box *s)
{
	u32 pos=0;
	GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
	//Header first
	gf_isom_check_position(s, (GF_Box *)ptr->InfoHeader, &pos);
	//then dataInfo
	gf_isom_check_position(s, (GF_Box *)ptr->dataInformation, &pos);
	gf_isom_check_position(s, gf_isom_box_find_child(s->child_boxes, GF_ISOM_BOX_TYPE_MVCI), &pos);
	//then sampleTable
	gf_isom_check_position(s, (GF_Box *)ptr->sampleTable, &pos);
	return GF_OK;
}

fixed #2092


GF_Err metx_box_size(GF_Box *s)
{
	GF_MetaDataSampleEntryBox *ptr = (GF_MetaDataSampleEntryBox *)s;
	ptr->size += 8;

	if (ptr->type!=GF_ISOM_BOX_TYPE_STPP) {
		if (ptr->content_encoding)
			ptr->size += strlen(ptr->content_encoding);
		ptr->size++;
	}

	if ((ptr->type==GF_ISOM_BOX_TYPE_METX) || (ptr->type==GF_ISOM_BOX_TYPE_STPP)) {

		if (ptr->xml_namespace)
			ptr->size += strlen(ptr->xml_namespace);
		ptr->size++;

		if (ptr->xml_schema_loc)
			ptr->size += strlen(ptr->xml_schema_loc);
		ptr->size++;

		if (ptr->type==GF_ISOM_BOX_TYPE_STPP) {
			if (ptr->mime_type)
				ptr->size += strlen(ptr->mime_type);
			ptr->size++;
		}

	}
	//mett, sbtt, stxt
	else {
		if (ptr->mime_type)
			ptr->size += strlen(ptr->mime_type);
		ptr->size++;
	}
	return GF_OK;

fixed #2092


GF_Err vwid_box_read(GF_Box *s,GF_BitStream *bs)
{
	u32 i;
	GF_ViewIdentifierBox *ptr = (GF_ViewIdentifierBox *) s;
	ISOM_DECREASE_SIZE(s, 3)
	gf_bs_read_int(bs, 2);
	ptr->min_temporal_id = gf_bs_read_int(bs, 3);
	ptr->max_temporal_id = gf_bs_read_int(bs, 3);
	ptr->num_views = gf_bs_read_u16(bs);
	if (ptr->num_views > ptr->size / 6)
		return GF_ISOM_INVALID_FILE;

	ptr->views = gf_malloc(sizeof(ViewIDEntry)*ptr->num_views);
	memset(ptr->views, 0, sizeof(ViewIDEntry)*ptr->num_views);
	for (i=0; i<ptr->num_views; i++) {
		u32 j;
		ISOM_DECREASE_SIZE(s, 6)

		gf_bs_read_int(bs, 6);
		ptr->views[i].view_id = gf_bs_read_int(bs, 10);
		gf_bs_read_int(bs, 6);
		ptr->views[i].view_order_index = gf_bs_read_int(bs, 10);
		ptr->views[i].texture_in_stream = gf_bs_read_int(bs, 1);
		ptr->views[i].texture_in_track = gf_bs_read_int(bs, 1);
		ptr->views[i].depth_in_stream = gf_bs_read_int(bs, 1);
		ptr->views[i].depth_in_track = gf_bs_read_int(bs, 1);
		ptr->views[i].base_view_type = gf_bs_read_int(bs, 2);
		ptr->views[i].num_ref_views = gf_bs_read_int(bs, 10);

		if (ptr->views[i].num_ref_views > ptr->size / 2)
			return GF_ISOM_INVALID_FILE;

		ptr->views[i].view_refs = gf_malloc(sizeof(ViewIDRefViewEntry)*ptr->views[i].num_ref_views);
		for (j=0; j<ptr->views[i].num_ref_views; j++) {
			ISOM_DECREASE_SIZE(s, 2)
			gf_bs_read_int(bs, 4);
			ptr->views[i].view_refs[j].dep_comp_idc = gf_bs_read_int(bs, 2);
			ptr->views[i].view_refs[j].ref_view_id = gf_bs_read_int(bs, 10);
		}
	}
	return GF_OK;

fixed #2092


GF_Err mp4s_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_MPEGSampleEntryBox *ptr = (GF_MPEGSampleEntryBox *)s;

	e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
	if (e) return e;

	ISOM_DECREASE_SIZE(ptr, 8);
	return gf_isom_box_array_read(s, bs);
}

fixed #2092


void maxr_box_del(GF_Box *s)
{
	gf_free((GF_MAXRBox *)s);
}

fixed #2092


GF_Err gitn_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GroupIdToNameBox *ptr = (GroupIdToNameBox *) s;
	if (!s) return GF_BAD_PARAM;
	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u16(bs, ptr->nb_entries);
	for (i=0; i<ptr->nb_entries; i++) {
		gf_bs_write_u32(bs, ptr->entries[i].group_id);
		if (ptr->entries[i].name) gf_bs_write_data(bs, ptr->entries[i].name, (u32)strlen(ptr->entries[i].name) );
		gf_bs_write_u8(bs, 0);
	}
	return GF_OK;

fixed #2092


GF_Err leva_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_LevelAssignmentBox *ptr = (GF_LevelAssignmentBox*)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u8(bs, ptr->level_count);
	for (i = 0; i<ptr->level_count; i++) {
		gf_bs_write_u32(bs, ptr->levels[i].track_id);
		gf_bs_write_u8(bs, ptr->levels[i].padding_flag << 7 | (ptr->levels[i].type & 0x7F));
		if (ptr->levels[i].type == 0) {
			gf_bs_write_u32(bs, ptr->levels[i].grouping_type);
		}
		else if (ptr->levels[i].type == 1) {
			gf_bs_write_u32(bs, ptr->levels[i].grouping_type);
			gf_bs_write_u32(bs, ptr->levels[i].grouping_type_parameter);
		}
		else if (ptr->levels[i].type == 4) {
			gf_bs_write_u32(bs, ptr->levels[i].sub_track_id);
		}
	}
	return GF_OK;

fixed #2092


GF_Err rvcc_box_size(GF_Box *s)
{
	GF_RVCConfigurationBox *ptr = (GF_RVCConfigurationBox *)s;
	ptr->size += 2;
	if (! ptr->predefined_rvc_config) ptr->size += 2;
	return GF_OK;

fixed #2092


GF_Err free_box_size(GF_Box *s)
{
	GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s;
	ptr->size += ptr->dataSize;
	return GF_OK;
}

fixed #2092


GF_Err audio_sample_entry_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_UnknownBox *wave = NULL;
	Bool drop_wave=GF_FALSE;
	GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s;

	switch (a->type) {
	case GF_ISOM_BOX_TYPE_ESDS:
		BOX_FIELD_ASSIGN(esd, GF_ESDBox)
		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
		break;

	case GF_ISOM_BOX_TYPE_DAMR:
	case GF_ISOM_BOX_TYPE_DEVC:
	case GF_ISOM_BOX_TYPE_DQCP:
	case GF_ISOM_BOX_TYPE_DSMV:
		BOX_FIELD_ASSIGN(cfg_3gpp, GF_3GPPConfigBox)
		/*for 3GP config, remember sample entry type in config*/
		ptr->cfg_3gpp->cfg.type = ptr->type;
		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
		break;

	case GF_ISOM_BOX_TYPE_DOPS:
		BOX_FIELD_ASSIGN(cfg_opus, GF_OpusSpecificBox)
		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
		break;
	case GF_ISOM_BOX_TYPE_DAC3:
		BOX_FIELD_ASSIGN(cfg_ac3, GF_AC3ConfigBox)
		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
		break;
	case GF_ISOM_BOX_TYPE_DEC3:
		BOX_FIELD_ASSIGN(cfg_ac3, GF_AC3ConfigBox)
		break;
	case GF_ISOM_BOX_TYPE_DMLP:
		BOX_FIELD_ASSIGN(cfg_mlp, GF_TrueHDConfigBox)
		break;
	case GF_ISOM_BOX_TYPE_MHAC:
		BOX_FIELD_ASSIGN(cfg_mha, GF_MHAConfigBox)
		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
		break;
	case GF_ISOM_BOX_TYPE_DFLA:
		BOX_FIELD_ASSIGN(cfg_flac, GF_FLACConfigBox)
		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
		break;

	case GF_ISOM_BOX_TYPE_UNKNOWN:
		wave = (GF_UnknownBox *)a;
		/*HACK for QT files: get the esds box from the track*/
		if (s->type == GF_ISOM_BOX_TYPE_MP4A) {
			if (is_rem) {
				return GF_OK;
			}
			if (ptr->esd) ERROR_ON_DUPLICATED_BOX(a, ptr)
			//wave subboxes may have been properly parsed
 			if ((wave->original_4cc == GF_QT_BOX_TYPE_WAVE) && gf_list_count(wave->child_boxes)) {
 				u32 i;
                for (i =0; i<gf_list_count(wave->child_boxes); i++) {
                    GF_Box *inner_box = (GF_Box *)gf_list_get(wave->child_boxes, i);
                    if (inner_box->type == GF_ISOM_BOX_TYPE_ESDS) {
                        ptr->esd = (GF_ESDBox *)inner_box;
 						if (ptr->qtff_mode & GF_ISOM_AUDIO_QTFF_CONVERT_FLAG) {
                        	gf_list_rem(a->child_boxes, i);
                        	drop_wave=GF_TRUE;
                        	ptr->compression_id = 0;
                        	gf_list_add(ptr->child_boxes, inner_box);
						}
                    }
                }
				if (drop_wave) {
					gf_isom_box_del_parent(&ptr->child_boxes, a);
                	ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
					ptr->version = 0;
					return GF_OK;
				}
                ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_EXT_VALID;
                return GF_OK;
            }
            gf_isom_box_del_parent(&ptr->child_boxes, a);
            return GF_ISOM_INVALID_MEDIA;

		}
 		ptr->qtff_mode &= ~GF_ISOM_AUDIO_QTFF_CONVERT_FLAG;

 		if ((wave->original_4cc == GF_QT_BOX_TYPE_WAVE) && gf_list_count(wave->child_boxes)) {
			ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_NOEXT;
		}
		return GF_OK;
	case GF_QT_BOX_TYPE_WAVE:
	{
		u32 subtype = 0;
		GF_Box **cfg_ptr = NULL;
		if (s->type == GF_ISOM_BOX_TYPE_MP4A) {
			cfg_ptr = (GF_Box **) &ptr->esd;
			subtype = GF_ISOM_BOX_TYPE_ESDS;
		}
		else if (s->type == GF_ISOM_BOX_TYPE_AC3) {
			cfg_ptr = (GF_Box **) &ptr->cfg_ac3;
			subtype = GF_ISOM_BOX_TYPE_DAC3;
		}
		else if (s->type == GF_ISOM_BOX_TYPE_EC3) {
			cfg_ptr = (GF_Box **) &ptr->cfg_ac3;
			subtype = GF_ISOM_BOX_TYPE_DEC3;
		}
		else if (s->type == GF_ISOM_BOX_TYPE_OPUS) {
			cfg_ptr = (GF_Box **) &ptr->cfg_opus;
			subtype = GF_ISOM_BOX_TYPE_DOPS;
		}
		else if ((s->type == GF_ISOM_BOX_TYPE_MHA1)
			|| (s->type == GF_ISOM_BOX_TYPE_MHA2)
			|| (s->type == GF_ISOM_BOX_TYPE_MHM1)
			|| (s->type == GF_ISOM_BOX_TYPE_MHM2)
		) {
			cfg_ptr = (GF_Box **) &ptr->cfg_mha;
			subtype = GF_ISOM_BOX_TYPE_MHAC;
		}
		else if (s->type == GF_ISOM_BOX_TYPE_MLPA) {
			cfg_ptr = (GF_Box **) &ptr->cfg_mlp;
			subtype = GF_ISOM_BOX_TYPE_DMLP;
		}

		if (cfg_ptr) {
			if (is_rem) {
				*cfg_ptr = NULL;
				return GF_OK;
			}
			if (*cfg_ptr) ERROR_ON_DUPLICATED_BOX(a, ptr)

			//wave subboxes may have been properly parsed
 			if (gf_list_count(a->child_boxes)) {
 				u32 i;
                for (i =0; i<gf_list_count(a->child_boxes); i++) {
                    GF_Box *inner_box = (GF_Box *)gf_list_get(a->child_boxes, i);
                    if (inner_box->type == subtype) {
                        *cfg_ptr = inner_box;
 						if (ptr->qtff_mode & GF_ISOM_AUDIO_QTFF_CONVERT_FLAG) {
                        	gf_list_rem(a->child_boxes, i);
                        	drop_wave=GF_TRUE;
                        	gf_list_add(ptr->child_boxes, inner_box);
						}
						break;
                    }
                }
				if (drop_wave) {
					gf_isom_box_del_parent(&ptr->child_boxes, a);
                	ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_NONE;
					ptr->compression_id = 0;
					ptr->version = 0;
					return GF_OK;
				}
                ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_EXT_VALID;
                return GF_OK;
            }
		}
	}
 		ptr->qtff_mode = GF_ISOM_AUDIO_QTFF_ON_EXT_VALID;
		return GF_OK;
	}
	return GF_OK;
}

fixed #2092


GF_Err rtpo_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_RTPOBox *ptr = (GF_RTPOBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->timeOffset = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #2092


void minf_box_del(GF_Box *s)
{
	GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
	if (ptr == NULL) return;

	//if we have a Handler not self-contained, delete it (the self-contained belongs to the movie)
	if (ptr->dataHandler) {
		gf_isom_datamap_close(ptr);
	}
	gf_free(ptr);
}

fixed #2092


GF_Err gitn_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i;
	GF_Err e;
	GroupIdToNameBox *ptr = (GroupIdToNameBox *)s;

	ISOM_DECREASE_SIZE(ptr, 2);
	ptr->nb_entries = gf_bs_read_u16(bs);
	if (ptr->size / 4 < ptr->nb_entries)
		return GF_ISOM_INVALID_FILE;

	GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, GroupIdNameEntry);
	if (!ptr->entries) return GF_OUT_OF_MEM;

	for (i=0; i<ptr->nb_entries; i++) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->entries[i].group_id = gf_bs_read_u32(bs);

		e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->entries[i].name);
		if (e) return e;
	}
	return GF_OK;

fixed #2092


void dmlp_box_del(GF_Box *s)
{
	gf_free(s);

fixed #2092


void drep_box_del(GF_Box *s)
{
	gf_free((GF_DREPBox *)s);
}

fixed #2092


GF_Err vmhd_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_VideoMediaHeaderBox *ptr = (GF_VideoMediaHeaderBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	gf_bs_write_u64(bs, ptr->reserved);
	return GF_OK;

fixed #2092


void trik_box_del(GF_Box *s)
{
	GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;
	if (ptr == NULL) return;
	if (ptr->entries) gf_free(ptr->entries);
	gf_free(ptr);

fixed #2092


GF_Err ctts_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i;
	u32 sampleCount;
	GF_CompositionOffsetBox *ptr = (GF_CompositionOffsetBox *)s;

	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->nb_entries = gf_bs_read_u32(bs);

	if (ptr->nb_entries > ptr->size / 8 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(GF_DttsEntry) ) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in ctts\n", ptr->nb_entries));
		return GF_ISOM_INVALID_FILE;
	}

	ptr->alloc_size = ptr->nb_entries;
	ptr->entries = (GF_DttsEntry *)gf_malloc(sizeof(GF_DttsEntry)*ptr->alloc_size);
	if (!ptr->entries) return GF_OUT_OF_MEM;
	sampleCount = 0;
	for (i=0; i<ptr->nb_entries; i++) {
		ISOM_DECREASE_SIZE(ptr, 8);
		ptr->entries[i].sampleCount = gf_bs_read_u32(bs);
		if (ptr->version)
			ptr->entries[i].decodingOffset = gf_bs_read_int(bs, 32);
		else
			ptr->entries[i].decodingOffset = (s32) gf_bs_read_u32(bs);

		if (ptr->max_cts_delta <= ABS(ptr->entries[i].decodingOffset)) {
			ptr->max_cts_delta = ABS(ptr->entries[i].decodingOffset);
			ptr->sample_num_max_cts_delta = sampleCount;
		}
		sampleCount += ptr->entries[i].sampleCount;
	}
#ifndef GPAC_DISABLE_ISOM_WRITE
	ptr->w_LastSampleNumber = sampleCount;
#endif
	return GF_OK;
}

fixed #2092


GF_Err xtra_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_XtraBox *ptr = (GF_XtraBox *)s;
	u32 i, count = gf_list_count(ptr->tags);

	e = gf_isom_box_write_header(s, bs);
	if (e) return e;

	for (i=0; i<count; i++) {
		GF_XtraTag *tag = gf_list_get(ptr->tags, i);
		u32 tag_size = 16;
		u32 name_len = tag->name ? (u32) strlen(tag->name) : 0;
		tag_size += name_len;
		if (tag->prop_value) {
			tag_size += 2 + tag->prop_size;
		}
		gf_bs_write_u32(bs, tag_size);
		gf_bs_write_u32(bs, name_len);
		gf_bs_write_data(bs, tag->name, name_len);
		gf_bs_write_u32(bs, tag->flags);
		gf_bs_write_u32(bs, 6 + tag->prop_size);
		gf_bs_write_u16(bs, tag->prop_type);
		gf_bs_write_data(bs, tag->prop_value, tag->prop_size);
	}
	return GF_OK;

fixed #2092


void trep_box_del(GF_Box *s)
{
	GF_TrackExtensionPropertiesBox *ptr = (GF_TrackExtensionPropertiesBox *)s;
	if (ptr == NULL) return;
	gf_free(ptr);

fixed #2092


GF_Err lsr1_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox *)s;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;

	gf_bs_write_data(bs, ptr->reserved, 6);
	gf_bs_write_u16(bs, ptr->dataReferenceIndex);
	return GF_OK;

fixed #2092


void sdtp_box_del(GF_Box *s)
{
	GF_SampleDependencyTypeBox *ptr = (GF_SampleDependencyTypeBox*)s;
	if (ptr == NULL) return;
	if (ptr->sample_info) gf_free(ptr->sample_info);
	gf_free(ptr);

fixed #2092


GF_Err snro_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_SeqOffHintEntryBox *ptr = (GF_SeqOffHintEntryBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;

	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->SeqOffset);
	return GF_OK;
}

fixed #2092


GF_Err trak_box_size(GF_Box *s)
{
	u32 pos=0;
	GF_TrackBox *ptr = (GF_TrackBox *)s;

	if (ptr->sample_encryption && ptr->sample_encryption->load_needed) {
		if (!ptr->moov || !ptr->moov->mov || !ptr->moov->mov->movieFileMap)
			return GF_ISOM_INVALID_FILE;
		GF_Err e = senc_Parse(ptr->moov->mov->movieFileMap->bs, ptr, NULL, ptr->sample_encryption);
		if (e) return e;
	}

	gf_isom_check_position(s, (GF_Box *)ptr->Header, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->Aperture, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->References, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->editBox, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->Media, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->meta, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->groups, &pos);
	gf_isom_check_position(s, (GF_Box *)ptr->udta, &pos);
	return GF_OK;

fixed #2092


GF_Box *pcrb_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_PcrInfoBox, GF_ISOM_BOX_TYPE_PCRB);
	return (GF_Box *)tmp;

fixed #2092


GF_Err minf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_MediaInformationBox *ptr = (GF_MediaInformationBox *)s;
	switch (a->type) {
	case GF_ISOM_BOX_TYPE_NMHD:
	case GF_ISOM_BOX_TYPE_STHD:
	case GF_ISOM_BOX_TYPE_VMHD:
	case GF_ISOM_BOX_TYPE_SMHD:
	case GF_ISOM_BOX_TYPE_HMHD:
	case GF_ISOM_BOX_TYPE_GMHD:
		BOX_FIELD_ASSIGN(InfoHeader, GF_Box)
		return GF_OK;

	case GF_ISOM_BOX_TYPE_DINF:
		BOX_FIELD_ASSIGN(dataInformation, GF_DataInformationBox)
		return GF_OK;

	case GF_ISOM_BOX_TYPE_STBL:
		BOX_FIELD_ASSIGN(sampleTable, GF_SampleTableBox)
		return GF_OK;
	}
	return GF_OK;
}

fixed #2092


GF_Box *fecr_box_new()
{
	ISOM_DECL_BOX_ALLOC(FECReservoirBox, GF_ISOM_BOX_TYPE_FECR);
	return (GF_Box *)tmp;

fixed #2092


GF_Err npck_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_NPCKBox *ptr = (GF_NPCKBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->nbPackets);
	return GF_OK;
}

fixed #2092


GF_Err udta_box_size(GF_Box *s)
{
	GF_Err e;
	u32 i;
	GF_UserDataMap *map;
	GF_UserDataBox *ptr = (GF_UserDataBox *)s;

	i=0;
	while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
		//warning: here we are not passing the actual "parent" of the list
		//but the UDTA box. The parent itself is not an box, we don't care about it
		e = gf_isom_box_array_size(s, map->boxes);
		if (e) return e;
	}
	return GF_OK;

fixed #2092


GF_Err prhd_box_size(GF_Box *s)
{
	s->size += 12;
	return GF_OK;

fixed #2092


GF_Err gnrm_box_read(GF_Box *s, GF_BitStream *bs)
{
	return GF_OK;
}

fixed #2092


GF_Box *rvcc_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_RVCConfigurationBox, GF_ISOM_BOX_TYPE_RVCC);
	return (GF_Box *)tmp;

fixed #2092


GF_Err hnti_box_read(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_array_read_ex(s, bs, s->type);
}

fixed #2092


GF_Err trun_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *) s;
	if (!s) return GF_BAD_PARAM;

#ifdef GF_ENABLE_CTRN
	if (ptr->use_ctrn)
		return ctrn_box_write(s, bs);
#endif

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u32(bs, ptr->sample_count);

	//The rest depends on the flags
	if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) {
		gf_bs_write_u32(bs, ptr->data_offset);
	}
	if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) {
		gf_bs_write_u32(bs, ptr->first_sample_flags);
	}

	if (ptr->flags & (GF_ISOM_TRUN_DURATION | GF_ISOM_TRUN_SIZE | GF_ISOM_TRUN_FLAGS | GF_ISOM_TRUN_CTS_OFFSET) )  {
		for (i=0; i<ptr->nb_samples; i++) {
			GF_TrunEntry *p = &ptr->samples[i];

			if (ptr->flags & GF_ISOM_TRUN_DURATION) {
				gf_bs_write_u32(bs, p->Duration);
			}
			if (ptr->flags & GF_ISOM_TRUN_SIZE) {
				gf_bs_write_u32(bs, p->size);
			}
			//SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED
			if (ptr->flags & GF_ISOM_TRUN_FLAGS) {
				gf_bs_write_u32(bs, p->flags);
			}
			if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) {
				if (ptr->version==0) {
					gf_bs_write_u32(bs, p->CTS_Offset);
				} else {
					gf_bs_write_u32(bs, (u32) p->CTS_Offset);
				}
			}
		}
	}

	if (ptr->sample_order) {
		u32 nb_bits = 8;
		if (ptr->sample_count>0xFFFFFF) nb_bits = 32;
		else if (ptr->sample_count>0xFFFF) nb_bits = 24;
		else if (ptr->sample_count>0xFF) nb_bits = 16;

		for (i=0; i<ptr->sample_count; i++) {
			gf_bs_write_int(bs, ptr->sample_order[i], nb_bits);
		}
	}
	return GF_OK;

fixed #2092


GF_Err tkhd_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	if (ptr->version == 1) {
		gf_bs_write_u64(bs, ptr->creationTime);
		gf_bs_write_u64(bs, ptr->modificationTime);
		gf_bs_write_u32(bs, ptr->trackID);
		gf_bs_write_u32(bs, ptr->reserved1);
		gf_bs_write_u64(bs, ptr->duration);
	} else {
		gf_bs_write_u32(bs, (u32) ptr->creationTime);
		gf_bs_write_u32(bs, (u32) ptr->modificationTime);
		gf_bs_write_u32(bs, ptr->trackID);
		gf_bs_write_u32(bs, ptr->reserved1);
		gf_bs_write_u32(bs, (u32) ptr->duration);
	}
	gf_bs_write_u32(bs, ptr->reserved2[0]);
	gf_bs_write_u32(bs, ptr->reserved2[1]);
	gf_bs_write_u16(bs, ptr->layer);
	gf_bs_write_u16(bs, ptr->alternate_group);
	gf_bs_write_u16(bs, ptr->volume);
	gf_bs_write_u16(bs, ptr->reserved3);
	gf_bs_write_u32(bs, ptr->matrix[0]);
	gf_bs_write_u32(bs, ptr->matrix[1]);
	gf_bs_write_u32(bs, ptr->matrix[2]);
	gf_bs_write_u32(bs, ptr->matrix[3]);
	gf_bs_write_u32(bs, ptr->matrix[4]);
	gf_bs_write_u32(bs, ptr->matrix[5]);
	gf_bs_write_u32(bs, ptr->matrix[6]);
	gf_bs_write_u32(bs, ptr->matrix[7]);
	gf_bs_write_u32(bs, ptr->matrix[8]);
	gf_bs_write_u32(bs, ptr->width);
	gf_bs_write_u32(bs, ptr->height);
	return GF_OK;
}

fixed #2092


GF_Err fiin_box_size(GF_Box *s)
{
	u32 pos=0;
	FDItemInformationBox *ptr = (FDItemInformationBox *) s;
	s->size+= 2;
	gf_isom_check_position_list(s, ptr->partition_entries, &pos);
	return GF_OK;

fixed #2092


GF_Box *drep_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_DREPBox, GF_ISOM_BOX_TYPE_DREP);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err mvex_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s;

	switch (a->type) {
	case GF_ISOM_BOX_TYPE_TREX:
		BOX_FIELD_LIST_ASSIGN(TrackExList)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_TREP:
		BOX_FIELD_LIST_ASSIGN(TrackExPropList)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_MEHD:
		BOX_FIELD_ASSIGN(mehd, GF_MovieExtendsHeaderBox)
		return GF_OK;
	}
	return GF_OK;
}

fixed #2092


GF_Err pcrb_box_size(GF_Box *s)
{
	GF_PcrInfoBox *ptr = (GF_PcrInfoBox*) s;

	ptr->size += 4;
	ptr->size += ptr->subsegment_count * 6;

	return GF_OK;

fixed #2092


GF_Err lsr1_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_LASeRSampleEntryBox *ptr = (GF_LASeRSampleEntryBox*)s;

	e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
	if (e) return e;

	ISOM_DECREASE_SIZE(ptr, 8);

	return gf_isom_box_array_read(s, bs);

fixed #2092


}
static u32 ctrn_read_flags(GF_BitStream *bs, u32 nbbits)
{
	u32 val = gf_bs_read_int(bs, nbbits);
	if (nbbits==16) val <<= 16;
	else if (nbbits==8) val <<= 24;
	return val;

fixed #2092


GF_Err smhd_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_SoundMediaHeaderBox *ptr = (GF_SoundMediaHeaderBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->balance = gf_bs_read_u16(bs);
	ptr->reserved = gf_bs_read_u16(bs);
	return GF_OK;
}

fixed #2092


GF_Err free_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 bytesToRead;
	GF_FreeSpaceBox *ptr = (GF_FreeSpaceBox *)s;

	if (ptr->size > 0xFFFFFFFF) return GF_IO_ERR;

	bytesToRead = (u32) (ptr->size);

	if (bytesToRead) {
		ptr->data = (char*)gf_malloc(bytesToRead * sizeof(char));
		if (!ptr->data) return GF_OUT_OF_MEM;
		gf_bs_read_data(bs, ptr->data, bytesToRead);
		ptr->dataSize = bytesToRead;
	}
	return GF_OK;
}

fixed #2092


GF_Err traf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s;

	switch (a->type) {
	case GF_ISOM_BOX_TYPE_TFHD:
		BOX_FIELD_ASSIGN(tfhd, GF_TrackFragmentHeaderBox)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_TRUN:
		BOX_FIELD_LIST_ASSIGN(TrackRuns)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_SDTP:
		BOX_FIELD_ASSIGN(sdtp, GF_SampleDependencyTypeBox)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_TFDT:
		BOX_FIELD_ASSIGN(tfdt, GF_TFBaseMediaDecodeTimeBox)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_SUBS:
		BOX_FIELD_LIST_ASSIGN(sub_samples)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_SBGP:
	case GF_ISOM_BOX_TYPE_CSGP:
		BOX_FIELD_LIST_ASSIGN(sampleGroups)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_SGPD:
		BOX_FIELD_LIST_ASSIGN(sampleGroupsDescription)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_SAIZ:
		BOX_FIELD_LIST_ASSIGN(sai_sizes)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_SAIO:
		BOX_FIELD_LIST_ASSIGN(sai_offsets)
		return GF_OK;
	//we will throw an error if both PIFF_PSEC and SENC are found. Not such files seen yet
	case GF_ISOM_BOX_TYPE_UUID:
		if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_PSEC) {
			BOX_FIELD_ASSIGN(sample_encryption, GF_SampleEncryptionBox)
			if (!is_rem)
				ptr->sample_encryption->traf = ptr;
			return GF_OK;
		} else if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_TFXD) {
			BOX_FIELD_ASSIGN(tfxd, GF_MSSTimeExtBox)
			return GF_OK;
		} else if ( ((GF_UUIDBox *)a)->internal_4cc==GF_ISOM_BOX_UUID_TFRF) {
			BOX_FIELD_ASSIGN(tfrf, GF_MSSTimeRefBox)
			return GF_OK;
		} else {
			return GF_OK;
		}
	case GF_ISOM_BOX_TYPE_SENC:
		BOX_FIELD_ASSIGN(sample_encryption, GF_SampleEncryptionBox)
		if (!is_rem)
			ptr->sample_encryption->traf = ptr;
		return GF_OK;
	}
	return GF_OK;
}

fixed #2092


GF_Err tkhd_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TrackHeaderBox *ptr = (GF_TrackHeaderBox *)s;

	if (ptr->version == 1) {
		ISOM_DECREASE_SIZE(ptr, 32);
		ptr->creationTime = gf_bs_read_u64(bs);
		ptr->modificationTime = gf_bs_read_u64(bs);
		ptr->trackID = gf_bs_read_u32(bs);
		ptr->reserved1 = gf_bs_read_u32(bs);
		ptr->duration = gf_bs_read_u64(bs);
	} else {
		ISOM_DECREASE_SIZE(ptr, 20);
		ptr->creationTime = gf_bs_read_u32(bs);
		ptr->modificationTime = gf_bs_read_u32(bs);
		ptr->trackID = gf_bs_read_u32(bs);
		ptr->reserved1 = gf_bs_read_u32(bs);
		ptr->duration = gf_bs_read_u32(bs);
	}
	ptr->initial_duration = ptr->duration;

	ISOM_DECREASE_SIZE(ptr, 60);
	ptr->reserved2[0] = gf_bs_read_u32(bs);
	ptr->reserved2[1] = gf_bs_read_u32(bs);
	ptr->layer = gf_bs_read_u16(bs);
	ptr->alternate_group = gf_bs_read_u16(bs);
	ptr->volume = gf_bs_read_u16(bs);
	ptr->reserved3 = gf_bs_read_u16(bs);
	ptr->matrix[0] = gf_bs_read_u32(bs);
	ptr->matrix[1] = gf_bs_read_u32(bs);
	ptr->matrix[2] = gf_bs_read_u32(bs);
	ptr->matrix[3] = gf_bs_read_u32(bs);
	ptr->matrix[4] = gf_bs_read_u32(bs);
	ptr->matrix[5] = gf_bs_read_u32(bs);
	ptr->matrix[6] = gf_bs_read_u32(bs);
	ptr->matrix[7] = gf_bs_read_u32(bs);
	ptr->matrix[8] = gf_bs_read_u32(bs);
	ptr->width = gf_bs_read_u32(bs);
	ptr->height = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #2092


}
static u32 ctrn_s32_to_index(s32 val)
{
	if (!val) return 0;
	if (ABS(val)<=127) return 1;
	if (ABS(val)<=32767) return 2;
	return 3;

fixed #2092


GF_Err udta_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_UserDataMap *map;
	GF_UserDataBox *ptr = (GF_UserDataBox *)s;

	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	i=0;
	while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
		//warning: here we are not passing the actual "parent" of the list
		//but the UDTA box. The parent itself is not an box, we don't care about it
		e = gf_isom_box_array_write(s, map->boxes, bs);
		if (e) return e;
	}
	return GF_OK;

fixed #2092


GF_Err jp2h_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_J2KHeaderBox *ptr = (GF_J2KHeaderBox *)s;
	switch(a->type) {
	case GF_ISOM_BOX_TYPE_IHDR:
		BOX_FIELD_ASSIGN(ihdr, GF_J2KImageHeaderBox)
		return GF_OK;
	case GF_ISOM_BOX_TYPE_COLR:
		BOX_FIELD_ASSIGN(colr, GF_ColourInformationBox)
		return GF_OK;
	}
	return GF_OK;

fixed #2092


GF_Err segr_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i, k;
	FDSessionGroupBox *ptr = (FDSessionGroupBox *)s;

	ISOM_DECREASE_SIZE(ptr, 2);
	ptr->num_session_groups = gf_bs_read_u16(bs);
	if (ptr->size < ptr->num_session_groups) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of entries %d in segr\n", ptr->num_session_groups));
		ptr->num_session_groups = 0;
		return GF_ISOM_INVALID_FILE;
	}

	GF_SAFE_ALLOC_N(ptr->session_groups, ptr->num_session_groups, SessionGroupEntry);
	if (!ptr->session_groups) return GF_OUT_OF_MEM;

	for (i=0; i<ptr->num_session_groups; i++) {
		ptr->session_groups[i].nb_groups = gf_bs_read_u8(bs);
		ISOM_DECREASE_SIZE(ptr, 1);

		ISOM_DECREASE_SIZE(ptr, ptr->session_groups[i].nb_groups*4);

		GF_SAFE_ALLOC_N(ptr->session_groups[i].group_ids, ptr->session_groups[i].nb_groups, u32);
		if (!ptr->session_groups[i].group_ids) return GF_OUT_OF_MEM;

		for (k=0; k<ptr->session_groups[i].nb_groups; k++) {
			ptr->session_groups[i].group_ids[k] = gf_bs_read_u32(bs);
		}

		ptr->session_groups[i].nb_channels = gf_bs_read_u16(bs);
		ISOM_DECREASE_SIZE(ptr, ptr->session_groups[i].nb_channels*4);

		GF_SAFE_ALLOC_N(ptr->session_groups[i].channels, ptr->session_groups[i].nb_channels, u32);
		if (!ptr->session_groups[i].channels) return GF_OUT_OF_MEM;

		for (k=0; k<ptr->session_groups[i].nb_channels; k++) {
			ptr->session_groups[i].channels[k] = gf_bs_read_u32(bs);
		}
	}
	return GF_OK;

fixed #2092


GF_Err pmax_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_PMAXBox *ptr = (GF_PMAXBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->maxSize);
	return GF_OK;
}

fixed #2092


GF_Err dinf_on_child_box(GF_Box *s, GF_Box *a, Bool is_rem)
{
	GF_DataInformationBox *ptr = (GF_DataInformationBox *)s;
	switch(a->type) {
	case GF_ISOM_BOX_TYPE_DREF:
		BOX_FIELD_ASSIGN(dref, GF_DataReferenceBox)
		return GF_OK;
	}
	return GF_OK;
}

fixed #2092


GF_Err tfxd_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_MSSTimeExtBox *ptr = (GF_MSSTimeExtBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->version = gf_bs_read_u8(bs);
	ptr->flags = gf_bs_read_u24(bs);

	if (ptr->version == 0x01) {
		ISOM_DECREASE_SIZE(ptr, 16);
		ptr->absolute_time_in_track_timescale = gf_bs_read_u64(bs);
		ptr->fragment_duration_in_track_timescale = gf_bs_read_u64(bs);
	} else {
		ISOM_DECREASE_SIZE(ptr, 8);
		ptr->absolute_time_in_track_timescale = gf_bs_read_u32(bs);
		ptr->fragment_duration_in_track_timescale = gf_bs_read_u32(bs);
	}

	return GF_OK;
}

fixed #2092


GF_Err tmin_box_size(GF_Box *s)
{
	s->size += 4;
	return GF_OK;
}

fixed #2092


GF_Err trex_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_TrackExtendsBox *ptr = (GF_TrackExtendsBox *) s;
	if (!s) return GF_BAD_PARAM;
	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u32(bs, ptr->trackID);
	//we always write 1 in trex default sample desc as using 0 breaks chrome/opera/...
	gf_bs_write_u32(bs, ptr->def_sample_desc_index ? ptr->def_sample_desc_index : 1);
	gf_bs_write_u32(bs, ptr->def_sample_duration);
	gf_bs_write_u32(bs, ptr->def_sample_size);
	gf_bs_write_u32(bs, ptr->def_sample_flags);
	return GF_OK;

fixed #2092


GF_Err iods_box_size(GF_Box *s)
{
	GF_ObjectDescriptorBox *ptr = (GF_ObjectDescriptorBox *)s;

	ptr->size += gf_odf_desc_size(ptr->descriptor);
	return GF_OK;
}

fixed #2092


GF_Err trun_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i;
	GF_TrackFragmentRunBox *ptr = (GF_TrackFragmentRunBox *)s;

#ifdef GF_ENABLE_CTRN
	if (ptr->type == GF_ISOM_BOX_TYPE_CTRN) {
		ptr->type = GF_ISOM_BOX_TYPE_TRUN;
		ptr->use_ctrn = GF_TRUE;
		return ctrn_box_read(s, bs);
	}
#endif

	//check this is a good file
	if ((ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) && (ptr->flags & GF_ISOM_TRUN_FLAGS))
		return GF_ISOM_INVALID_FILE;

	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->sample_count = gf_bs_read_u32(bs);

	//The rest depends on the flags
	if (ptr->flags & GF_ISOM_TRUN_DATA_OFFSET) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->data_offset = gf_bs_read_u32(bs);
	}
	if (ptr->flags & GF_ISOM_TRUN_FIRST_FLAG) {
		ISOM_DECREASE_SIZE(ptr, 4);
		ptr->first_sample_flags = gf_bs_read_u32(bs);
	}
	if (! (ptr->flags & (GF_ISOM_TRUN_DURATION | GF_ISOM_TRUN_SIZE | GF_ISOM_TRUN_FLAGS | GF_ISOM_TRUN_CTS_OFFSET) ) ) {
		ptr->samples = gf_malloc(sizeof(GF_TrunEntry));
		if (!ptr->samples) return GF_OUT_OF_MEM;
		//memset to 0 !!
		memset(ptr->samples, 0, sizeof(GF_TrunEntry));
		ptr->sample_alloc = ptr->nb_samples = 1;
		ptr->samples[0].nb_pack = ptr->sample_count;
	} else {
		//if we get here, at least one flag (so at least 4 bytes) is set, check size
		if (ptr->sample_count * 4 > ptr->size) {
			ISOM_DECREASE_SIZE(ptr, ptr->sample_count*4);
		}
		if ((u64)ptr->sample_count > (u64)SIZE_MAX/sizeof(GF_TrunEntry)) {
			GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid number of samples %d in trun\n", ptr->sample_count));
			return GF_ISOM_INVALID_FILE;
		}
		ptr->samples = gf_malloc(sizeof(GF_TrunEntry) * ptr->sample_count);
		if (!ptr->samples) return GF_OUT_OF_MEM;
		ptr->sample_alloc = ptr->nb_samples = ptr->sample_count;
		//memset to 0 upfront
		memset(ptr->samples, 0, ptr->sample_count * sizeof(GF_TrunEntry));

		//read each entry (even though nothing may be written)
		for (i=0; i<ptr->sample_count; i++) {
			u32 trun_size = 0;
			GF_TrunEntry *p = &ptr->samples[i];

			if (ptr->flags & GF_ISOM_TRUN_DURATION) {
				p->Duration = gf_bs_read_u32(bs);
				trun_size += 4;
			}
			if (ptr->flags & GF_ISOM_TRUN_SIZE) {
				p->size = gf_bs_read_u32(bs);
				trun_size += 4;
			}
			//SHOULDN'T BE USED IF GF_ISOM_TRUN_FIRST_FLAG IS DEFINED
			if (ptr->flags & GF_ISOM_TRUN_FLAGS) {
				p->flags = gf_bs_read_u32(bs);
				trun_size += 4;
			}
			if (ptr->flags & GF_ISOM_TRUN_CTS_OFFSET) {
				if (ptr->version==0) {
					p->CTS_Offset = (u32) gf_bs_read_u32(bs);
				} else {
					p->CTS_Offset = (s32) gf_bs_read_u32(bs);
				}
				trun_size += 4;
			}
			ISOM_DECREASE_SIZE(ptr, trun_size);
		}
	}
	/*todo parse sample reorder*/
	if (ptr->size) {
		gf_bs_skip_bytes(bs, ptr->size);
		ptr->size = 0;
	}
	return GF_OK;

fixed #2092


void audio_sample_entry_box_del(GF_Box *s)
{
	GF_MPEGAudioSampleEntryBox *ptr = (GF_MPEGAudioSampleEntryBox *)s;
	if (ptr == NULL) return;
	gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)s);
	if (ptr->slc) gf_odf_desc_del((GF_Descriptor *)ptr->slc);
	gf_free(ptr);
}

fixed #2092


GF_Err tpyl_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_NTYLBox *ptr = (GF_NTYLBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u64(bs, ptr->nbBytes);
	return GF_OK;
}

fixed #2092


GF_Box *mhac_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_MHAConfigBox, GF_ISOM_BOX_TYPE_MHAC);
	tmp->configuration_version = 1;
	return (GF_Box *)tmp;

fixed #2092


GF_Err sdp_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_SDPBox *ptr = (GF_SDPBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	//don't write the NULL char!!!
	if (ptr->sdpText)
		gf_bs_write_data(bs, ptr->sdpText, (u32) strlen(ptr->sdpText));
	return GF_OK;
}

fixed #2092


void gnrv_box_del(GF_Box *s)
{
	GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s;
	gf_isom_sample_entry_predestroy((GF_SampleEntryBox *)ptr);
	if (ptr->data) gf_free(ptr->data);
	gf_free(ptr);
}

fixed #2092


GF_UserDataMap *udta_getEntry(GF_UserDataBox *ptr, u32 box_type, bin128 *uuid)
{
	u32 i;
	GF_UserDataMap *map;
	if (ptr == NULL) return NULL;
	i=0;
	while ((map = (GF_UserDataMap *)gf_list_enum(ptr->recordList, &i))) {
		if (map->boxType == box_type) {
			if ((box_type != GF_ISOM_BOX_TYPE_UUID) || !uuid) return map;
			if (!memcmp(map->uuid, *uuid, 16)) return map;
		}
	}
	return NULL;

fixed #2092


GF_Box *segr_box_new()
{
	ISOM_DECL_BOX_ALLOC(FDSessionGroupBox, GF_ISOM_BOX_TYPE_SEGR);
	return (GF_Box *)tmp;

fixed #2092


GF_Box *stri_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_SubTrackInformationBox, GF_ISOM_BOX_TYPE_STRI);
	return (GF_Box *)tmp;

fixed #2092


GF_Err fecr_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	FECReservoirBox *ptr = (FECReservoirBox *) s;
	if (!s) return GF_BAD_PARAM;
	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_int(bs, ptr->nb_entries, ptr->version ? 32 : 16);
	for (i=0; i<ptr->nb_entries; i++) {
		gf_bs_write_int(bs, ptr->entries[i].item_id, ptr->version ? 32 : 16);
		gf_bs_write_u32(bs, ptr->entries[i].symbol_count);
	}
	return GF_OK;

fixed #2092


GF_Box *csgp_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_CompactSampleGroupBox, GF_ISOM_BOX_TYPE_CSGP);
	return (GF_Box *)tmp;

fixed #2092


GF_Err gen_sample_entry_box_size(GF_Box *s)
{
	GF_SampleEntryBox *ptr = (GF_SampleEntryBox *)s;
	ptr->size += 8;
	return GF_OK;
}

fixed #2092


GF_Err fdpa_box_size(GF_Box *s)
{
	u32 i;
	GF_FDpacketBox *ptr = (GF_FDpacketBox *)s;

	ptr->size += 5;

	for (i=0; i<ptr->header_ext_count; i++) {
		ptr->size += 1;
		if (ptr->headers[i].header_extension_type > 127) {
			ptr->size += 3;
		} else {
			ptr->size += 1 + ptr->headers[i].data_length;
		}
	}
	return GF_OK;

fixed #2092


void tfxd_box_del(GF_Box *s)
{
	gf_free(s);
}

fixed #2092


GF_Box *tsro_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_TimeOffHintEntryBox, GF_ISOM_BOX_TYPE_TSRO);
	return (GF_Box *)tmp;

fixed #2092


GF_Err trik_box_read(GF_Box *s,GF_BitStream *bs)
{
	u32 i;
	GF_TrickPlayBox *ptr = (GF_TrickPlayBox *) s;
	ptr->entry_count = (u32) ptr->size;
	if ((u64)ptr->entry_count > (u64)SIZE_MAX/sizeof(GF_TrickPlayBoxEntry)) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Invalid size %llu in trik\n", ptr->size));
		return GF_ISOM_INVALID_FILE;
	}
	ptr->entries = (GF_TrickPlayBoxEntry *) gf_malloc(ptr->entry_count * sizeof(GF_TrickPlayBoxEntry) );
	if (!ptr->entries) return GF_OUT_OF_MEM;

	for (i=0; i< ptr->entry_count; i++) {
		ptr->entries[i].pic_type = gf_bs_read_int(bs, 2);
		ptr->entries[i].dependency_level = gf_bs_read_int(bs, 6);
	}
	return GF_OK;

fixed #2092


GF_Err void_box_read(GF_Box *s, GF_BitStream *bs)
{
	if (s->size) return GF_ISOM_INVALID_FILE;
	return GF_OK;

fixed #2092


void moof_box_del(GF_Box *s)
{
	GF_MovieFragmentBox *ptr = (GF_MovieFragmentBox *)s;
	if (ptr == NULL) return;

	gf_list_del(ptr->TrackList);
	if (ptr->PSSHs) gf_list_del(ptr->PSSHs);
	if (ptr->mdat) gf_free(ptr->mdat);
	gf_free(ptr);
}

fixed #2092


GF_Err strk_box_write(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_write_header(s, bs);

fixed #2092


GF_Box *unkn_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_UnknownBox, GF_ISOM_BOX_TYPE_UNKNOWN);
	return (GF_Box *) tmp;
}

fixed #2092


GF_Err emsg_box_read(GF_Box *s,GF_BitStream *bs)
{
	GF_Err e;
	GF_EventMessageBox *ptr = (GF_EventMessageBox*) s;

	if (ptr->version==0) {
		e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_id_uri);
		if (e) return e;
		e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->value);
		if (e) return e;

		ISOM_DECREASE_SIZE(ptr, 16);
		ptr->timescale = gf_bs_read_u32(bs);
		ptr->presentation_time_delta = gf_bs_read_u32(bs);
		ptr->event_duration = gf_bs_read_u32(bs);
		ptr->event_id = gf_bs_read_u32(bs);
	} else if (ptr->version==1) {
		ISOM_DECREASE_SIZE(ptr, 20);
		ptr->timescale = gf_bs_read_u32(bs);
		ptr->presentation_time_delta = gf_bs_read_u64(bs);
		ptr->event_duration = gf_bs_read_u32(bs);
		ptr->event_id = gf_bs_read_u32(bs);

		e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_id_uri);
		if (e) return e;
		e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->value);
		if (e) return e;
	} else {
		return GF_OK;
	}
	if (ptr->size) {
		if (ptr->size>0xFFFFFFFUL) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[IsoMedia] emsg message data size too big ("LLU") to be loaded\n", ptr->size));
			return GF_OUT_OF_MEM;
		}
		ptr->message_data_size = (u32) ptr->size;
		ptr->message_data = gf_malloc(ptr->message_data_size);
		if (!ptr->message_data) return GF_OUT_OF_MEM;
		gf_bs_read_data(bs, ptr->message_data, ptr->message_data_size);
		ptr->size = 0;
	}
	return GF_OK;

fixed #2092


GF_Err def_parent_full_box_size(GF_Box *s)
{
	return GF_OK;
}

fixed #2092


GF_Err padb_box_size(GF_Box *s)
{
	GF_PaddingBitsBox *ptr = (GF_PaddingBitsBox *)s;
	ptr->size += 4;
	if (ptr->SampleCount) ptr->size += (ptr->SampleCount + 1) / 2;

	return GF_OK;
}

fixed #2092


GF_Err stts_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->nb_entries);
	for (i=0; i<ptr->nb_entries; i++) {
		gf_bs_write_u32(bs, ptr->entries[i].sampleCount);
		gf_bs_write_u32(bs, ptr->entries[i].sampleDelta);
	}
	return GF_OK;
}

fixed #2092


GF_Err proj_type_box_size(GF_Box *s)
{
	GF_ProjectionTypeBox *ptr = (GF_ProjectionTypeBox *)s;
	if (ptr->type==GF_ISOM_BOX_TYPE_CBMP)
		s->size += 8;
	else if (ptr->type==GF_ISOM_BOX_TYPE_EQUI)
		s->size += 16;
	else
		s->size += 8;

	return GF_OK;

fixed #2092


GF_Box *ainf_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_AssetInformationBox, GF_ISOM_BOX_TYPE_AINF);
	return (GF_Box *)tmp;

fixed #2092


GF_Err moof_box_write(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_write_header(s, bs);
}

fixed #2092


GF_Err saiz_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_SampleAuxiliaryInfoSizeBox*ptr = (GF_SampleAuxiliaryInfoSizeBox*)s;

	if (ptr->flags & 1) {
		ISOM_DECREASE_SIZE(ptr, 8);
		ptr->aux_info_type = gf_bs_read_u32(bs);
		ptr->aux_info_type_parameter = gf_bs_read_u32(bs);
	}
	ISOM_DECREASE_SIZE(ptr, 5);
	ptr->default_sample_info_size = gf_bs_read_u8(bs);
	ptr->sample_count = gf_bs_read_u32(bs);

	if (ptr->default_sample_info_size == 0) {
		if (ptr->size < ptr->sample_count)
		    return GF_ISOM_INVALID_FILE;

		ptr->sample_info_size = gf_malloc(sizeof(u8)*ptr->sample_count);
		ptr->sample_alloc = ptr->sample_count;
		if (!ptr->sample_info_size)
		    return GF_OUT_OF_MEM;

		ISOM_DECREASE_SIZE(ptr, ptr->sample_count);
		gf_bs_read_data(bs, (char *) ptr->sample_info_size, ptr->sample_count);
	}
	return GF_OK;

fixed #2092


GF_Err unkn_box_size(GF_Box *s)
{
	GF_UnknownBox *ptr = (GF_UnknownBox *)s;

	if (ptr->dataSize && ptr->data) {
		ptr->size += ptr->dataSize;
	}
	return GF_OK;
}

fixed #2092


GF_Err npck_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_NPCKBox *ptr = (GF_NPCKBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->nbPackets = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #2092


GF_Err fpar_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i;
	GF_Err e;
	FilePartitionBox *ptr = (FilePartitionBox *)s;

	ISOM_DECREASE_SIZE(ptr, ((ptr->version ? 4 : 2) + 12) );
	ptr->itemID = gf_bs_read_int(bs, ptr->version ? 32 : 16);
	ptr->packet_payload_size = gf_bs_read_u16(bs);
	gf_bs_read_u8(bs);
	ptr->FEC_encoding_ID = gf_bs_read_u8(bs);
	ptr->FEC_instance_ID = gf_bs_read_u16(bs);
	ptr->max_source_block_length = gf_bs_read_u16(bs);
	ptr->encoding_symbol_length = gf_bs_read_u16(bs);
	ptr->max_number_of_encoding_symbols = gf_bs_read_u16(bs);

	e = gf_isom_read_null_terminated_string(s, bs, ptr->size, &ptr->scheme_specific_info);
	if (e) return e;

	ISOM_DECREASE_SIZE(ptr, (ptr->version ? 4 : 2) );
	ptr->nb_entries = gf_bs_read_int(bs, ptr->version ? 32 : 16);
	if (ptr->nb_entries > ptr->size / 6 || (u64)ptr->nb_entries > (u64)SIZE_MAX/sizeof(FilePartitionEntry))
		return GF_ISOM_INVALID_FILE;

	ISOM_DECREASE_SIZE(ptr, ptr->nb_entries * 6 );
	GF_SAFE_ALLOC_N(ptr->entries, ptr->nb_entries, FilePartitionEntry);
	if (!ptr->entries) return GF_OUT_OF_MEM;

	for (i=0;i < ptr->nb_entries; i++) {
		ptr->entries[i].block_count = gf_bs_read_u16(bs);
		ptr->entries[i].block_size = gf_bs_read_u32(bs);
	}
	return GF_OK;

fixed #2092


void jp2h_box_del(GF_Box *s)
{
	gf_free(s);

fixed #2092


GF_Err gnrv_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_GenericVisualSampleEntryBox *ptr = (GF_GenericVisualSampleEntryBox *)s;

	//careful we are not writing the box type but the entry type so switch for write
	ptr->type = ptr->EntryType;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	ptr->type = GF_ISOM_BOX_TYPE_GNRV;

	gf_isom_video_sample_entry_write((GF_VisualSampleEntryBox *)ptr, bs);
	gf_bs_write_data(bs,  ptr->data, ptr->data_size);
	return GF_OK;
}

fixed #2092


GF_Err chnl_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_ChannelLayoutBox *ptr = (GF_ChannelLayoutBox *) s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u8(bs, ptr->layout.stream_structure);
	if (ptr->layout.stream_structure & 1) {
		gf_bs_write_u8(bs, ptr->layout.definedLayout);
		if (ptr->layout.definedLayout==0) {
			u32 i;
			for (i=0; i<ptr->layout.channels_count; i++) {
				gf_bs_write_u8(bs, ptr->layout.layouts[i].position);
				if (ptr->layout.layouts[i].position==126) {
					gf_bs_write_int(bs, ptr->layout.layouts[i].azimuth, 16);
					gf_bs_write_int(bs, ptr->layout.layouts[i].elevation, 8);
				}
			}
		} else {
			gf_bs_write_u64(bs, ptr->layout.omittedChannelsMap);
		}
	}
	if (ptr->layout.stream_structure & 2) {
		gf_bs_write_u8(bs, ptr->layout.object_count);
	}
	return GF_OK;

fixed #2092


GF_Box *gnrv_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_GenericVisualSampleEntryBox, GF_ISOM_BOX_TYPE_GNRV);
	gf_isom_video_sample_entry_init((GF_VisualSampleEntryBox*) tmp);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err sidx_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_SegmentIndexBox *ptr = (GF_SegmentIndexBox*) s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	gf_bs_write_u32(bs, ptr->reference_ID);
	gf_bs_write_u32(bs, ptr->timescale);
	if (ptr->version==0) {
		gf_bs_write_u32(bs, (u32) ptr->earliest_presentation_time);
		gf_bs_write_u32(bs, (u32) ptr->first_offset);
	} else {
		gf_bs_write_u64(bs, ptr->earliest_presentation_time);
		gf_bs_write_u64(bs, ptr->first_offset);
	}
	gf_bs_write_u16(bs, 0);
	gf_bs_write_u16(bs, ptr->nb_refs);
	for (i=0; i<ptr->nb_refs; i++ ) {
		gf_bs_write_int(bs, ptr->refs[i].reference_type, 1);
		gf_bs_write_int(bs, ptr->refs[i].reference_size, 31);
		gf_bs_write_u32(bs, ptr->refs[i].subsegment_duration);
		gf_bs_write_int(bs, ptr->refs[i].starts_with_SAP, 1);
		gf_bs_write_int(bs, ptr->refs[i].SAP_type, 3);
		gf_bs_write_int(bs, ptr->refs[i].SAP_delta_time, 28);
	}
	return GF_OK;

fixed #2092


GF_Box *jp2h_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_J2KHeaderBox, GF_ISOM_BOX_TYPE_JP2H);
	return (GF_Box *)tmp;

fixed #2092


GF_Err co64_box_size(GF_Box *s)
{
	GF_ChunkLargeOffsetBox *ptr = (GF_ChunkLargeOffsetBox *) s;

	ptr->size += 4 + (8 * ptr->nb_entries);
	return GF_OK;
}

fixed #2092


GF_Box *vmhd_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_VideoMediaHeaderBox, GF_ISOM_BOX_TYPE_VMHD);
	tmp->flags = 1;
	return (GF_Box *)tmp;

fixed #2092


void clap_box_del(GF_Box *s)
{
	GF_CleanApertureBox *ptr = (GF_CleanApertureBox*)s;
	if (ptr == NULL) return;
	gf_free(ptr);

fixed #2092


GF_Err saio_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox *)s;

	if (ptr->flags & 1) {
		ISOM_DECREASE_SIZE(ptr, 8);
		ptr->aux_info_type = gf_bs_read_u32(bs);
		ptr->aux_info_type_parameter = gf_bs_read_u32(bs);
	}
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->entry_count = gf_bs_read_u32(bs);

	if (ptr->entry_count) {
		u32 i;
		if (ptr->size / (ptr->version == 0 ? 4 : 8) < ptr->entry_count || (u64)ptr->entry_count > (u64)SIZE_MAX/sizeof(u64))
			return GF_ISOM_INVALID_FILE;
		ptr->offsets = gf_malloc(sizeof(u64)*ptr->entry_count);
		if (!ptr->offsets)
			return GF_OUT_OF_MEM;
		ptr->entry_alloc = ptr->entry_count;
		if (ptr->version==0) {
			ISOM_DECREASE_SIZE(ptr, 4*ptr->entry_count);
			for (i=0; i<ptr->entry_count; i++)
				ptr->offsets[i] = gf_bs_read_u32(bs);
		} else {
			ISOM_DECREASE_SIZE(ptr, 8*ptr->entry_count);
			for (i=0; i<ptr->entry_count; i++)
				ptr->offsets[i] = gf_bs_read_u64(bs);
		}
	}
	return GF_OK;

fixed #2092


void pmax_box_del(GF_Box *s)
{
	gf_free((GF_PMAXBox *)s);
}

fixed #2092


GF_Err dvvC_box_size(GF_Box *s)
{
	return dvcC_box_size(s);

fixed #2092


GF_Box *pcmC_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_PCMConfigBox, GF_ISOM_BOX_TYPE_PCMC);
	return (GF_Box *)tmp;

fixed #2092


GF_Err saio_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_SampleAuxiliaryInfoOffsetBox *ptr = (GF_SampleAuxiliaryInfoOffsetBox *) s;
	if (!s) return GF_BAD_PARAM;
	e = gf_isom_full_box_write(s, bs);
	if (e) return e;

	if (ptr->flags & 1) {
		gf_bs_write_u32(bs, ptr->aux_info_type);
		gf_bs_write_u32(bs, ptr->aux_info_type_parameter);
	}

	gf_bs_write_u32(bs, ptr->entry_count);
	if (ptr->entry_count) {
		u32 i;
		//store position in bitstream before writing data - offsets can be NULL if a single offset is rewritten later on (cf senc_box_write)
		ptr->offset_first_offset_field = gf_bs_get_position(bs);
		if (ptr->version==0) {
			if (!ptr->offsets) {
				gf_bs_write_u32(bs, 0);
			} else {
				for (i=0; i<ptr->entry_count; i++)
					gf_bs_write_u32(bs, (u32) ptr->offsets[i]);
			}
		} else {
			if (!ptr->offsets) {
				gf_bs_write_u64(bs, 0);
			} else {
				for (i=0; i<ptr->entry_count; i++)
					gf_bs_write_u64(bs, ptr->offsets[i]);
			}
		}
	}
	return GF_OK;

fixed #2092


void esds_box_del(GF_Box *s)
{
	GF_ESDBox *ptr = (GF_ESDBox *)s;
	if (ptr == NULL)	return;
	if (ptr->desc) gf_odf_desc_del((GF_Descriptor *)ptr->desc);
	gf_free(ptr);
}

fixed #2092


GF_Err snro_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_SeqOffHintEntryBox *ptr = (GF_SeqOffHintEntryBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->SeqOffset = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #2092


void stss_box_del(GF_Box *s)
{
	GF_SyncSampleBox *ptr = (GF_SyncSampleBox *)s;
	if (ptr == NULL) return;
	if (ptr->sampleNumbers) gf_free(ptr->sampleNumbers);
	gf_free(ptr);
}

fixed #2092


GF_Err stts_box_size(GF_Box *s)
{
	GF_TimeToSampleBox *ptr = (GF_TimeToSampleBox *)s;
	ptr->size += 4 + (8 * ptr->nb_entries);
	return GF_OK;
}

fixed #2092


GF_Err totl_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TOTLBox *ptr = (GF_TOTLBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->nbBytes = gf_bs_read_u32(bs);
	return GF_OK;
}

fixed #2092


GF_Err ihdr_box_read(GF_Box *s,GF_BitStream *bs)
{
	GF_J2KImageHeaderBox *ptr = (GF_J2KImageHeaderBox *) s;

	ISOM_DECREASE_SIZE(s, 14)

	ptr->height = gf_bs_read_u32(bs);
	ptr->width = gf_bs_read_u32(bs);
	ptr->nb_comp = gf_bs_read_u16(bs);
	ptr->bpc = gf_bs_read_u8(bs);
	ptr->Comp = gf_bs_read_u8(bs);
	ptr->UnkC = gf_bs_read_u8(bs);
	ptr->IPR = gf_bs_read_u8(bs);

	return GF_OK;

fixed #2092


void def_parent_full_box_del(GF_Box *s)
{
	if (s) gf_free(s);
}

fixed #2092


void fiin_box_del(GF_Box *s)
{
	FDItemInformationBox *ptr = (FDItemInformationBox *)s;
	if (ptr == NULL) return;
	if (ptr->partition_entries) gf_list_del(ptr->partition_entries);
	gf_free(ptr);

fixed #2092


void prhd_box_del(GF_Box *s)
{
	gf_free(s);

fixed #2092


GF_Err mdat_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_MediaDataBox *ptr = (GF_MediaDataBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;

	ptr->dataSize = s->size;
	ptr->bsOffset = gf_bs_get_position(bs);

	//store idat for rewrite
	if (ptr->type==GF_ISOM_BOX_TYPE_IDAT) {
		ptr->data = gf_malloc(sizeof(u8) * (size_t)ptr->dataSize);
		if (!ptr->data) return GF_OUT_OF_MEM;
		gf_bs_read_data(bs, ptr->data, (u32) ptr->dataSize);
		ptr->size = 0;
		return GF_OK;
	}

	//then skip these bytes
	gf_bs_skip_bytes(bs, ptr->dataSize);
	return GF_OK;
}

fixed #2092


void hdlr_box_del(GF_Box *s)
{
	GF_HandlerBox *ptr = (GF_HandlerBox *)s;
	if (ptr == NULL) return;
	if (ptr->nameUTF8) gf_free(ptr->nameUTF8);
	gf_free(ptr);
}

fixed #2092


void traf_box_del(GF_Box *s)
{
	GF_TrackFragmentBox *ptr = (GF_TrackFragmentBox *)s;
	if (ptr == NULL) return;
	if (ptr->sub_samples) gf_list_del(ptr->sub_samples);
	gf_list_del(ptr->TrackRuns);
	if (ptr->sampleGroups) gf_list_del(ptr->sampleGroups);
	if (ptr->sampleGroupsDescription) gf_list_del(ptr->sampleGroupsDescription);
	if (ptr->sai_sizes) gf_list_del(ptr->sai_sizes);
	if (ptr->sai_offsets) gf_list_del(ptr->sai_offsets);
	gf_free(ptr);
}

fixed #2092


GF_Err stsh_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_StshEntry *ent;
	GF_ShadowSyncBox *ptr = (GF_ShadowSyncBox *)s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, gf_list_count(ptr->entries));
	i=0;
	while ((ent = (GF_StshEntry *)gf_list_enum(ptr->entries, &i))) {
		gf_bs_write_u32(bs, ent->shadowedSampleNumber);
		gf_bs_write_u32(bs, ent->syncSampleNumber);
	}
	return GF_OK;
}

fixed #2092


GF_Err edts_box_size(GF_Box *s)
{
	GF_EditBox *ptr = (GF_EditBox *)s;

	//here we have a trick: if editList is empty, skip the box
	if (!ptr->editList || ! gf_list_count(ptr->editList->entryList)) {
		ptr->size = 0;
	}
	return GF_OK;
}

fixed #2092


GF_Err tims_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_TSHintEntryBox *ptr = (GF_TSHintEntryBox *)s;
	if (ptr == NULL) return GF_BAD_PARAM;
	e = gf_isom_box_write_header(s, bs);
	if (e) return e;
	gf_bs_write_u32(bs, ptr->timeScale);
	return GF_OK;
}

fixed #2092


GF_Err tpyl_box_size(GF_Box *s)
{
	s->size += 8;
	return GF_OK;
}

fixed #2092


GF_Err segr_box_size(GF_Box *s)
{
	u32 i;
	FDSessionGroupBox *ptr = (FDSessionGroupBox *)s;

	ptr->size += 2;

	for (i=0; i<ptr->num_session_groups; i++) {
		ptr->size += 1 + 4*ptr->session_groups[i].nb_groups;
		ptr->size += 2 + 4*ptr->session_groups[i].nb_channels;
	}
	return GF_OK;

fixed #2092


GF_Box *dimm_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_DIMMBox, GF_ISOM_BOX_TYPE_DIMM);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err extr_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	GF_ExtraDataBox *ptr = (GF_ExtraDataBox *)s;

	e = gf_isom_box_parse((GF_Box**) &ptr->feci, bs);
	if (e) return e;
	if (!ptr->feci || ptr->feci->size > ptr->size) return GF_ISOM_INVALID_MEDIA;
	ptr->data_length = (u32) (ptr->size - ptr->feci->size);
	ptr->data = gf_malloc(sizeof(char)*ptr->data_length);
	if (!ptr->data) return GF_OUT_OF_MEM;
	gf_bs_read_data(bs, ptr->data, ptr->data_length);

	return GF_OK;

fixed #2092


GF_Err mfra_box_read(GF_Box *s, GF_BitStream *bs)
{
	return gf_isom_box_array_read(s, bs);
}

fixed #2092


GF_Box *def_parent_full_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_Box, 0);
	return (GF_Box *) tmp;
}

fixed #2092


GF_Box *sidx_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_SegmentIndexBox, GF_ISOM_BOX_TYPE_SIDX);
	return (GF_Box *)tmp;

fixed #2092


GF_Err tfhd_box_size(GF_Box *s)
{
	GF_TrackFragmentHeaderBox *ptr = (GF_TrackFragmentHeaderBox *)s;
	ptr->size += 4;

	//The rest depends on the flags
	if (ptr->flags & GF_ISOM_TRAF_BASE_OFFSET) ptr->size += 8;
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DESC) ptr->size += 4;
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_DUR) ptr->size += 4;
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_SIZE) ptr->size += 4;
	if (ptr->flags & GF_ISOM_TRAF_SAMPLE_FLAGS) ptr->size += 4;
	return GF_OK;
}

fixed #2092


GF_Err bloc_box_write(GF_Box *s, GF_BitStream *bs)
{
	GF_Err e;
	u32 i;
	GF_BaseLocationBox *ptr = (GF_BaseLocationBox *) s;

	e = gf_isom_full_box_write(s, bs);
	if (e) return e;
	gf_bs_write_data(bs, (const char *) ptr->baseLocation, 256);
	gf_bs_write_data(bs, (const char *) ptr->basePurlLocation, 256);
	for (i=0; i < 64; i++ ) {
		gf_bs_write_u64(bs, 0);
	}
	return GF_OK;

fixed #2092


GF_Err tsro_box_read(GF_Box *s, GF_BitStream *bs)
{
	GF_TimeOffHintEntryBox *ptr = (GF_TimeOffHintEntryBox *)s;
	ISOM_DECREASE_SIZE(ptr, 4);
	ptr->TimeOffset = gf_bs_read_u32(bs);
	return GF_OK;

fixed #2092


void mvex_box_del(GF_Box *s)
{
	GF_MovieExtendsBox *ptr = (GF_MovieExtendsBox *)s;
	if (ptr == NULL) return;
	gf_list_del(ptr->TrackExList);
	gf_list_del(ptr->TrackExPropList);
	gf_free(ptr);
}

fixed #2092


GF_Err fiin_box_read(GF_Box *s, GF_BitStream *bs)
{
	FDItemInformationBox *ptr = (FDItemInformationBox *)s;

	ISOM_DECREASE_SIZE(ptr, 2);
	gf_bs_read_u16(bs);
	return gf_isom_box_array_read(s, bs);

fixed #2092


GF_Box *prhd_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_ProjectionHeaderBox, GF_ISOM_BOX_TYPE_PRHD);
	return (GF_Box *)tmp;

fixed #2092


GF_Err urn_box_read(GF_Box *s, GF_BitStream *bs)
{
	u32 i, to_read;
	char *tmpName;
	GF_DataEntryURNBox *ptr = (GF_DataEntryURNBox *)s;
	if (! ptr->size ) return GF_OK;

	//here we have to handle that in a clever way
	to_read = (u32) ptr->size;
	tmpName = (char*)gf_malloc(sizeof(char) * to_read);
	if (!tmpName) return GF_OUT_OF_MEM;
	//get the data
	gf_bs_read_data(bs, tmpName, to_read);

	//then get the break
	i = 0;
	while ( (i < to_read) && (tmpName[i] != 0) ) {
		i++;
	}
	//check the data is consistent
	if (i == to_read) {
		gf_free(tmpName);
		return GF_ISOM_INVALID_FILE;
	}
	//no NULL char, URL is not specified
	if (i == to_read - 1) {
		ptr->nameURN = tmpName;
		ptr->location = NULL;
		return GF_OK;
	}
	//OK, this has both URN and URL
	ptr->nameURN = (char*)gf_malloc(sizeof(char) * (i+1));
	if (!ptr->nameURN) {
		gf_free(tmpName);
		return GF_OUT_OF_MEM;
	}
	memcpy(ptr->nameURN, tmpName, i + 1);

	if (tmpName[to_read - 1] != 0) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] urn box contains invalid location field\n" ));
	}
	else {
		ptr->location = (char*)gf_malloc(sizeof(char) * (to_read - i - 1));
		if (!ptr->location) {
			gf_free(tmpName);
			gf_free(ptr->nameURN);
			ptr->nameURN = NULL;
			return GF_OUT_OF_MEM;
		}
		memcpy(ptr->location, tmpName + i + 1, (to_read - i - 1));
	}

	gf_free(tmpName);
	return GF_OK;
}

fixed #2092


GF_Err fecr_box_size(GF_Box *s)
{
	FECReservoirBox *ptr = (FECReservoirBox *)s;
	ptr->size += (ptr->version ? 4 : 2) +  ptr->nb_entries * (ptr->version ? 8 : 6);
	return GF_OK;

fixed #2092


void tmin_box_del(GF_Box *s)
{
	gf_free((GF_TMINBox *)s);
}

fixed #2092


GF_Box *stsc_box_new()
{
	ISOM_DECL_BOX_ALLOC(GF_SampleToChunkBox, GF_ISOM_BOX_TYPE_STSC);
	return (GF_Box *)tmp;
}

fixed #2092


GF_Err hnti_box_size(GF_Box *s)
{
	return GF_OK;
}

fixed #2092


GF_Box *video_sample_entry_box_new()
{
	GF_MPEGVisualSampleEntryBox *tmp;
	GF_SAFEALLOC(tmp, GF_MPEGVisualSampleEntryBox);
	if (tmp == NULL) return NULL;

	gf_isom_video_sample_entry_init((GF_VisualSampleEntryBox *)tmp);
	return (GF_Box *)tmp;
}

fixed #2092


    explicit Iterator(const typename Iterator::Params& params)
        : DatasetIterator<Dataset<T>>(params),
          num_elements_(params.dataset->sparse_tensor_.shape()[0]),
          dense_shape_(DT_INT64, {params.dataset->sparse_tensor_.dims() - 1}),
          group_iterable_(params.dataset->sparse_tensor_.group({0})),
          iter_(group_iterable_.begin()) {
      for (size_t i = 0; i < dense_shape_.NumElements(); ++i) {
        dense_shape_.vec<int64_t>()(i) =
            params.dataset->sparse_tensor_.shape()[i + 1];
      }
    }

Properly validate sparse tensor in `SparseTensorSliceDataset`

Existing validation was incomplete.

PiperOrigin-RevId: 415375048
Change-Id: I14cd18f29ede73286f3ffac35171bd15828997e9


    std::shared_ptr<model::Node> CreateNode(
        IteratorContext* ctx, model::Node::Args args) const override {
      return model::MakeSourceNode(std::move(args));
    }


  Status InputDatasets(std::vector<const DatasetBase*>* inputs) const override {
    return Status::OK();
  }


  int64_t CardinalityInternal() const override {
    return sparse_tensor_.shape()[0];
  }


  Status AsGraphDefInternal(SerializationContext* ctx,
                            DatasetGraphDefBuilder* b,
                            Node** output) const override {
    Node* indices_node;
    TF_RETURN_IF_ERROR(b->AddTensor(sparse_tensor_.indices(), &indices_node));
    Node* value_node;
    TF_RETURN_IF_ERROR(b->AddTensor(sparse_tensor_.values(), &value_node));
    Node* dense_shape_node;
    std::vector<int64_t> dense_shape;
    dense_shape.reserve(sparse_tensor_.shape().size());
    for (int i = 0; i < sparse_tensor_.shape().size(); i++)
      dense_shape.emplace_back(sparse_tensor_.shape()[i]);
    TF_RETURN_IF_ERROR(b->AddVector(dense_shape, &dense_shape_node));
    AttrValue val_dtype;
    b->BuildAttrValue(sparse_tensor_.dtype(), &val_dtype);
    TF_RETURN_IF_ERROR(
        b->AddDataset(this, {indices_node, value_node, dense_shape_node},
                      {{"Tvalues", val_dtype}}, output));
    return Status::OK();
  }


  explicit SparseTensorSliceDatasetOp(OpKernelConstruction* ctx)
      : DatasetOpKernel(ctx) {}


  const std::vector<PartialTensorShape>& output_shapes() const override {
    return shapes_;
  }


  void MakeDataset(OpKernelContext* ctx, DatasetBase** output) override {
    // Create a new SparseTensorSliceDatasetOp::Dataset, insert it in
    // the step container, and return it as the output.
    const Tensor* indices;
    OP_REQUIRES_OK(ctx, ctx->input("indices", &indices));
    const Tensor* values;
    OP_REQUIRES_OK(ctx, ctx->input("values", &values));
    const Tensor* dense_shape;
    OP_REQUIRES_OK(ctx, ctx->input("dense_shape", &dense_shape));

    OP_REQUIRES(ctx, TensorShapeUtils::IsMatrix(indices->shape()),
                errors::InvalidArgument("Input indices must be a matrix. Got: ",
                                        indices->shape().DebugString()));
    OP_REQUIRES(ctx, TensorShapeUtils::IsVector(values->shape()),
                errors::InvalidArgument("Input values must be a vector. Got: ",
                                        values->shape().DebugString()));
    OP_REQUIRES(ctx, TensorShapeUtils::IsVector(dense_shape->shape()),
                errors::InvalidArgument("Input shape must be a vector. Got: ",
                                        dense_shape->shape().DebugString()));
    OP_REQUIRES(
        ctx, values->shape().dim_size(0) == indices->shape().dim_size(0),
        errors::InvalidArgument(
            "Number of values must match first dimension of indices. ", "Got ",
            values->shape().dim_size(0),
            " values, indices shape: ", indices->shape().DebugString()));
    OP_REQUIRES(
        ctx, dense_shape->shape().dim_size(0) == indices->shape().dim_size(1),
        errors::InvalidArgument(
            "Number of dimensions must match second dimension of indices. ",
            "Got ", dense_shape->shape().dim_size(0),
            " dimensions, indices shape: ", indices->shape().DebugString()));
    OP_REQUIRES(ctx, dense_shape->NumElements() > 0,
                errors::InvalidArgument(
                    "The shape argument requires at least one element."));

    // We currently ensure that `sparse_tensor` is ordered in the
    // batch dimension.
    // TODO(mrry): Investigate ways to avoid this unconditional check
    // if we can be sure that the sparse tensor was produced in an
    // appropriate order (e.g. by `tf.parse_example()` or a Dataset
    // that batches elements into rows of a SparseTensor).
    int64_t previous_batch_index = -1;
    for (int64_t i = 0; i < indices->dim_size(0); ++i) {
      int64_t next_batch_index = indices->matrix<int64_t>()(i, 0);
      OP_REQUIRES(
          ctx, next_batch_index >= previous_batch_index,
          errors::Unimplemented("The SparseTensor must be ordered in the batch "
                                "dimension; handling arbitrarily ordered input "
                                "is not currently supported."));
      previous_batch_index = next_batch_index;
    }
    gtl::InlinedVector<int64_t, 8> std_order(dense_shape->NumElements(), 0);
    sparse::SparseTensor tensor;
    OP_REQUIRES_OK(
        ctx, sparse::SparseTensor::Create(
                 *indices, *values, TensorShape(dense_shape->vec<int64_t>()),
                 std_order, &tensor));
    *output = new Dataset<T>(ctx, std::move(tensor));
  }


  explicit Dataset(OpKernelContext* ctx,
                   const sparse::SparseTensor& sparse_tensor)
      : DatasetBase(DatasetContext(ctx)),
        sparse_tensor_(sparse_tensor),
        dtypes_({DT_INT64, sparse_tensor.dtype(), DT_INT64}),
        shapes_({{-1, sparse_tensor.dims() - 1},
                 {-1},
                 {sparse_tensor.dims() - 1}}) {}


  string DebugString() const override {
    return "SparseTensorSliceDatasetOp::Dataset";
  }


const DataTypeVector& output_dtypes() const override { return dtypes_; }


Status CheckExternalState() const override { return Status::OK(); }


    Status GetNextInternal(IteratorContext* ctx,
                           std::vector<Tensor>* out_tensors,
                           bool* end_of_sequence) override {
      mutex_lock l(mu_);
      if (i_ == num_elements_) {
        *end_of_sequence = true;
        return Status::OK();
      }

      out_tensors->clear();
      out_tensors->reserve(3);
      const int rank = Iterator::dataset()->sparse_tensor_.dims();

      if (i_ > next_non_empty_i_ && iter_ != group_iterable_.end()) {
        // We still have elements to consume from `group_iterable_`
        // and we have emitted all elements up to and including the
        // current position.
        sparse::Group group = *iter_;
        const auto indices = group.indices();
        const auto values = group.values<T>();
        const int64_t num_entries = values.size();
        next_non_empty_i_ = indices(0, 0);

        next_indices_ = Tensor(DT_INT64, {num_entries, rank - 1});
        next_values_ = Tensor(DataTypeToEnum<T>::value, {num_entries});

        auto next_indices_t = next_indices_.matrix<int64_t>();
        auto next_values_t = next_values_.vec<T>();

        for (int64_t i = 0; i < num_entries; ++i) {
          for (int d = 1; d < rank; ++d) {
            next_indices_t(i, d - 1) = indices(i, d);
          }
          next_values_t(i) = values(i);
        }

        ++iter_;
      }
      if (i_ == next_non_empty_i_) {
        // The current position is non-empty in the input
        // `SparseTensor`, and we have already read the value from the
        // `GroupIterable`.
        out_tensors->push_back(std::move(next_indices_));
        out_tensors->push_back(std::move(next_values_));
        out_tensors->push_back(dense_shape_);
        next_non_empty_i_ = kNextNonEmptyUnknown;
      } else {
        DCHECK(i_ < next_non_empty_i_ || iter_ == group_iterable_.end());
        // The current position is empty in the input `SparseTensor`,
        // so emit empty indices and values.
        out_tensors->push_back(Tensor(DT_INT64, TensorShape({0, rank - 1})));
        out_tensors->push_back(Tensor(DataTypeToEnum<T>::value, {0}));
        out_tensors->push_back(dense_shape_);
      }

      ++i_;
      *end_of_sequence = false;
      return Status::OK();
    }


    Status SaveInternal(SerializationContext* ctx,
                        IteratorStateWriter* writer) override {
      mutex_lock l(mu_);
      TF_RETURN_IF_ERROR(writer->WriteScalar(Iterator::full_name("i"), i_));
      TF_RETURN_IF_ERROR(
          writer->WriteScalar(Iterator::full_name("iter_loc"), iter_.loc()));
      TF_RETURN_IF_ERROR(writer->WriteScalar(
          Iterator::full_name("next_non_empty_i_"), next_non_empty_i_));
      if (i_ <= next_non_empty_i_) {
        TF_RETURN_IF_ERROR(writer->WriteTensor(
            Iterator::full_name("next_indices_"), next_indices_));
        TF_RETURN_IF_ERROR(writer->WriteTensor(
            Iterator::full_name("next_values_"), next_values_));
      }
      return Status::OK();
    }


  std::unique_ptr<IteratorBase> MakeIteratorInternal(
      const string& prefix) const override {
    return absl::make_unique<Iterator>(typename Iterator::Params{
        this, strings::StrCat(prefix, "::SparseTensorSlice")});
  }


    Status RestoreInternal(IteratorContext* ctx,
                           IteratorStateReader* reader) override {
      mutex_lock l(mu_);
      TF_RETURN_IF_ERROR(reader->ReadScalar(Iterator::full_name("i"), &i_));
      int64_t iter_loc;
      TF_RETURN_IF_ERROR(
          reader->ReadScalar(Iterator::full_name("iter_loc"), &iter_loc));
      iter_ = group_iterable_.at(iter_loc);
      TF_RETURN_IF_ERROR(reader->ReadScalar(
          Iterator::full_name("next_non_empty_i_"), &next_non_empty_i_));
      if (i_ <= next_non_empty_i_) {
        TF_RETURN_IF_ERROR(reader->ReadTensor(
            Iterator::full_name("next_indices_"), &next_indices_));
        TF_RETURN_IF_ERROR(reader->ReadTensor(
            Iterator::full_name("next_values_"), &next_values_));
      }
      return Status::OK();
    }


IRC_PROTOCOL_CALLBACK(312)
{
    IRC_PROTOCOL_MIN_ARGS(6);

    weechat_printf_date_tags (
        irc_msgbuffer_get_target_buffer (
            server, argv[3], command, "whois", NULL),
        date,
        irc_protocol_tags (command, "irc_numeric", NULL, NULL),
        "%s%s[%s%s%s] %s%s %s(%s%s%s)",
        weechat_prefix ("network"),
        IRC_COLOR_CHAT_DELIMITERS,
        irc_nick_color_for_msg (server, 1, NULL, argv[3]),
        argv[3],
        IRC_COLOR_CHAT_DELIMITERS,
        IRC_COLOR_RESET,
        argv[4],
        IRC_COLOR_CHAT_DELIMITERS,
        IRC_COLOR_RESET,
        (argv_eol[5][0] == ':') ? argv_eol[5] + 1 : argv_eol[5],
        IRC_COLOR_CHAT_DELIMITERS);

    return WEECHAT_RC_OK;
}

irc: fix crash when receiving a malformed message 352 (who)

Thanks to Stuart Nevans Locke for reporting the issue.


IRC_PROTOCOL_CALLBACK(005)
{
    char *pos, *pos2, *pos_start, *error, *isupport2;
    int length_isupport, length, casemapping;
    long value;

    IRC_PROTOCOL_MIN_ARGS(4);

    irc_protocol_cb_numeric (server,
                             date, nick, address, host, command,
                             ignored, argc, argv, argv_eol);

    /* save prefix */
    pos = strstr (argv_eol[3], "PREFIX=");
    if (pos)
    {
        pos += 7;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        irc_server_set_prefix_modes_chars (server, pos);
        if (pos2)
            pos2[0] = ' ';
    }

    /* save max nick length */
    pos = strstr (argv_eol[3], "NICKLEN=");
    if (pos)
    {
        pos += 8;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        error = NULL;
        value = strtol (pos, &error, 10);
        if (error && !error[0] && (value > 0))
            server->nick_max_length = (int)value;
        if (pos2)
            pos2[0] = ' ';
    }

    /* save max user length */
    pos = strstr (argv_eol[3], "USERLEN=");
    if (pos)
    {
        pos += 8;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        error = NULL;
        value = strtol (pos, &error, 10);
        if (error && !error[0] && (value > 0))
            server->user_max_length = (int)value;
        if (pos2)
            pos2[0] = ' ';
    }

    /* save max host length */
    pos = strstr (argv_eol[3], "HOSTLEN=");
    if (pos)
    {
        pos += 8;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        error = NULL;
        value = strtol (pos, &error, 10);
        if (error && !error[0] && (value > 0))
            server->host_max_length = (int)value;
        if (pos2)
            pos2[0] = ' ';
    }

    /* save casemapping */
    pos = strstr (argv_eol[3], "CASEMAPPING=");
    if (pos)
    {
        pos += 12;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        casemapping = irc_server_search_casemapping (pos);
        if (casemapping >= 0)
            server->casemapping = casemapping;
        if (pos2)
            pos2[0] = ' ';
    }

    /* save chantypes */
    pos = strstr (argv_eol[3], "CHANTYPES=");
    if (pos)
    {
        pos += 10;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        if (server->chantypes)
            free (server->chantypes);
        server->chantypes = strdup (pos);
        if (pos2)
            pos2[0] = ' ';
    }

    /* save chanmodes */
    pos = strstr (argv_eol[3], "CHANMODES=");
    if (pos)
    {
        pos += 10;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        if (server->chanmodes)
            free (server->chanmodes);
        server->chanmodes = strdup (pos);
        if (pos2)
            pos2[0] = ' ';
    }

    /* save monitor (limit) */
    pos = strstr (argv_eol[3], "MONITOR=");
    if (pos)
    {
        pos += 8;
        pos2 = strchr (pos, ' ');
        if (pos2)
            pos2[0] = '\0';
        error = NULL;
        value = strtol (pos, &error, 10);
        if (error && !error[0] && (value > 0))
            server->monitor = (int)value;
        if (pos2)
            pos2[0] = ' ';
    }

    /* save whole message (concatenate to existing isupport, if any) */
    pos_start = NULL;
    pos = strstr (argv_eol[3], " :");
    length = (pos) ? pos - argv_eol[3] : (int)strlen (argv_eol[3]);
    if (server->isupport)
    {
        length_isupport = strlen (server->isupport);
        isupport2 = realloc (server->isupport,
                             length_isupport + /* existing */
                             1 + length + 1); /* new */
        if (isupport2)
        {
            server->isupport = isupport2;
            pos_start = server->isupport + length_isupport;
        }
    }
    else
    {
        server->isupport = malloc (1 + length + 1);
        if (server->isupport)
            pos_start = server->isupport;
    }

    if (pos_start)
    {
        pos_start[0] = ' ';
        memcpy (pos_start + 1, argv_eol[3], length);
        pos_start[length + 1] = '\0';
    }

    return WEECHAT_RC_OK;
}


IRC_PROTOCOL_CALLBACK(305)
{
    IRC_PROTOCOL_MIN_ARGS(3);

    if (argc > 3)
    {
        weechat_printf_date_tags (
            irc_msgbuffer_get_target_buffer (
                server, NULL, command, "unaway", NULL),
            date,
            irc_protocol_tags (command, "irc_numeric", NULL, NULL),
            "%s%s",
            weechat_prefix ("network"),
            (argv_eol[3][0] == ':') ? argv_eol[3] + 1 : argv_eol[3]);
    }

    server->is_away = 0;
    server->away_time = 0;

    weechat_bar_item_update ("away");

    return WEECHAT_RC_OK;
}


IRC_PROTOCOL_CALLBACK(whowas_nick_msg)
{
    IRC_PROTOCOL_MIN_ARGS(5);

    weechat_printf_date_tags (
        irc_msgbuffer_get_target_buffer (
            server, argv[3], command, "whowas", NULL),
        date,
        irc_protocol_tags (command, "irc_numeric", NULL, NULL),
        "%s%s[%s%s%s] %s%s",
        weechat_prefix ("network"),
        IRC_COLOR_CHAT_DELIMITERS,
        irc_nick_color_for_msg (server, 1, NULL, argv[3]),
        argv[3],
        IRC_COLOR_CHAT_DELIMITERS,
        IRC_COLOR_RESET,
        (argv_eol[4][0] == ':') ? argv_eol[4] + 1 : argv_eol[4]);

    return WEECHAT_RC_OK;
}


irc_protocol_cap_print_cb (void *data,
                           struct t_hashtable *hashtable,
                           const char *key, const char *value)
{
    char **str_caps;

    /* make C compiler happy */
    (void) hashtable;

    str_caps = (char **)data;

    if (*str_caps[0])
        weechat_string_dyn_concat (str_caps, " ");
    weechat_string_dyn_concat (str_caps, key);
    if (value)
    {
        weechat_string_dyn_concat (str_caps, "=");
        weechat_string_dyn_concat (str_caps, value);
    }
}


IRC_PROTOCOL_CALLBACK(328)
{
    struct t_irc_channel *ptr_channel;

    IRC_PROTOCOL_MIN_ARGS(5);

    ptr_channel = irc_channel_search (server, argv[3]);
    if (ptr_channel)
    {
        weechat_printf_date_tags (
            irc_msgbuffer_get_target_buffer (
                server, NULL, command, NULL, ptr_channel->buffer),
            date,
            irc_protocol_tags (command, "irc_numeric", NULL, NULL),
            _("%sURL for %s%s%s: %s"),
            weechat_prefix ("network"),
            IRC_COLOR_CHAT_CHANNEL,
            argv[3],
            IRC_COLOR_RESET,
            (argv_eol[4][0] == ':') ?
            argv_eol[4] + 1 : argv_eol[4]);
    }

    return WEECHAT_RC_OK;
}


IRC_PROTOCOL_CALLBACK(account)
{
    struct t_irc_channel *ptr_channel;
    struct t_irc_nick *ptr_nick;
    char *pos_account;
    int cap_account_notify;

    IRC_PROTOCOL_MIN_ARGS(3);

    pos_account = (strcmp (argv[2], "*") != 0) ? argv[2] : NULL;

    cap_account_notify = weechat_hashtable_has_key (server->cap_list,
                                                    "account-notify");

    for (ptr_channel = server->channels; ptr_channel;
         ptr_channel = ptr_channel->next_channel)
    {
        ptr_nick = irc_nick_search (server, ptr_channel, nick);
        if (ptr_nick)
        {
            if (ptr_nick->account)
                free (ptr_nick->account);
            ptr_nick->account = (cap_account_notify && pos_account) ?
                strdup (pos_account) : NULL;
        }
    }

    return WEECHAT_RC_OK;
}


IRC_PROTOCOL_CALLBACK(error)
{
    char *ptr_args;

    IRC_PROTOCOL_MIN_ARGS(2);

    ptr_args = (argv_eol[1][0] == ':') ? argv_eol[1] + 1 : argv_eol[1];

    weechat_printf_date_tags (
        irc_msgbuffer_get_target_buffer (server, NULL, command, NULL, NULL),
        date,
        irc_protocol_tags (command, NULL, NULL, NULL),
        "%s%s",
        weechat_prefix ("error"),
        ptr_args);

    if (strncmp (ptr_args, "Closing Link", 12) == 0)
    {
        irc_server_disconnect (server, !server->is_connected, 1);
    }

    return WEECHAT_RC_OK;
}


IRC_PROTOCOL_CALLBACK(327)
{
    char *pos_realname;
    struct t_gui_buffer *ptr_buffer;

    IRC_PROTOCOL_MIN_ARGS(6);

    pos_realname = (argc > 6) ?
        ((argv_eol[6][0] == ':') ? argv_eol[6] + 1 : argv_eol[6]) : NULL;

    ptr_buffer = irc_msgbuffer_get_target_buffer (server, argv[3],
                                                  command, "whois", NULL);

    if (pos_realname && pos_realname[0])
    {
        weechat_printf_date_tags (
            ptr_buffer,
            date,
            irc_protocol_tags (command, "irc_numeric", NULL, NULL),
            "%s%s[%s%s%s] %s%s %s %s(%s%s%s)",
            weechat_prefix ("network"),
            IRC_COLOR_CHAT_DELIMITERS,
            irc_nick_color_for_msg (server, 1, NULL, argv[3]),
            argv[3],
            IRC_COLOR_CHAT_DELIMITERS,
            IRC_COLOR_CHAT_HOST,
            argv[4],
            argv[5],
            IRC_COLOR_CHAT_DELIMITERS,
            IRC_COLOR_RESET,
            pos_realname,
            IRC_COLOR_CHAT_DELIMITERS);
    }
    else
    {
        weechat_printf_date_tags (
            ptr_buffer,
            date,
            irc_protocol_tags (command, "irc_numeric", NULL, NULL),
            "%s%s[%s%s%s] %s%s %s",
            weechat_prefix ("network"),
            IRC_COLOR_CHAT_DELIMITERS,
            irc_nick_color_for_msg (server, 1, NULL, argv[3]),
            argv[3],
            IRC_COLOR_CHAT_DELIMITERS,
            IRC_COLOR_CHAT_HOST,
            argv[4],
            argv[5]);
    }

    return WEECHAT_RC_OK;
}