box: Utilize meaningful error values.
[L-SMASH.git] / core / meta.c
blob79bb6499d326862deb8a924b530e50572fe8fbc5
1 /*****************************************************************************
2 * meta.c:
3 *****************************************************************************
4 * Copyright (C) 2012-2014 L-SMASH project
6 * Authors: Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 *****************************************************************************/
21 /* This file is available under an ISC license. */
23 #include "common/internal.h" /* must be placed first */
25 #include <string.h>
26 #include <stdlib.h>
28 #include "box.h"
30 static isom_data_t *isom_add_metadata( lsmash_file_t *file,
31 lsmash_itunes_metadata_item item,
32 char *meaning_string, char *name_string )
34 assert( file && file->moov );
35 if( ((item == ITUNES_METADATA_ITEM_CUSTOM) && (!meaning_string || !meaning_string[0]) )
36 || (!file->moov->udta && !isom_add_udta( file->moov ))
37 || (!file->moov->udta->meta && !isom_add_meta( file->moov->udta ))
38 || (!file->moov->udta->meta->ilst && !isom_add_ilst( file->moov->udta->meta )) )
39 return NULL;
40 if( !file->moov->udta->meta->hdlr )
42 if( !isom_add_hdlr( file->moov->udta->meta )
43 || isom_setup_handler_reference( file->moov->udta->meta->hdlr, ISOM_META_HANDLER_TYPE_ITUNES_METADATA ) < 0 )
44 return NULL;
46 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
47 if( !isom_add_metaitem( ilst, item ) )
48 return NULL;
49 isom_metaitem_t *metaitem = (isom_metaitem_t *)ilst->metaitem_list.tail->data;
50 if( item == ITUNES_METADATA_ITEM_CUSTOM )
52 if( !isom_add_mean( metaitem ) )
53 goto fail;
54 isom_mean_t *mean = metaitem->mean;
55 mean->meaning_string_length = strlen( meaning_string ); /* No null terminator */
56 mean->meaning_string = lsmash_memdup( meaning_string, mean->meaning_string_length );
57 if( !mean->meaning_string )
58 goto fail;
59 if( name_string && name_string[0] )
61 if( !isom_add_name( metaitem ) )
62 goto fail;
63 isom_name_t *name = metaitem->name;
64 name->name_length = strlen( name_string ); /* No null terminator */
65 name->name = lsmash_memdup( name_string, name->name_length );
66 if( !name->name )
67 goto fail;
70 if( !isom_add_data( metaitem ) )
71 goto fail;
72 return metaitem->data;
73 fail:
74 isom_remove_box_by_itself( metaitem );
75 return NULL;
78 static int isom_set_itunes_metadata_string( lsmash_file_t *file,
79 lsmash_itunes_metadata_item item,
80 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
82 uint32_t value_length = strlen( value.string );
83 if( item == ITUNES_METADATA_ITEM_DESCRIPTION && value_length > 255 )
84 item = ITUNES_METADATA_ITEM_LONG_DESCRIPTION;
85 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
86 if( !data )
87 return -1;
88 data->type_code = ITUNES_METADATA_SUBTYPE_UTF8;
89 data->value_length = value_length; /* No null terminator */
90 data->value = lsmash_memdup( value.string, data->value_length );
91 if( !data->value )
93 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
94 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
95 return -1;
97 return 0;
100 static int isom_set_itunes_metadata_integer( lsmash_file_t *file,
101 lsmash_itunes_metadata_item item,
102 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
104 static const struct
106 lsmash_itunes_metadata_item item;
107 int length;
108 } metadata_code_type_table[] =
110 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, 1 },
111 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, 2 },
112 { ITUNES_METADATA_ITEM_CONTENT_RATING, 1 },
113 { ITUNES_METADATA_ITEM_MEDIA_TYPE, 1 },
114 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, 2 },
115 { ITUNES_METADATA_ITEM_TV_EPISODE, 4 },
116 { ITUNES_METADATA_ITEM_TV_SEASON, 4 },
117 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, 1 },
118 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, 4 },
119 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, 4 },
120 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, 4 },
121 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, 4 },
122 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, 8 },
123 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, 4 },
124 { ITUNES_METADATA_ITEM_CUSTOM, 8 },
125 { 0, 0 }
127 int i;
128 for( i = 0; metadata_code_type_table[i].item; i++ )
129 if( item == metadata_code_type_table[i].item )
130 break;
131 if( metadata_code_type_table[i].length == 0 )
132 return -1;
133 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
134 if( !data )
135 return -1;
136 if( item == ITUNES_METADATA_ITEM_PREDEFINED_GENRE )
137 data->type_code = ITUNES_METADATA_SUBTYPE_IMPLICIT;
138 else
139 data->type_code = ITUNES_METADATA_SUBTYPE_INTEGER;
140 data->value_length = metadata_code_type_table[i].length;
141 uint8_t temp[8];
142 for( i = 0; i < data->value_length; i++ )
144 int shift = (data->value_length - i - 1) * 8;
145 temp[i] = (value.integer >> shift) & 0xff;
147 data->value = lsmash_memdup( temp, data->value_length );
148 if( !data->value )
150 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
151 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
152 return -1;
154 return 0;
157 static int isom_set_itunes_metadata_boolean( lsmash_file_t *file,
158 lsmash_itunes_metadata_item item,
159 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
161 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
162 if( !data )
163 return -1;
164 data->type_code = ITUNES_METADATA_SUBTYPE_INTEGER;
165 data->value_length = 1;
166 uint8_t temp = (uint8_t)value.boolean;
167 data->value = lsmash_memdup( &temp, 1 );
168 if( !data->value )
170 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
171 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
172 return -1;
174 return 0;
177 static int isom_set_itunes_metadata_binary( lsmash_file_t *file,
178 lsmash_itunes_metadata_item item,
179 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
181 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
182 if( !data )
183 return -1;
184 switch( item )
186 case ITUNES_METADATA_ITEM_COVER_ART :
187 if( value.binary.subtype != ITUNES_METADATA_SUBTYPE_JPEG
188 && value.binary.subtype != ITUNES_METADATA_SUBTYPE_PNG
189 && value.binary.subtype != ITUNES_METADATA_SUBTYPE_BMP )
190 return -1;
191 break;
192 case ITUNES_METADATA_ITEM_DISC_NUMBER :
193 case ITUNES_METADATA_ITEM_TRACK_NUMBER :
194 value.binary.subtype = ITUNES_METADATA_SUBTYPE_IMPLICIT;
195 break;
196 default :
197 break;
199 switch( value.binary.subtype )
201 case ITUNES_METADATA_SUBTYPE_UUID :
202 if( value.binary.size != 16 )
203 return -1;
204 break;
205 case ITUNES_METADATA_SUBTYPE_DURATION :
206 if( value.binary.size != 4 )
207 return -1;
208 break;
209 case ITUNES_METADATA_SUBTYPE_TIME :
210 if( value.binary.size != 4 && value.binary.size != 8 )
211 return -1;
212 break;
213 case ITUNES_METADATA_SUBTYPE_INTEGER :
214 if( value.binary.size != 1 && value.binary.size != 2
215 && value.binary.size != 3 && value.binary.size != 4
216 && value.binary.size != 8 )
217 return -1;
218 break;
219 case ITUNES_METADATA_SUBTYPE_RIAAPA :
220 if( value.binary.size != 1 )
221 return -1;
222 break;
223 default :
224 break;
226 data->type_code = value.binary.subtype;
227 data->value_length = value.binary.size;
228 data->value = lsmash_memdup( value.binary.data, value.binary.size );
229 if( !data->value )
231 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
232 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
233 return -1;
235 return 0;
238 int lsmash_set_itunes_metadata( lsmash_root_t *root, lsmash_itunes_metadata_t metadata )
240 if( isom_check_initializer_present( root ) < 0 )
241 return -1;
242 static const struct
244 lsmash_itunes_metadata_item item;
245 int (*func_set_itunes_metadata)( lsmash_file_t *, lsmash_itunes_metadata_item, lsmash_itunes_metadata_value_t, char *, char * );
246 } itunes_metadata_function_mapping[] =
248 { ITUNES_METADATA_ITEM_ALBUM_NAME, isom_set_itunes_metadata_string },
249 { ITUNES_METADATA_ITEM_ARTIST, isom_set_itunes_metadata_string },
250 { ITUNES_METADATA_ITEM_USER_COMMENT, isom_set_itunes_metadata_string },
251 { ITUNES_METADATA_ITEM_RELEASE_DATE, isom_set_itunes_metadata_string },
252 { ITUNES_METADATA_ITEM_ENCODED_BY, isom_set_itunes_metadata_string },
253 { ITUNES_METADATA_ITEM_USER_GENRE, isom_set_itunes_metadata_string },
254 { ITUNES_METADATA_ITEM_GROUPING, isom_set_itunes_metadata_string },
255 { ITUNES_METADATA_ITEM_LYRICS, isom_set_itunes_metadata_string },
256 { ITUNES_METADATA_ITEM_TITLE, isom_set_itunes_metadata_string },
257 { ITUNES_METADATA_ITEM_TRACK_SUBTITLE, isom_set_itunes_metadata_string },
258 { ITUNES_METADATA_ITEM_ENCODING_TOOL, isom_set_itunes_metadata_string },
259 { ITUNES_METADATA_ITEM_COMPOSER, isom_set_itunes_metadata_string },
260 { ITUNES_METADATA_ITEM_ALBUM_ARTIST, isom_set_itunes_metadata_string },
261 { ITUNES_METADATA_ITEM_PODCAST_CATEGORY, isom_set_itunes_metadata_string },
262 { ITUNES_METADATA_ITEM_COPYRIGHT, isom_set_itunes_metadata_string },
263 { ITUNES_METADATA_ITEM_DESCRIPTION, isom_set_itunes_metadata_string },
264 { ITUNES_METADATA_ITEM_GROUPING_DRAFT, isom_set_itunes_metadata_string },
265 { ITUNES_METADATA_ITEM_PODCAST_KEYWORD, isom_set_itunes_metadata_string },
266 { ITUNES_METADATA_ITEM_LONG_DESCRIPTION, isom_set_itunes_metadata_string },
267 { ITUNES_METADATA_ITEM_PURCHASE_DATE, isom_set_itunes_metadata_string },
268 { ITUNES_METADATA_ITEM_TV_EPISODE_ID, isom_set_itunes_metadata_string },
269 { ITUNES_METADATA_ITEM_TV_NETWORK, isom_set_itunes_metadata_string },
270 { ITUNES_METADATA_ITEM_TV_SHOW_NAME, isom_set_itunes_metadata_string },
271 { ITUNES_METADATA_ITEM_ITUNES_PURCHASE_ACCOUNT_ID, isom_set_itunes_metadata_string },
272 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM, isom_set_itunes_metadata_string },
273 { ITUNES_METADATA_ITEM_ITUNES_SORT_ARTIST, isom_set_itunes_metadata_string },
274 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM_ARTIST, isom_set_itunes_metadata_string },
275 { ITUNES_METADATA_ITEM_ITUNES_SORT_COMPOSER, isom_set_itunes_metadata_string },
276 { ITUNES_METADATA_ITEM_ITUNES_SORT_NAME, isom_set_itunes_metadata_string },
277 { ITUNES_METADATA_ITEM_ITUNES_SORT_SHOW, isom_set_itunes_metadata_string },
278 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, isom_set_itunes_metadata_integer },
279 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, isom_set_itunes_metadata_integer },
280 { ITUNES_METADATA_ITEM_CONTENT_RATING, isom_set_itunes_metadata_integer },
281 { ITUNES_METADATA_ITEM_MEDIA_TYPE, isom_set_itunes_metadata_integer },
282 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, isom_set_itunes_metadata_integer },
283 { ITUNES_METADATA_ITEM_TV_EPISODE, isom_set_itunes_metadata_integer },
284 { ITUNES_METADATA_ITEM_TV_SEASON, isom_set_itunes_metadata_integer },
285 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, isom_set_itunes_metadata_integer },
286 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, isom_set_itunes_metadata_integer },
287 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, isom_set_itunes_metadata_integer },
288 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, isom_set_itunes_metadata_integer },
289 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, isom_set_itunes_metadata_integer },
290 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, isom_set_itunes_metadata_integer },
291 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, isom_set_itunes_metadata_integer },
292 { ITUNES_METADATA_ITEM_DISC_COMPILATION, isom_set_itunes_metadata_boolean },
293 { ITUNES_METADATA_ITEM_HIGH_DEFINITION_VIDEO, isom_set_itunes_metadata_boolean },
294 { ITUNES_METADATA_ITEM_PODCAST, isom_set_itunes_metadata_boolean },
295 { ITUNES_METADATA_ITEM_GAPLESS_PLAYBACK, isom_set_itunes_metadata_boolean },
296 { ITUNES_METADATA_ITEM_COVER_ART, isom_set_itunes_metadata_binary },
297 { ITUNES_METADATA_ITEM_DISC_NUMBER, isom_set_itunes_metadata_binary },
298 { ITUNES_METADATA_ITEM_TRACK_NUMBER, isom_set_itunes_metadata_binary },
299 { 0, NULL }
301 lsmash_file_t *file = root->file;
302 for( int i = 0; itunes_metadata_function_mapping[i].func_set_itunes_metadata; i++ )
303 if( metadata.item == itunes_metadata_function_mapping[i].item )
304 return itunes_metadata_function_mapping[i].func_set_itunes_metadata( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
305 if( metadata.item == ITUNES_METADATA_ITEM_CUSTOM )
306 switch( metadata.type )
308 case ITUNES_METADATA_TYPE_STRING :
309 return isom_set_itunes_metadata_string( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
310 case ITUNES_METADATA_TYPE_INTEGER :
311 return isom_set_itunes_metadata_integer( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
312 case ITUNES_METADATA_TYPE_BOOLEAN :
313 return isom_set_itunes_metadata_boolean( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
314 case ITUNES_METADATA_TYPE_BINARY :
315 return isom_set_itunes_metadata_binary( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
316 default :
317 break;
319 return -1;
322 static lsmash_itunes_metadata_type isom_get_itunes_metadata_type( lsmash_itunes_metadata_item item )
324 static const struct
326 lsmash_itunes_metadata_item item;
327 lsmash_itunes_metadata_type type;
328 } itunes_metadata_item_type_mapping[] =
330 { ITUNES_METADATA_ITEM_ALBUM_NAME, ITUNES_METADATA_TYPE_STRING },
331 { ITUNES_METADATA_ITEM_ARTIST, ITUNES_METADATA_TYPE_STRING },
332 { ITUNES_METADATA_ITEM_USER_COMMENT, ITUNES_METADATA_TYPE_STRING },
333 { ITUNES_METADATA_ITEM_RELEASE_DATE, ITUNES_METADATA_TYPE_STRING },
334 { ITUNES_METADATA_ITEM_ENCODED_BY, ITUNES_METADATA_TYPE_STRING },
335 { ITUNES_METADATA_ITEM_USER_GENRE, ITUNES_METADATA_TYPE_STRING },
336 { ITUNES_METADATA_ITEM_GROUPING, ITUNES_METADATA_TYPE_STRING },
337 { ITUNES_METADATA_ITEM_LYRICS, ITUNES_METADATA_TYPE_STRING },
338 { ITUNES_METADATA_ITEM_TITLE, ITUNES_METADATA_TYPE_STRING },
339 { ITUNES_METADATA_ITEM_TRACK_SUBTITLE, ITUNES_METADATA_TYPE_STRING },
340 { ITUNES_METADATA_ITEM_ENCODING_TOOL, ITUNES_METADATA_TYPE_STRING },
341 { ITUNES_METADATA_ITEM_COMPOSER, ITUNES_METADATA_TYPE_STRING },
342 { ITUNES_METADATA_ITEM_ALBUM_ARTIST, ITUNES_METADATA_TYPE_STRING },
343 { ITUNES_METADATA_ITEM_PODCAST_CATEGORY, ITUNES_METADATA_TYPE_STRING },
344 { ITUNES_METADATA_ITEM_COPYRIGHT, ITUNES_METADATA_TYPE_STRING },
345 { ITUNES_METADATA_ITEM_DESCRIPTION, ITUNES_METADATA_TYPE_STRING },
346 { ITUNES_METADATA_ITEM_GROUPING_DRAFT, ITUNES_METADATA_TYPE_STRING },
347 { ITUNES_METADATA_ITEM_PODCAST_KEYWORD, ITUNES_METADATA_TYPE_STRING },
348 { ITUNES_METADATA_ITEM_LONG_DESCRIPTION, ITUNES_METADATA_TYPE_STRING },
349 { ITUNES_METADATA_ITEM_PURCHASE_DATE, ITUNES_METADATA_TYPE_STRING },
350 { ITUNES_METADATA_ITEM_TV_EPISODE_ID, ITUNES_METADATA_TYPE_STRING },
351 { ITUNES_METADATA_ITEM_TV_NETWORK, ITUNES_METADATA_TYPE_STRING },
352 { ITUNES_METADATA_ITEM_TV_SHOW_NAME, ITUNES_METADATA_TYPE_STRING },
353 { ITUNES_METADATA_ITEM_ITUNES_PURCHASE_ACCOUNT_ID, ITUNES_METADATA_TYPE_STRING },
354 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM, ITUNES_METADATA_TYPE_STRING },
355 { ITUNES_METADATA_ITEM_ITUNES_SORT_ARTIST, ITUNES_METADATA_TYPE_STRING },
356 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM_ARTIST, ITUNES_METADATA_TYPE_STRING },
357 { ITUNES_METADATA_ITEM_ITUNES_SORT_COMPOSER, ITUNES_METADATA_TYPE_STRING },
358 { ITUNES_METADATA_ITEM_ITUNES_SORT_NAME, ITUNES_METADATA_TYPE_STRING },
359 { ITUNES_METADATA_ITEM_ITUNES_SORT_SHOW, ITUNES_METADATA_TYPE_STRING },
360 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, ITUNES_METADATA_TYPE_INTEGER },
361 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, ITUNES_METADATA_TYPE_INTEGER },
362 { ITUNES_METADATA_ITEM_CONTENT_RATING, ITUNES_METADATA_TYPE_INTEGER },
363 { ITUNES_METADATA_ITEM_MEDIA_TYPE, ITUNES_METADATA_TYPE_INTEGER },
364 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, ITUNES_METADATA_TYPE_INTEGER },
365 { ITUNES_METADATA_ITEM_TV_EPISODE, ITUNES_METADATA_TYPE_INTEGER },
366 { ITUNES_METADATA_ITEM_TV_SEASON, ITUNES_METADATA_TYPE_INTEGER },
367 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, ITUNES_METADATA_TYPE_INTEGER },
368 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, ITUNES_METADATA_TYPE_INTEGER },
369 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, ITUNES_METADATA_TYPE_INTEGER },
370 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, ITUNES_METADATA_TYPE_INTEGER },
371 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, ITUNES_METADATA_TYPE_INTEGER },
372 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, ITUNES_METADATA_TYPE_INTEGER },
373 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, ITUNES_METADATA_TYPE_INTEGER },
374 { ITUNES_METADATA_ITEM_DISC_COMPILATION, ITUNES_METADATA_TYPE_BOOLEAN },
375 { ITUNES_METADATA_ITEM_HIGH_DEFINITION_VIDEO, ITUNES_METADATA_TYPE_BOOLEAN },
376 { ITUNES_METADATA_ITEM_PODCAST, ITUNES_METADATA_TYPE_BOOLEAN },
377 { ITUNES_METADATA_ITEM_GAPLESS_PLAYBACK, ITUNES_METADATA_TYPE_BOOLEAN },
378 { ITUNES_METADATA_ITEM_COVER_ART, ITUNES_METADATA_TYPE_BINARY },
379 { ITUNES_METADATA_ITEM_DISC_NUMBER, ITUNES_METADATA_TYPE_BINARY },
380 { ITUNES_METADATA_ITEM_TRACK_NUMBER, ITUNES_METADATA_TYPE_BINARY },
381 { 0, ITUNES_METADATA_TYPE_NONE }
383 for( int i = 0; itunes_metadata_item_type_mapping[i].type != ITUNES_METADATA_TYPE_NONE; i++ )
384 if( item == itunes_metadata_item_type_mapping[i].item )
385 return itunes_metadata_item_type_mapping[i].type;
386 return ITUNES_METADATA_TYPE_NONE;
389 int lsmash_get_itunes_metadata( lsmash_root_t *root, uint32_t metadata_number, lsmash_itunes_metadata_t *metadata )
391 if( isom_check_initializer_present( root ) < 0 || !metadata )
392 return -1;
393 lsmash_file_t *file = root->file->initializer;
394 if( !file->moov
395 || !file->moov->udta
396 || !file->moov->udta->meta
397 || !file->moov->udta->meta->ilst )
398 return -1;
399 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
400 isom_metaitem_t *metaitem = (isom_metaitem_t *)lsmash_get_entry_data( &ilst->metaitem_list, metadata_number );
401 if( !metaitem || !metaitem->data || !metaitem->data->value || metaitem->data->value_length == 0 )
402 return -1;
403 /* Get 'item'. */
404 metadata->item = metaitem->type.fourcc;
405 /* Get 'type'. */
406 metadata->type = isom_get_itunes_metadata_type( metadata->item );
407 /* Get 'meaning'. */
408 isom_mean_t *mean = metaitem->mean;
409 if( mean )
411 uint8_t *temp = lsmash_malloc( mean->meaning_string_length + 1 );
412 if( !temp )
413 goto fail;
414 memcpy( temp, mean->meaning_string, mean->meaning_string_length );
415 temp[ mean->meaning_string_length ] = 0;
416 metadata->meaning = (char *)temp;
418 else
419 metadata->meaning = NULL;
420 /* Get 'name'. */
421 isom_name_t *name = metaitem->name;
422 if( name )
424 uint8_t *temp = lsmash_malloc( name->name_length + 1 );
425 if( !temp )
426 goto fail;
427 memcpy( temp, name->name, name->name_length );
428 temp[ name->name_length ] = 0;
429 metadata->name = (char *)temp;
431 else
432 metadata->name = NULL;
433 /* Get 'value'. */
434 isom_data_t *data = metaitem->data;
435 switch( metadata->type )
437 case ITUNES_METADATA_TYPE_STRING :
439 uint8_t *temp = lsmash_malloc( data->value_length + 1 );
440 if( !temp )
441 goto fail;
442 memcpy( temp, data->value, data->value_length );
443 temp[ data->value_length ] = 0;
444 metadata->value.string = (char *)temp;
445 break;
447 case ITUNES_METADATA_TYPE_INTEGER :
448 if( data->value_length > 8 )
449 return -1;
450 metadata->value.integer = 0;
451 for( uint32_t i = 0; i < data->value_length; i++ )
453 int shift = (data->value_length - i - 1) * 8;
454 metadata->value.integer |= (uint64_t)data->value[i] << shift;
456 break;
457 case ITUNES_METADATA_TYPE_BOOLEAN :
458 metadata->value.boolean = !!data->value[0];
459 break;
460 default :
461 metadata->type = ITUNES_METADATA_TYPE_BINARY;
462 metadata->value.binary.subtype = data->type_code;
463 metadata->value.binary.size = data->value_length;
464 metadata->value.binary.data = lsmash_memdup( data->value, data->value_length );
465 if( !metadata->value.binary.data )
466 goto fail;
467 break;
469 return 0;
470 fail:
471 lsmash_freep( &metadata->meaning );
472 lsmash_freep( &metadata->name );
473 return -1;
476 uint32_t lsmash_count_itunes_metadata( lsmash_root_t *root )
478 if( isom_check_initializer_present( root ) < 0
479 || !root->file->initializer->moov
480 || !root->file->initializer->moov->udta
481 || !root->file->initializer->moov->udta->meta
482 || !root->file->initializer->moov->udta->meta->ilst )
483 return 0;
484 return root->file->initializer->moov->udta->meta->ilst->metaitem_list.entry_count;
487 void lsmash_cleanup_itunes_metadata( lsmash_itunes_metadata_t *metadata )
489 if( !metadata )
490 return;
491 lsmash_freep( &metadata->meaning );
492 lsmash_freep( &metadata->name );
493 if( metadata->type == ITUNES_METADATA_TYPE_STRING )
494 lsmash_freep( &metadata->value.string );
495 else if( metadata->type == ITUNES_METADATA_TYPE_BINARY )
496 lsmash_freep( &metadata->value.binary.data );