1 /*
2 *					GPAC Multimedia Framework
3 *
4 *			Authors: Cyril Concolato - Jean le Feuvre
5 *			Copyright (c) Telecom ParisTech 2005-2012
6 *					All rights reserved
7 *
8 *  This file is part of GPAC / ISO Media File Format sub-project
9 *
10 *  GPAC is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU Lesser General Public License as published by
12 *  the Free Software Foundation; either version 2, or (at your option)
13 *  any later version.
14 *
15 *  GPAC is distributed in the hope that it will be useful,
16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 *  GNU Lesser General Public License for more details.
19 *
20 *  You should have received a copy of the GNU Lesser General Public
21 *  License along with this library; see the file COPYING.  If not, write to
22 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25 
26 
27 #include <gpac/internal/isomedia_dev.h>
28 
29 #ifndef GPAC_DISABLE_ISOM
30 
gf_isom_get_meta(GF_ISOFile * file,Bool root_meta,u32 track_num)31 GF_MetaBox *gf_isom_get_meta(GF_ISOFile *file, Bool root_meta, u32 track_num)
32 {
33 	GF_TrackBox *tk;
34 	if (!file) return NULL;
35 	if (root_meta) return file->meta;
36 	if (!track_num) return file->moov ? file->moov->meta : NULL;
37 
38 	tk = (GF_TrackBox*)gf_list_get(file->moov->trackList, track_num - 1);
39 	return tk ? tk->meta : NULL;
40 }
41 
42 GF_EXPORT
gf_isom_get_meta_type(GF_ISOFile * file,Bool root_meta,u32 track_num)43 u32 gf_isom_get_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num)
44 {
45 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
46 	if (!meta) return 0;
47 	if (!meta->handler) return 0;
48 	return meta->handler->handlerType;
49 }
50 
51 GF_EXPORT
gf_isom_has_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num)52 u32 gf_isom_has_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
53 {
54 	u32 i, count;
55 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
56 	if (!meta) return 0;
57 
58 	count = gf_list_count(meta->other_boxes);
59 	for (i = 0; i<count; i++) {
60 		GF_Box *a = (GF_Box *)gf_list_get(meta->other_boxes, i);
61 		if (a->type == GF_ISOM_BOX_TYPE_XML) return 1;
62 		if (a->type == GF_ISOM_BOX_TYPE_BXML) return 2;
63 	}
64 	return 0;
65 }
66 
67 GF_EXPORT
gf_isom_extract_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num,char * outName,Bool * is_binary)68 GF_Err gf_isom_extract_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, char *outName, Bool *is_binary)
69 {
70 	u32 i, count;
71 	FILE *didfile;
72 	GF_XMLBox *xml = NULL;
73 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
74 	if (!meta) return GF_BAD_PARAM;
75 
76 	/*Find XMLBox*/
77 	count = gf_list_count(meta->other_boxes);
78 	for (i = 0; i <count; i++) {
79 		GF_Box *a = (GF_Box *)gf_list_get(meta->other_boxes, i);
80 		if ((a->type == GF_ISOM_BOX_TYPE_XML) || (a->type == GF_ISOM_BOX_TYPE_BXML)) {
81 			xml = (GF_XMLBox *)a;
82 			break;
83 		}
84 	}
85 	if (!xml || !xml->xml || !xml->xml_length) return GF_BAD_PARAM;
86 
87 	didfile = gf_fopen(outName, "wb");
88 	if (!didfile) return GF_IO_ERR;
89 	gf_fwrite(xml->xml, xml->xml_length, 1, didfile);
90 	gf_fclose(didfile);
91 
92 	if (is_binary) *is_binary = (xml->type == GF_ISOM_BOX_TYPE_BXML) ? 1 : 0;
93 	return GF_OK;
94 }
95 
gf_isom_get_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num,Bool * is_binary)96 GF_XMLBox *gf_isom_get_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool *is_binary)
97 {
98 	u32 i, count;
99 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
100 	if (!meta) return NULL;
101 
102 	/*Find XMLBox*/
103 	count = gf_list_count(meta->other_boxes);
104 	for (i = 0; i <count; i++) {
105 		GF_Box *a = (GF_Box *)gf_list_get(meta->other_boxes, i);
106 		if (a->type == GF_ISOM_BOX_TYPE_XML) {
107 			*is_binary = 0;
108 			return (GF_XMLBox *)a;
109 		}
110 		else if (a->type == GF_ISOM_BOX_TYPE_BXML) {
111 			*is_binary = 1;
112 			return (GF_XMLBox *)a;
113 		}
114 	}
115 	return NULL;
116 }
117 
118 
119 
120 GF_EXPORT
gf_isom_get_meta_item_count(GF_ISOFile * file,Bool root_meta,u32 track_num)121 u32 gf_isom_get_meta_item_count(GF_ISOFile *file, Bool root_meta, u32 track_num)
122 {
123 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
124 	if (!meta || !meta->item_infos || !meta->item_locations) return 0;
125 	return gf_list_count(meta->item_infos->item_infos);
126 }
127 
128 GF_EXPORT
gf_isom_get_meta_item_info(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_num,u32 * itemID,u32 * protection_idx,Bool * is_self_reference,const char ** item_name,const char ** item_mime_type,const char ** item_encoding,const char ** item_url,const char ** item_urn)129 GF_Err gf_isom_get_meta_item_info(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_num,
130 	u32 *itemID, u32 *protection_idx, Bool *is_self_reference,
131 	const char **item_name, const char **item_mime_type, const char **item_encoding,
132 	const char **item_url, const char **item_urn)
133 {
134 	GF_ItemInfoEntryBox *iinf;
135 	u32 i, count;
136 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
137 	if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
138 
139 	iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1);
140 	if (!iinf) return GF_BAD_PARAM;
141 
142 	if (itemID) (*itemID) = iinf->item_ID;
143 	if (protection_idx) (*protection_idx) = iinf->item_protection_index;
144 	if (item_name) (*item_name) = iinf->item_name;
145 	if (item_mime_type) (*item_mime_type) = iinf->content_type;
146 	if (item_encoding) (*item_encoding) = iinf->content_encoding;
147 	if (is_self_reference) *is_self_reference = 0;
148 
149 	if (item_url) (*item_url) = NULL;
150 	if (item_urn) (*item_urn) = NULL;
151 
152 	count = gf_list_count(meta->item_locations->location_entries);
153 	for (i = 0; i<count; i++) {
154 		GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
155 		if (iloc->item_ID == iinf->item_ID) {
156 			if (iloc->data_reference_index) {
157 				GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->other_boxes, iloc->data_reference_index - 1);
158 				if (a->type == GF_ISOM_BOX_TYPE_URL) {
159 					if (item_url) (*item_url) = ((GF_DataEntryURLBox*)a)->location;
160 				}
161 				else if (a->type == GF_ISOM_BOX_TYPE_URN) {
162 					if (item_url) (*item_url) = ((GF_DataEntryURNBox*)a)->location;
163 					if (item_urn) (*item_urn) = ((GF_DataEntryURNBox*)a)->nameURN;
164 				}
165 				break;
166 			}
167 			else if (is_self_reference && !iloc->base_offset) {
168 				GF_ItemExtentEntry *entry = (GF_ItemExtentEntry *)gf_list_get(iloc->extent_entries, 0);
169 				if (!entry->extent_length
170 #ifndef GPAC_DISABLE_ISOM_WRITE
171 					&& !entry->original_extent_offset
172 #endif
173 					)
174 					*is_self_reference = 1;
175 			}
176 		}
177 	}
178 	return GF_OK;
179 }
180 
181 GF_EXPORT
gf_isom_get_meta_item_by_id(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_ID)182 u32 gf_isom_get_meta_item_by_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_ID)
183 {
184 	GF_ItemInfoEntryBox *iinf;
185 	u32 i, count;
186 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
187 	if (!meta || !meta->item_infos || !meta->item_locations) return 0;
188 	count = gf_list_count(meta->item_infos->item_infos);
189 	for (i = 0; i<count; i++) {
190 		iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
191 		if (iinf->item_ID == item_ID) return i + 1;
192 	}
193 	return 0;
194 }
195 
196 GF_EXPORT
gf_isom_extract_meta_item_extended(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id,const char * dump_file_name,char ** out_data,u32 * out_size,const char ** out_mime)197 GF_Err gf_isom_extract_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name, char **out_data, u32 *out_size, const char **out_mime)
198 {
199 	GF_BitStream *item_bs;
200 	char szPath[1024];
201 	GF_ItemExtentEntry *extent_entry;
202 	FILE *resource = NULL;
203 	u32 i, count;
204 	GF_ItemLocationEntry *location_entry;
205 	u32 item_num;
206 	char *item_name = NULL;
207 
208 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
209 	if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
210 
211 	if (out_mime) *out_mime = NULL;
212 
213 	item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
214 	if (item_num) {
215 		GF_ItemInfoEntryBox *item_entry = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1);
216 		item_name = item_entry->item_name;
217 		if (out_mime) *out_mime = item_entry->content_type;
218 	}
219 
220 	location_entry = NULL;
221 	count = gf_list_count(meta->item_locations->location_entries);
222 	for (i = 0; i<count; i++) {
223 		location_entry = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
224 		if (location_entry->item_ID == item_id) break;
225 		location_entry = NULL;
226 	}
227 
228 	if (!location_entry) return GF_BAD_PARAM;
229 	/*FIXME*/
230 	if (location_entry->data_reference_index) {
231 		char *item_url = NULL, *item_urn = NULL;
232 		GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->other_boxes, location_entry->data_reference_index - 1);
233 		if (a->type == GF_ISOM_BOX_TYPE_URL) {
234 			item_url = ((GF_DataEntryURLBox*)a)->location;
235 		}
236 		else if (a->type == GF_ISOM_BOX_TYPE_URN) {
237 			item_url = ((GF_DataEntryURNBox*)a)->location;
238 			item_urn = ((GF_DataEntryURNBox*)a)->nameURN;
239 		}
240 		GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item already outside the ISO file at URL: %s, URN: %s\n", (item_url ? item_url : "N/A"), (item_urn ? item_urn : "N/A")));
241 		return GF_OK;
242 	}
243 
244 	/*don't extract self-reference item*/
245 	count = gf_list_count(location_entry->extent_entries);
246 	if (!location_entry->base_offset && (count == 1)) {
247 		extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, 0);
248 		if (!extent_entry->extent_length
249 #ifndef GPAC_DISABLE_ISOM_WRITE
250 			&& !extent_entry->original_extent_offset
251 #endif
252 			) return GF_BAD_PARAM;
253 	}
254 
255 	item_bs = NULL;
256 
257 	if (out_data) {
258 		item_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
259 	}
260 	else if (dump_file_name) {
261 		strcpy(szPath, dump_file_name);
262 		resource = gf_fopen(szPath, "wb");
263 		item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
264 	}
265 	else {
266 		if (item_name) strcpy(szPath, item_name);
267 		else sprintf(szPath, "item_id%02d", item_id);
268 		resource = gf_fopen(szPath, "wb");
269 		item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE);
270 	}
271 
272 	for (i = 0; i<count; i++) {
273 		char buf_cache[4096];
274 		u64 remain;
275 		GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, i);
276 		gf_bs_seek(file->movieFileMap->bs, location_entry->base_offset + extent_entry->extent_offset);
277 
278 		remain = extent_entry->extent_length;
279 		while (remain) {
280 			u32 cache_size = (remain>4096) ? 4096 : (u32)remain;
281 			gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size);
282 			gf_bs_write_data(item_bs, buf_cache, cache_size);
283 			remain -= cache_size;
284 		}
285 	}
286 	if (out_data) {
287 		gf_bs_get_content(item_bs, out_data, out_size);
288 	}
289 	if (resource) {
290 		gf_fclose(resource);
291 	}
292 	gf_bs_del(item_bs);
293 	return GF_OK;
294 }
295 
296 GF_EXPORT
gf_isom_extract_meta_item(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id,const char * dump_file_name)297 GF_Err gf_isom_extract_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name)
298 {
299 	return gf_isom_extract_meta_item_extended(file, root_meta, track_num, item_id, dump_file_name, NULL, NULL, NULL);
300 }
301 
gf_isom_extract_meta_item_mem(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id,char ** out_data,u32 * out_size,const char ** out_mime)302 GF_Err gf_isom_extract_meta_item_mem(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, char **out_data, u32 *out_size, const char **out_mime)
303 {
304 	return gf_isom_extract_meta_item_extended(file, root_meta, track_num, item_id, NULL, out_data, out_size, out_mime);
305 }
306 
307 GF_EXPORT
gf_isom_get_meta_primary_item_id(GF_ISOFile * file,Bool root_meta,u32 track_num)308 u32 gf_isom_get_meta_primary_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num)
309 {
310 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
311 	if (!meta || !meta->primary_resource) return 0;
312 	return meta->primary_resource->item_ID;
313 }
314 
315 
316 #ifndef GPAC_DISABLE_ISOM_WRITE
317 
318 
319 GF_EXPORT
gf_isom_set_meta_type(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 metaType)320 GF_Err gf_isom_set_meta_type(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 metaType)
321 {
322 	char szName[20];
323 	GF_MetaBox *meta;
324 
325 	GF_Err e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
326 	if (e) return e;
327 
328 	meta = gf_isom_get_meta(file, root_meta, track_num);
329 	if (!meta) {
330 		if (!metaType) return GF_OK;
331 		meta = (GF_MetaBox *)meta_New();
332 		if (root_meta) {
333 			file->meta = meta;
334 			gf_list_add(file->TopBoxes, meta);
335 		}
336 		else {
337 			gf_isom_insert_moov(file);
338 			if (!track_num) {
339 				file->moov->meta = meta;
340 			}
341 			else {
342 				GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num - 1);
343 				if (!tk) {
344 					gf_isom_box_del((GF_Box *)meta);
345 					return GF_BAD_PARAM;
346 				}
347 				tk->meta = meta;
348 			}
349 		}
350 	}
351 	else if (!metaType) {
352 		if (root_meta) {
353 			gf_list_del_item(file->TopBoxes, meta);
354 			gf_isom_box_del((GF_Box *)file->meta);
355 			file->meta = NULL;
356 		}
357 		else if (file->moov) {
358 			if (!track_num) {
359 				gf_isom_box_del((GF_Box *)file->moov->meta);
360 				file->moov->meta = NULL;
361 			}
362 			else {
363 				GF_TrackBox *tk = (GF_TrackBox *)gf_list_get(file->moov->trackList, track_num - 1);
364 				if (!tk) return GF_BAD_PARAM;
365 				gf_isom_box_del((GF_Box *)tk->meta);
366 				tk->meta = NULL;
367 			}
368 		}
369 		return GF_OK;
370 	}
371 
372 	if (!meta->handler)
373 		meta->handler = (GF_HandlerBox *)hdlr_New();
374 
375 	if (meta->handler->nameUTF8) gf_free(meta->handler->nameUTF8);
376 	meta->handler->handlerType = metaType;
377 	sprintf(szName, "GPAC %s Handler", gf_4cc_to_str(metaType));
378 	meta->handler->nameUTF8 = gf_strdup(szName);
379 	return GF_OK;
380 }
381 
382 GF_EXPORT
gf_isom_remove_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num)383 GF_Err gf_isom_remove_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num)
384 {
385 	u32 i;
386 	GF_Box *a;
387 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
388 	if (!meta) return GF_BAD_PARAM;
389 	i = 0;
390 	while ((a = (GF_Box*)gf_list_enum(meta->other_boxes, &i))) {
391 		switch (a->type) {
392 		case GF_ISOM_BOX_TYPE_XML:
393 		case GF_ISOM_BOX_TYPE_BXML:
394 			gf_list_rem(meta->other_boxes, i - 1);
395 			gf_isom_box_del(a);
396 			return GF_OK;
397 		}
398 	}
399 	return GF_OK;
400 }
401 
402 GF_EXPORT
gf_isom_set_meta_xml(GF_ISOFile * file,Bool root_meta,u32 track_num,char * XMLFileName,Bool IsBinaryXML)403 GF_Err gf_isom_set_meta_xml(GF_ISOFile *file, Bool root_meta, u32 track_num, char *XMLFileName, Bool IsBinaryXML)
404 {
405 	GF_Err e;
406 	FILE *xmlfile;
407 	GF_XMLBox *xml;
408 	GF_MetaBox *meta;
409 
410 	e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
411 	if (e) return e;
412 
413 	meta = gf_isom_get_meta(file, root_meta, track_num);
414 	if (!meta) return GF_BAD_PARAM;
415 
416 	e = gf_isom_remove_meta_xml(file, root_meta, track_num);
417 	if (e) return e;
418 
419 	xml = (GF_XMLBox *)xml_New();
420 	if (!xml) return GF_OUT_OF_MEM;
421 	gf_list_add(meta->other_boxes, xml);
422 	if (IsBinaryXML) xml->type = GF_ISOM_BOX_TYPE_BXML;
423 
424 
425 	/*assume 32bit max size = 4Go should be sufficient for a DID!!*/
426 	xmlfile = gf_fopen(XMLFileName, "rb");
427 	if (!xmlfile) return GF_URL_ERROR;
428 	gf_fseek(xmlfile, 0, SEEK_END);
429 	assert(gf_ftell(xmlfile) < 1 << 31);
430 	xml->xml_length = (u32)gf_ftell(xmlfile);
431 	gf_fseek(xmlfile, 0, SEEK_SET);
432 	xml->xml = (char*)gf_malloc(sizeof(unsigned char)*xml->xml_length);
433 	xml->xml_length = (u32)fread(xml->xml, 1, sizeof(unsigned char)*xml->xml_length, xmlfile);
434 	if (ferror(xmlfile)) {
435 		gf_free(xml->xml);
436 		xml->xml = NULL;
437 		return GF_BAD_PARAM;
438 	}
439 	gf_fclose(xmlfile);
440 	return GF_OK;
441 }
442 
gf_isom_set_meta_xml_memory(GF_ISOFile * file,Bool root_meta,u32 track_num,unsigned char * data,u32 data_size,Bool IsBinaryXML)443 GF_Err gf_isom_set_meta_xml_memory(GF_ISOFile *file, Bool root_meta, u32 track_num, unsigned char *data, u32 data_size, Bool IsBinaryXML)
444 {
445 	GF_Err e;
446 	GF_XMLBox *xml;
447 	GF_MetaBox *meta;
448 
449 	e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
450 	if (e) return e;
451 
452 	meta = gf_isom_get_meta(file, root_meta, track_num);
453 	if (!meta) return GF_BAD_PARAM;
454 
455 	e = gf_isom_remove_meta_xml(file, root_meta, track_num);
456 	if (e) return e;
457 
458 	xml = (GF_XMLBox *)xml_New();
459 	if (!xml) return GF_OUT_OF_MEM;
460 	gf_list_add(meta->other_boxes, xml);
461 	if (IsBinaryXML) xml->type = GF_ISOM_BOX_TYPE_BXML;
462 
463 
464 	/*assume 32bit max size = 4Go should be sufficient for a DID!!*/
465 	xml->xml_length = data_size;
466 	xml->xml = (char*)gf_malloc(sizeof(unsigned char)*xml->xml_length);
467 	memcpy(xml->xml, data, sizeof(unsigned char)*xml->xml_length);
468 	return GF_OK;
469 }
470 
meta_add_item_property_association(GF_ItemPropertyAssociationBox * ipma,u32 item_ID,u32 prop_index,Bool essential)471 static void meta_add_item_property_association(GF_ItemPropertyAssociationBox *ipma, u32 item_ID, u32 prop_index, Bool essential) {
472 	u32 i, count;
473 	GF_ItemPropertyAssociationEntry *found_entry = NULL;
474 	Bool *ess = (Bool *)gf_malloc(sizeof(Bool));
475 	u32 *index = (u32 *)gf_malloc(sizeof(u32));
476 
477 	*ess = essential;
478 	*index = prop_index;
479 	count = gf_list_count(ipma->entries);
480 	for (i = 0; i < count; i++) {
481 		GF_ItemPropertyAssociationEntry *entry = (GF_ItemPropertyAssociationEntry *)gf_list_get(ipma->entries, i);
482 		if (entry->item_id == item_ID) {
483 			found_entry = entry;
484 			break;
485 		}
486 	}
487 	if (!found_entry) {
488 		GF_SAFEALLOC(found_entry, GF_ItemPropertyAssociationEntry);
489 		if (!found_entry) return;
490 
491 		gf_list_add(ipma->entries, found_entry);
492 		found_entry->item_id = item_ID;
493 		found_entry->essential = gf_list_new();
494 		found_entry->property_index = gf_list_new();
495 	}
496 	gf_list_add(found_entry->essential, ess);
497 	gf_list_add(found_entry->property_index, index);
498 }
499 
500 GF_EXPORT
gf_isom_meta_get_next_item_id(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 * item_id)501 GF_Err gf_isom_meta_get_next_item_id(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 *item_id)
502 {
503 	GF_MetaBox *meta;
504 	u32 lastItemID = 0;
505 
506 	if (!file || !item_id) return GF_BAD_PARAM;
507 	meta = gf_isom_get_meta(file, root_meta, track_num);
508 	if (!meta) {
509 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Missing meta box"));
510 		return GF_BAD_PARAM;
511 	}
512 
513 	if (meta->item_infos) {
514 		u32 i;
515 		u32 item_count = gf_list_count(meta->item_infos->item_infos);
516 		for (i = 0; i < item_count; i++) {
517 			GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
518 			if (e->item_ID > lastItemID) lastItemID = e->item_ID;
519 		}
520 		*item_id = lastItemID + 1;
521 	}
522 	else {
523 		*item_id = lastItemID + 1;
524 	}
525 	return GF_OK;
526 }
527 
gf_isom_add_meta_item_extended(GF_ISOFile * file,Bool root_meta,u32 track_num,Bool self_reference,char * resource_path,const char * item_name,u32 item_id,u32 item_type,const char * mime_type,const char * content_encoding,GF_ImageItemProperties * image_props,const char * URL,const char * URN,char * data,u32 data_len,GF_List * item_extent_refs)528 GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path,
529 	const char *item_name, u32 item_id, u32 item_type, const char *mime_type, const char *content_encoding,
530 	GF_ImageItemProperties *image_props,
531 	const char *URL, const char *URN,
532 	char *data, u32 data_len, GF_List *item_extent_refs)
533 {
534 	u32 i;
535 	GF_Err e;
536 	GF_ItemLocationEntry *location_entry;
537 	GF_ItemInfoEntryBox *infe;
538 	GF_MetaBox *meta;
539 	u32 lastItemID = 0;
540 
541 	if (!self_reference && !resource_path && !data) return GF_BAD_PARAM;
542 	e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE);
543 	if (e) return e;
544 	meta = gf_isom_get_meta(file, root_meta, track_num);
545 	if (!meta) {
546 		GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Trying to add item, but missing meta box"));
547 		return GF_BAD_PARAM;
548 	}
549 
550 	e = FlushCaptureMode(file);
551 	if (e) return e;
552 
553 	/*check file exists */
554 	if (!URN && !URL && !self_reference && !data) {
555 		FILE *src = gf_fopen(resource_path, "rb");
556 		if (!src) return GF_URL_ERROR;
557 		gf_fclose(src);
558 	}
559 
560 	if (meta->item_infos) {
561 		u32 item_count = gf_list_count(meta->item_infos->item_infos);
562 		for (i = 0; i < item_count; i++) {
563 			GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i);
564 			if (e->item_ID > lastItemID) lastItemID = e->item_ID;
565 			if (item_id == e->item_ID) {
566 				GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item with id %d already exists, ignoring id\n", item_id));
567 				item_id = 0;
568 			}
569 		}
570 	}
571 
572 	infe = (GF_ItemInfoEntryBox *)infe_New();
573 	if (item_id) {
574 		infe->item_ID = item_id;
575 	}
576 	else {
577 		infe->item_ID = ++lastItemID;
578 	}
579 
580 	/*get relative name*/
581 	if (item_name) {
582 		infe->item_name = gf_strdup(item_name);
583 	}
584 	else if (resource_path) {
585 		if (strrchr(resource_path, GF_PATH_SEPARATOR)) {
586 			infe->item_name = gf_strdup(strrchr(resource_path, GF_PATH_SEPARATOR) + 1);
587 		}
588 		else {
589 			infe->item_name = gf_strdup(resource_path);
590 		}
591 	}
592 
593 	infe->item_type = item_type;
594 
595 	if (mime_type) {
596 		infe->content_type = gf_strdup(mime_type);
597 	}
598 	else {
599 		infe->content_type = gf_strdup("application/octet-stream");
600 	}
601 	if (content_encoding) infe->content_encoding = gf_strdup(content_encoding);
602 
603 	/*Creation of the ItemLocation */
604 	location_entry = (GF_ItemLocationEntry*)gf_malloc(sizeof(GF_ItemLocationEntry));
605 	if (!location_entry) {
606 		gf_isom_box_del((GF_Box *)infe);
607 		return GF_OUT_OF_MEM;
608 	}
609 	memset(location_entry, 0, sizeof(GF_ItemLocationEntry));
610 	location_entry->extent_entries = gf_list_new();
611 
612 	/*Creates an mdat if it does not exist*/
613 	if (!file->mdat) {
614 		file->mdat = (GF_MediaDataBox *)mdat_New();
615 		gf_list_add(file->TopBoxes, file->mdat);
616 	}
617 
618 	/*Creation an ItemLocation Box if it does not exist*/
619 	if (!meta->item_locations) meta->item_locations = (GF_ItemLocationBox *)iloc_New();
620 	gf_list_add(meta->item_locations->location_entries, location_entry);
621 	location_entry->item_ID = infe->item_ID;
622 
623 	if (!meta->item_infos) meta->item_infos = (GF_ItemInfoBox *)iinf_New();
624 	e = gf_list_add(meta->item_infos->item_infos, infe);
625 	if (e) return e;
626 
627 	if (image_props) {
628 		if (image_props->hidden) {
629 			infe->flags = 0x1;
630 		}
631 	}
632 
633 	/*0: the current file*/
634 	location_entry->data_reference_index = 0;
635 	if (self_reference) {
636 		GF_ItemExtentEntry *entry;
637 		GF_SAFEALLOC(entry, GF_ItemExtentEntry);
638 		gf_list_add(location_entry->extent_entries, entry);
639 		if (!infe->item_name) infe->item_name = gf_strdup("");
640 		return GF_OK;
641 	}
642 
643 	/*file not copied, just referenced*/
644 	if (URL || URN) {
645 		u32 dataRefIndex;
646 		if (!meta->file_locations) meta->file_locations = (GF_DataInformationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DINF);
647 		if (!meta->file_locations->dref) meta->file_locations->dref = (GF_DataReferenceBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DREF);
648 		e = Media_FindDataRef(meta->file_locations->dref, (char *)URL, (char *)URN, &dataRefIndex);
649 		if (e) return e;
650 		if (!dataRefIndex) {
651 			e = Media_CreateDataRef(meta->file_locations->dref, (char *)URL, (char *)URN, &dataRefIndex);
652 			if (e) return e;
653 		}
654 		location_entry->data_reference_index = dataRefIndex;
655 	}
656 
657 	if (item_extent_refs && gf_list_count(item_extent_refs)) {
658 		u32 refs_count;
659 		location_entry->construction_method = 2;
660 		meta->item_locations->index_size = 4;
661 		refs_count = gf_list_count(item_extent_refs);
662 		for (i = 0; i < refs_count; i++) {
663 			u32 *item_index;
664 			GF_ItemExtentEntry *entry;
665 			GF_SAFEALLOC(entry, GF_ItemExtentEntry);
666 			gf_list_add(location_entry->extent_entries, entry);
667 			item_index = (u32 *)gf_list_get(item_extent_refs, i);
668 			gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, *item_index, GF_4CC('i', 'l', 'o', 'c'), &(entry->extent_index));
669 		}
670 	}
671 	else {
672 		/*capture mode, write to disk*/
673 		if ((file->openMode == GF_ISOM_OPEN_WRITE) && !location_entry->data_reference_index) {
674 			FILE *src;
675 			GF_ItemExtentEntry *entry;
676 			GF_SAFEALLOC(entry, GF_ItemExtentEntry);
677 
678 			location_entry->base_offset = gf_bs_get_position(file->editFileMap->bs);
679 
680 			/*update base offset size*/
681 			if (location_entry->base_offset > 0xFFFFFFFF) meta->item_locations->base_offset_size = 8;
682 			else if (location_entry->base_offset && !meta->item_locations->base_offset_size) meta->item_locations->base_offset_size = 4;
683 
684 			entry->extent_length = 0;
685 			entry->extent_offset = 0;
686 			gf_list_add(location_entry->extent_entries, entry);
687 
688 			if (data) {
689 				gf_bs_write_data(file->editFileMap->bs, data, data_len);
690 				/*update length size*/
691 				if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
692 				else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
693 			}
694 			else if (resource_path) {
695 				src = gf_fopen(resource_path, "rb");
696 				if (src) {
697 					char cache_data[4096];
698 					u64 remain;
699 					gf_fseek(src, 0, SEEK_END);
700 					entry->extent_length = gf_ftell(src);
701 					gf_fseek(src, 0, SEEK_SET);
702 
703 					remain = entry->extent_length;
704 					while (remain) {
705 						u32 size_cache = (remain > 4096) ? 4096 : (u32)remain;
706 						size_t read = fread(cache_data, 1, size_cache, src);
707 						if (read == (size_t)-1) break;
708 						gf_bs_write_data(file->editFileMap->bs, cache_data, (u32)read);
709 						remain -= (u32)read;
710 					}
711 					gf_fclose(src);
712 
713 					/*update length size*/
714 					if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8;
715 					else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4;
716 				}
717 			}
718 		}
719 		/*store full path for info*/
720 		else if (!location_entry->data_reference_index) {
721 			if (data) {
722 				infe->full_path = (char *)gf_malloc(sizeof(char) * data_len);
723 				memcpy(infe->full_path, data, sizeof(char) * data_len);
724 				infe->data_len = data_len;
725 			}
726 			else {
727 				infe->full_path = gf_strdup(resource_path);
728 				infe->data_len = 0;
729 			}
730 		}
731 	}
732 	return GF_OK;
733 }
734 
735 GF_EXPORT
gf_isom_add_meta_item(GF_ISOFile * file,Bool root_meta,u32 track_num,Bool self_reference,char * resource_path,const char * item_name,u32 item_id,u32 item_type,const char * mime_type,const char * content_encoding,const char * URL,const char * URN,GF_ImageItemProperties * image_props)736 GF_Err gf_isom_add_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path, const char *item_name, u32 item_id, u32 item_type,
737 	const char *mime_type, const char *content_encoding, const char *URL, const char *URN,
738 	GF_ImageItemProperties *image_props)
739 {
740 	return gf_isom_add_meta_item_extended(file, root_meta, track_num, self_reference, resource_path, item_name, item_id, item_type, mime_type, content_encoding, image_props, URL, URN, NULL, 0, NULL);
741 }
742 
gf_isom_add_meta_item_memory(GF_ISOFile * file,Bool root_meta,u32 track_num,const char * item_name,u32 item_id,u32 item_type,const char * mime_type,const char * content_encoding,GF_ImageItemProperties * image_props,char * data,u32 data_len,GF_List * item_extent_refs)743 GF_Err gf_isom_add_meta_item_memory(GF_ISOFile *file, Bool root_meta, u32 track_num, const char *item_name, u32 item_id, u32 item_type, const char *mime_type, const char *content_encoding, GF_ImageItemProperties *image_props, char *data, u32 data_len, GF_List *item_extent_refs)
744 {
745 	return gf_isom_add_meta_item_extended(file, root_meta, track_num, GF_FALSE, NULL, item_name, item_id, item_type, mime_type, content_encoding, image_props, NULL, NULL, data, data_len, item_extent_refs);
746 }
747 
748 GF_EXPORT
gf_isom_remove_meta_item(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id)749 GF_Err gf_isom_remove_meta_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
750 {
751 	GF_ItemInfoEntryBox *iinf;
752 	u32 i, count;
753 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
754 	u32 item_num;
755 	if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
756 
757 	item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id);
758 	if (!item_num) return GF_BAD_PARAM;
759 	iinf = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1);
760 	gf_list_rem(meta->item_infos->item_infos, item_num - 1);
761 
762 	count = gf_list_count(meta->item_locations->location_entries);
763 	for (i = 0; i<count; i++) {
764 		GF_ItemLocationEntry *iloc = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i);
765 		if (iloc->item_ID == iinf->item_ID) {
766 			/*FIXME: remove data ref...*/
767 			if (iloc->data_reference_index) {}
768 
769 			gf_list_rem(meta->item_locations->location_entries, i);
770 			iloc_entry_del(iloc);
771 			break;
772 		}
773 	}
774 	gf_isom_box_del((GF_Box *)iinf);
775 	return GF_OK;
776 }
777 
778 GF_EXPORT
gf_isom_set_meta_primary_item(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 item_id)779 GF_Err gf_isom_set_meta_primary_item(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id)
780 {
781 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
782 	if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM;
783 	/*either one or the other*/
784 	if (gf_isom_has_meta_xml(file, root_meta, track_num)) return GF_BAD_PARAM;
785 
786 	if (meta->primary_resource) gf_isom_box_del((GF_Box*)meta->primary_resource);
787 	meta->primary_resource = (GF_PrimaryItemBox*)gf_isom_box_new(GF_ISOM_BOX_TYPE_PITM);
788 	meta->primary_resource->item_ID = item_id;
789 	return GF_OK;
790 }
791 
792 
793 #endif	/*GPAC_DISABLE_ISOM_WRITE*/
794 
795 GF_EXPORT
gf_isom_meta_add_item_ref(GF_ISOFile * file,Bool root_meta,u32 track_num,u32 from_id,u32 to_id,u32 type,u64 * ref_index)796 GF_Err gf_isom_meta_add_item_ref(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 from_id, u32 to_id, u32 type, u64 *ref_index)
797 {
798 	u32 i, count;
799 	s32 index = -1;
800 	GF_ItemReferenceTypeBox *ref;
801 	GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num);
802 	if (!meta) return GF_BAD_PARAM;
803 	if (!meta->item_refs) {
804 		meta->item_refs = (GF_ItemReferenceBox *)iref_New();
805 	}
806 	count = gf_list_count(meta->item_refs->references);
807 	for (i = 0; i < count; i++) {
808 		ref = (GF_ItemReferenceTypeBox *)gf_list_get(meta->item_refs->references, i);
809 		if (ref->from_item_id == from_id && ref->reference_type == type) {
810 			index = i;
811 			break;
812 		}
813 	}
814 	if (index < 0) {
815 		ref = (GF_ItemReferenceTypeBox *)ireftype_New();
816 		gf_list_add(meta->item_refs->references, ref);
817 		ref->reference_type = type;
818 		ref->from_item_id = from_id;
819 	}
820 	else {
821 		for (i = 0; i < ref->reference_count; i++) {
822 			if (ref->to_item_IDs[i] == to_id) {
823 				return GF_OK;
824 			}
825 		}
826 	}
827 
828 	ref->to_item_IDs = (u32 *)gf_realloc(ref->to_item_IDs, (ref->reference_count + 1) * sizeof(u32));
829 	if (!ref->to_item_IDs) return GF_OUT_OF_MEM;
830 	ref->to_item_IDs[ref->reference_count] = to_id;
831 	ref->reference_count++;
832 	if (ref_index) {
833 		*ref_index = ref->reference_count;
834 	}
835 	return GF_OK;
836 
837 }
838 
839 #endif /*GPAC_DISABLE_ISOM*/
840