meta: Check non-existing box properly when counting itunes metadata.
[L-SMASH.git] / core / meta.c
blobdc871872361cd3fe05ce81e36b8ebb957572b22b
1 /*****************************************************************************
2 * meta.c
3 *****************************************************************************
4 * Copyright (C) 2012-2017 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"
29 #include "box_default.h"
31 static isom_data_t *isom_add_metadata( lsmash_file_t *file,
32 lsmash_itunes_metadata_item item,
33 char *meaning_string, char *name_string )
35 assert( LSMASH_IS_EXISTING_BOX( file->moov ) );
36 if( ((item == ITUNES_METADATA_ITEM_CUSTOM) && (!meaning_string || !meaning_string[0]) )
37 || (LSMASH_IS_NON_EXISTING_BOX( file->moov->udta )
38 && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_udta( file->moov ) ))
39 || (LSMASH_IS_NON_EXISTING_BOX( file->moov->udta->meta )
40 && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_meta( file->moov->udta ) ))
41 || (LSMASH_IS_NON_EXISTING_BOX( file->moov->udta->meta->ilst )
42 && LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_ilst( file->moov->udta->meta ) )) )
43 return isom_non_existing_data();
44 if( LSMASH_IS_NON_EXISTING_BOX( file->moov->udta->meta->hdlr ) )
46 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_hdlr( file->moov->udta->meta ) )
47 || isom_setup_handler_reference( file->moov->udta->meta->hdlr, ISOM_META_HANDLER_TYPE_ITUNES_METADATA ) < 0 )
48 return isom_non_existing_data();
50 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
51 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_metaitem( ilst, item ) ) )
52 return isom_non_existing_data();
53 isom_metaitem_t *metaitem = (isom_metaitem_t *)ilst->metaitem_list.tail->data;
54 if( item == ITUNES_METADATA_ITEM_CUSTOM )
56 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_mean( metaitem ) ) )
57 goto fail;
58 isom_mean_t *mean = metaitem->mean;
59 mean->meaning_string_length = strlen( meaning_string ); /* No null terminator */
60 mean->meaning_string = lsmash_memdup( meaning_string, mean->meaning_string_length );
61 if( !mean->meaning_string )
62 goto fail;
63 if( name_string && name_string[0] )
65 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_name( metaitem ) ) )
66 goto fail;
67 isom_name_t *name = metaitem->name;
68 name->name_length = strlen( name_string ); /* No null terminator */
69 name->name = lsmash_memdup( name_string, name->name_length );
70 if( !name->name )
71 goto fail;
74 if( LSMASH_IS_BOX_ADDITION_FAILURE( isom_add_data( metaitem ) ) )
75 goto fail;
76 return metaitem->data;
77 fail:
78 isom_remove_box_by_itself( metaitem );
79 return isom_non_existing_data();
82 static int isom_set_itunes_metadata_string( lsmash_file_t *file,
83 lsmash_itunes_metadata_item item,
84 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
86 uint32_t value_length = strlen( value.string );
87 if( item == ITUNES_METADATA_ITEM_DESCRIPTION && value_length > 255 )
88 item = ITUNES_METADATA_ITEM_LONG_DESCRIPTION;
89 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
90 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
91 return LSMASH_ERR_NAMELESS;
92 data->type_code = ITUNES_METADATA_SUBTYPE_UTF8;
93 data->value_length = value_length; /* No null terminator */
94 data->value = lsmash_memdup( value.string, data->value_length );
95 if( !data->value )
97 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
98 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
99 return LSMASH_ERR_MEMORY_ALLOC;
101 return 0;
104 static int isom_set_itunes_metadata_integer( lsmash_file_t *file,
105 lsmash_itunes_metadata_item item,
106 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
108 static const struct
110 lsmash_itunes_metadata_item item;
111 int length;
112 } metadata_code_type_table[] =
114 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, 1 },
115 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, 2 },
116 { ITUNES_METADATA_ITEM_CONTENT_RATING, 1 },
117 { ITUNES_METADATA_ITEM_MEDIA_TYPE, 1 },
118 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, 2 },
119 { ITUNES_METADATA_ITEM_TV_EPISODE, 4 },
120 { ITUNES_METADATA_ITEM_TV_SEASON, 4 },
121 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, 1 },
122 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, 4 },
123 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, 4 },
124 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, 4 },
125 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, 4 },
126 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, 8 },
127 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, 4 },
128 { ITUNES_METADATA_ITEM_CUSTOM, 8 },
129 { 0, 0 }
131 int i;
132 for( i = 0; metadata_code_type_table[i].item; i++ )
133 if( item == metadata_code_type_table[i].item )
134 break;
135 if( metadata_code_type_table[i].length == 0 )
136 return LSMASH_ERR_NAMELESS;
137 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
138 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
139 return LSMASH_ERR_NAMELESS;
140 if( item == ITUNES_METADATA_ITEM_PREDEFINED_GENRE )
141 data->type_code = ITUNES_METADATA_SUBTYPE_IMPLICIT;
142 else
143 data->type_code = ITUNES_METADATA_SUBTYPE_INTEGER;
144 data->value_length = metadata_code_type_table[i].length;
145 uint8_t temp[8];
146 for( i = 0; i < data->value_length; i++ )
148 int shift = (data->value_length - i - 1) * 8;
149 temp[i] = (value.integer >> shift) & 0xff;
151 data->value = lsmash_memdup( temp, data->value_length );
152 if( !data->value )
154 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
155 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
156 return LSMASH_ERR_MEMORY_ALLOC;
158 return 0;
161 static int isom_set_itunes_metadata_boolean( lsmash_file_t *file,
162 lsmash_itunes_metadata_item item,
163 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
165 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
166 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
167 return LSMASH_ERR_NAMELESS;
168 data->type_code = ITUNES_METADATA_SUBTYPE_INTEGER;
169 data->value_length = 1;
170 uint8_t temp = (uint8_t)value.boolean;
171 data->value = lsmash_memdup( &temp, 1 );
172 if( !data->value )
174 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
175 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
176 return LSMASH_ERR_MEMORY_ALLOC;
178 return 0;
181 static int isom_set_itunes_metadata_binary( lsmash_file_t *file,
182 lsmash_itunes_metadata_item item,
183 lsmash_itunes_metadata_value_t value, char *meaning, char *name )
185 isom_data_t *data = isom_add_metadata( file, item, meaning, name );
186 if( LSMASH_IS_NON_EXISTING_BOX( data ) )
187 return LSMASH_ERR_NAMELESS;
188 switch( item )
190 case ITUNES_METADATA_ITEM_COVER_ART :
191 if( value.binary.subtype != ITUNES_METADATA_SUBTYPE_JPEG
192 && value.binary.subtype != ITUNES_METADATA_SUBTYPE_PNG
193 && value.binary.subtype != ITUNES_METADATA_SUBTYPE_BMP )
194 return LSMASH_ERR_FUNCTION_PARAM;
195 break;
196 case ITUNES_METADATA_ITEM_DISC_NUMBER :
197 case ITUNES_METADATA_ITEM_TRACK_NUMBER :
198 value.binary.subtype = ITUNES_METADATA_SUBTYPE_IMPLICIT;
199 break;
200 default :
201 break;
203 switch( value.binary.subtype )
205 case ITUNES_METADATA_SUBTYPE_UUID :
206 if( value.binary.size != 16 )
207 return LSMASH_ERR_FUNCTION_PARAM;
208 break;
209 case ITUNES_METADATA_SUBTYPE_DURATION :
210 if( value.binary.size != 4 )
211 return LSMASH_ERR_FUNCTION_PARAM;
212 break;
213 case ITUNES_METADATA_SUBTYPE_TIME :
214 if( value.binary.size != 4 && value.binary.size != 8 )
215 return LSMASH_ERR_FUNCTION_PARAM;
216 break;
217 case ITUNES_METADATA_SUBTYPE_INTEGER :
218 if( value.binary.size != 1 && value.binary.size != 2
219 && value.binary.size != 3 && value.binary.size != 4
220 && value.binary.size != 8 )
221 return LSMASH_ERR_FUNCTION_PARAM;
222 break;
223 case ITUNES_METADATA_SUBTYPE_RIAAPA :
224 if( value.binary.size != 1 )
225 return LSMASH_ERR_FUNCTION_PARAM;
226 break;
227 default :
228 break;
230 data->type_code = value.binary.subtype;
231 data->value_length = value.binary.size;
232 data->value = lsmash_memdup( value.binary.data, value.binary.size );
233 if( !data->value )
235 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
236 isom_remove_box_by_itself( ilst->metaitem_list.tail->data );
237 return LSMASH_ERR_MEMORY_ALLOC;
239 return 0;
242 int lsmash_set_itunes_metadata( lsmash_root_t *root, lsmash_itunes_metadata_t metadata )
244 if( isom_check_initializer_present( root ) < 0 )
245 return LSMASH_ERR_FUNCTION_PARAM;
246 static const struct
248 lsmash_itunes_metadata_item item;
249 int (*func_set_itunes_metadata)( lsmash_file_t *, lsmash_itunes_metadata_item, lsmash_itunes_metadata_value_t, char *, char * );
250 } itunes_metadata_function_mapping[] =
252 { ITUNES_METADATA_ITEM_ALBUM_NAME, isom_set_itunes_metadata_string },
253 { ITUNES_METADATA_ITEM_ARTIST, isom_set_itunes_metadata_string },
254 { ITUNES_METADATA_ITEM_USER_COMMENT, isom_set_itunes_metadata_string },
255 { ITUNES_METADATA_ITEM_RELEASE_DATE, isom_set_itunes_metadata_string },
256 { ITUNES_METADATA_ITEM_ENCODED_BY, isom_set_itunes_metadata_string },
257 { ITUNES_METADATA_ITEM_USER_GENRE, isom_set_itunes_metadata_string },
258 { ITUNES_METADATA_ITEM_GROUPING, isom_set_itunes_metadata_string },
259 { ITUNES_METADATA_ITEM_LYRICS, isom_set_itunes_metadata_string },
260 { ITUNES_METADATA_ITEM_TITLE, isom_set_itunes_metadata_string },
261 { ITUNES_METADATA_ITEM_TRACK_SUBTITLE, isom_set_itunes_metadata_string },
262 { ITUNES_METADATA_ITEM_ENCODING_TOOL, isom_set_itunes_metadata_string },
263 { ITUNES_METADATA_ITEM_COMPOSER, isom_set_itunes_metadata_string },
264 { ITUNES_METADATA_ITEM_ALBUM_ARTIST, isom_set_itunes_metadata_string },
265 { ITUNES_METADATA_ITEM_PODCAST_CATEGORY, isom_set_itunes_metadata_string },
266 { ITUNES_METADATA_ITEM_COPYRIGHT, isom_set_itunes_metadata_string },
267 { ITUNES_METADATA_ITEM_DESCRIPTION, isom_set_itunes_metadata_string },
268 { ITUNES_METADATA_ITEM_GROUPING_DRAFT, isom_set_itunes_metadata_string },
269 { ITUNES_METADATA_ITEM_PODCAST_KEYWORD, isom_set_itunes_metadata_string },
270 { ITUNES_METADATA_ITEM_LONG_DESCRIPTION, isom_set_itunes_metadata_string },
271 { ITUNES_METADATA_ITEM_PURCHASE_DATE, isom_set_itunes_metadata_string },
272 { ITUNES_METADATA_ITEM_TV_EPISODE_ID, isom_set_itunes_metadata_string },
273 { ITUNES_METADATA_ITEM_TV_NETWORK, isom_set_itunes_metadata_string },
274 { ITUNES_METADATA_ITEM_TV_SHOW_NAME, isom_set_itunes_metadata_string },
275 { ITUNES_METADATA_ITEM_ITUNES_PURCHASE_ACCOUNT_ID, isom_set_itunes_metadata_string },
276 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM, isom_set_itunes_metadata_string },
277 { ITUNES_METADATA_ITEM_ITUNES_SORT_ARTIST, isom_set_itunes_metadata_string },
278 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM_ARTIST, isom_set_itunes_metadata_string },
279 { ITUNES_METADATA_ITEM_ITUNES_SORT_COMPOSER, isom_set_itunes_metadata_string },
280 { ITUNES_METADATA_ITEM_ITUNES_SORT_NAME, isom_set_itunes_metadata_string },
281 { ITUNES_METADATA_ITEM_ITUNES_SORT_SHOW, isom_set_itunes_metadata_string },
282 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, isom_set_itunes_metadata_integer },
283 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, isom_set_itunes_metadata_integer },
284 { ITUNES_METADATA_ITEM_CONTENT_RATING, isom_set_itunes_metadata_integer },
285 { ITUNES_METADATA_ITEM_MEDIA_TYPE, isom_set_itunes_metadata_integer },
286 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, isom_set_itunes_metadata_integer },
287 { ITUNES_METADATA_ITEM_TV_EPISODE, isom_set_itunes_metadata_integer },
288 { ITUNES_METADATA_ITEM_TV_SEASON, isom_set_itunes_metadata_integer },
289 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, isom_set_itunes_metadata_integer },
290 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, isom_set_itunes_metadata_integer },
291 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, isom_set_itunes_metadata_integer },
292 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, isom_set_itunes_metadata_integer },
293 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, isom_set_itunes_metadata_integer },
294 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, isom_set_itunes_metadata_integer },
295 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, isom_set_itunes_metadata_integer },
296 { ITUNES_METADATA_ITEM_DISC_COMPILATION, isom_set_itunes_metadata_boolean },
297 { ITUNES_METADATA_ITEM_HIGH_DEFINITION_VIDEO, isom_set_itunes_metadata_boolean },
298 { ITUNES_METADATA_ITEM_PODCAST, isom_set_itunes_metadata_boolean },
299 { ITUNES_METADATA_ITEM_GAPLESS_PLAYBACK, isom_set_itunes_metadata_boolean },
300 { ITUNES_METADATA_ITEM_COVER_ART, isom_set_itunes_metadata_binary },
301 { ITUNES_METADATA_ITEM_DISC_NUMBER, isom_set_itunes_metadata_binary },
302 { ITUNES_METADATA_ITEM_TRACK_NUMBER, isom_set_itunes_metadata_binary },
303 { 0, NULL }
305 lsmash_file_t *file = root->file;
306 for( int i = 0; itunes_metadata_function_mapping[i].func_set_itunes_metadata; i++ )
307 if( metadata.item == itunes_metadata_function_mapping[i].item )
308 return itunes_metadata_function_mapping[i].func_set_itunes_metadata( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
309 if( metadata.item == ITUNES_METADATA_ITEM_CUSTOM )
310 switch( metadata.type )
312 case ITUNES_METADATA_TYPE_STRING :
313 return isom_set_itunes_metadata_string( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
314 case ITUNES_METADATA_TYPE_INTEGER :
315 return isom_set_itunes_metadata_integer( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
316 case ITUNES_METADATA_TYPE_BOOLEAN :
317 return isom_set_itunes_metadata_boolean( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
318 case ITUNES_METADATA_TYPE_BINARY :
319 return isom_set_itunes_metadata_binary( file, metadata.item, metadata.value, metadata.meaning, metadata.name );
320 default :
321 break;
323 return LSMASH_ERR_FUNCTION_PARAM;
326 static lsmash_itunes_metadata_type isom_get_itunes_metadata_type( lsmash_itunes_metadata_item item )
328 static const struct
330 lsmash_itunes_metadata_item item;
331 lsmash_itunes_metadata_type type;
332 } itunes_metadata_item_type_mapping[] =
334 { ITUNES_METADATA_ITEM_ALBUM_NAME, ITUNES_METADATA_TYPE_STRING },
335 { ITUNES_METADATA_ITEM_ARTIST, ITUNES_METADATA_TYPE_STRING },
336 { ITUNES_METADATA_ITEM_USER_COMMENT, ITUNES_METADATA_TYPE_STRING },
337 { ITUNES_METADATA_ITEM_RELEASE_DATE, ITUNES_METADATA_TYPE_STRING },
338 { ITUNES_METADATA_ITEM_ENCODED_BY, ITUNES_METADATA_TYPE_STRING },
339 { ITUNES_METADATA_ITEM_USER_GENRE, ITUNES_METADATA_TYPE_STRING },
340 { ITUNES_METADATA_ITEM_GROUPING, ITUNES_METADATA_TYPE_STRING },
341 { ITUNES_METADATA_ITEM_LYRICS, ITUNES_METADATA_TYPE_STRING },
342 { ITUNES_METADATA_ITEM_TITLE, ITUNES_METADATA_TYPE_STRING },
343 { ITUNES_METADATA_ITEM_TRACK_SUBTITLE, ITUNES_METADATA_TYPE_STRING },
344 { ITUNES_METADATA_ITEM_ENCODING_TOOL, ITUNES_METADATA_TYPE_STRING },
345 { ITUNES_METADATA_ITEM_COMPOSER, ITUNES_METADATA_TYPE_STRING },
346 { ITUNES_METADATA_ITEM_ALBUM_ARTIST, ITUNES_METADATA_TYPE_STRING },
347 { ITUNES_METADATA_ITEM_PODCAST_CATEGORY, ITUNES_METADATA_TYPE_STRING },
348 { ITUNES_METADATA_ITEM_COPYRIGHT, ITUNES_METADATA_TYPE_STRING },
349 { ITUNES_METADATA_ITEM_DESCRIPTION, ITUNES_METADATA_TYPE_STRING },
350 { ITUNES_METADATA_ITEM_GROUPING_DRAFT, ITUNES_METADATA_TYPE_STRING },
351 { ITUNES_METADATA_ITEM_PODCAST_KEYWORD, ITUNES_METADATA_TYPE_STRING },
352 { ITUNES_METADATA_ITEM_LONG_DESCRIPTION, ITUNES_METADATA_TYPE_STRING },
353 { ITUNES_METADATA_ITEM_PURCHASE_DATE, ITUNES_METADATA_TYPE_STRING },
354 { ITUNES_METADATA_ITEM_TV_EPISODE_ID, ITUNES_METADATA_TYPE_STRING },
355 { ITUNES_METADATA_ITEM_TV_NETWORK, ITUNES_METADATA_TYPE_STRING },
356 { ITUNES_METADATA_ITEM_TV_SHOW_NAME, ITUNES_METADATA_TYPE_STRING },
357 { ITUNES_METADATA_ITEM_ITUNES_PURCHASE_ACCOUNT_ID, ITUNES_METADATA_TYPE_STRING },
358 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM, ITUNES_METADATA_TYPE_STRING },
359 { ITUNES_METADATA_ITEM_ITUNES_SORT_ARTIST, ITUNES_METADATA_TYPE_STRING },
360 { ITUNES_METADATA_ITEM_ITUNES_SORT_ALBUM_ARTIST, ITUNES_METADATA_TYPE_STRING },
361 { ITUNES_METADATA_ITEM_ITUNES_SORT_COMPOSER, ITUNES_METADATA_TYPE_STRING },
362 { ITUNES_METADATA_ITEM_ITUNES_SORT_NAME, ITUNES_METADATA_TYPE_STRING },
363 { ITUNES_METADATA_ITEM_ITUNES_SORT_SHOW, ITUNES_METADATA_TYPE_STRING },
364 { ITUNES_METADATA_ITEM_EPISODE_GLOBAL_ID, ITUNES_METADATA_TYPE_INTEGER },
365 { ITUNES_METADATA_ITEM_PREDEFINED_GENRE, ITUNES_METADATA_TYPE_INTEGER },
366 { ITUNES_METADATA_ITEM_CONTENT_RATING, ITUNES_METADATA_TYPE_INTEGER },
367 { ITUNES_METADATA_ITEM_MEDIA_TYPE, ITUNES_METADATA_TYPE_INTEGER },
368 { ITUNES_METADATA_ITEM_BEATS_PER_MINUTE, ITUNES_METADATA_TYPE_INTEGER },
369 { ITUNES_METADATA_ITEM_TV_EPISODE, ITUNES_METADATA_TYPE_INTEGER },
370 { ITUNES_METADATA_ITEM_TV_SEASON, ITUNES_METADATA_TYPE_INTEGER },
371 { ITUNES_METADATA_ITEM_ITUNES_ACCOUNT_TYPE, ITUNES_METADATA_TYPE_INTEGER },
372 { ITUNES_METADATA_ITEM_ITUNES_ARTIST_ID, ITUNES_METADATA_TYPE_INTEGER },
373 { ITUNES_METADATA_ITEM_ITUNES_COMPOSER_ID, ITUNES_METADATA_TYPE_INTEGER },
374 { ITUNES_METADATA_ITEM_ITUNES_CATALOG_ID, ITUNES_METADATA_TYPE_INTEGER },
375 { ITUNES_METADATA_ITEM_ITUNES_TV_GENRE_ID, ITUNES_METADATA_TYPE_INTEGER },
376 { ITUNES_METADATA_ITEM_ITUNES_PLAYLIST_ID, ITUNES_METADATA_TYPE_INTEGER },
377 { ITUNES_METADATA_ITEM_ITUNES_COUNTRY_CODE, ITUNES_METADATA_TYPE_INTEGER },
378 { ITUNES_METADATA_ITEM_DISC_COMPILATION, ITUNES_METADATA_TYPE_BOOLEAN },
379 { ITUNES_METADATA_ITEM_HIGH_DEFINITION_VIDEO, ITUNES_METADATA_TYPE_BOOLEAN },
380 { ITUNES_METADATA_ITEM_PODCAST, ITUNES_METADATA_TYPE_BOOLEAN },
381 { ITUNES_METADATA_ITEM_GAPLESS_PLAYBACK, ITUNES_METADATA_TYPE_BOOLEAN },
382 { ITUNES_METADATA_ITEM_COVER_ART, ITUNES_METADATA_TYPE_BINARY },
383 { ITUNES_METADATA_ITEM_DISC_NUMBER, ITUNES_METADATA_TYPE_BINARY },
384 { ITUNES_METADATA_ITEM_TRACK_NUMBER, ITUNES_METADATA_TYPE_BINARY },
385 { 0, ITUNES_METADATA_TYPE_NONE }
387 for( int i = 0; itunes_metadata_item_type_mapping[i].type != ITUNES_METADATA_TYPE_NONE; i++ )
388 if( item == itunes_metadata_item_type_mapping[i].item )
389 return itunes_metadata_item_type_mapping[i].type;
390 return ITUNES_METADATA_TYPE_NONE;
393 int lsmash_get_itunes_metadata( lsmash_root_t *root, uint32_t metadata_number, lsmash_itunes_metadata_t *metadata )
395 if( isom_check_initializer_present( root ) < 0 || !metadata )
396 return LSMASH_ERR_FUNCTION_PARAM;
397 lsmash_file_t *file = root->file->initializer;
398 if( !file->moov->udta->meta->ilst )
399 return LSMASH_ERR_NAMELESS;
400 isom_ilst_t *ilst = file->moov->udta->meta->ilst;
401 isom_metaitem_t *metaitem = (isom_metaitem_t *)lsmash_list_get_entry_data( &ilst->metaitem_list, metadata_number );
402 if( LSMASH_IS_NON_EXISTING_BOX( metaitem )
403 || LSMASH_IS_NON_EXISTING_BOX( metaitem->data )
404 || metaitem->data->value == NULL
405 || metaitem->data->value_length == 0 )
406 return LSMASH_ERR_NAMELESS;
407 metadata->item = metaitem->type.fourcc;
408 metadata->type = isom_get_itunes_metadata_type( metadata->item );
409 /* Get 'meaning'. */
410 int err = LSMASH_ERR_MEMORY_ALLOC;
411 isom_mean_t *mean = metaitem->mean;
412 if( LSMASH_IS_NON_EXISTING_BOX( mean ) )
414 uint8_t *temp = lsmash_malloc( mean->meaning_string_length + 1 );
415 if( !temp )
416 goto fail;
417 memcpy( temp, mean->meaning_string, mean->meaning_string_length );
418 temp[ mean->meaning_string_length ] = 0;
419 metadata->meaning = (char *)temp;
421 else
422 metadata->meaning = NULL;
423 /* Get 'name'. */
424 isom_name_t *name = metaitem->name;
425 if( LSMASH_IS_NON_EXISTING_BOX( name ) )
427 uint8_t *temp = lsmash_malloc( name->name_length + 1 );
428 if( !temp )
429 goto fail;
430 memcpy( temp, name->name, name->name_length );
431 temp[ name->name_length ] = 0;
432 metadata->name = (char *)temp;
434 else
435 metadata->name = NULL;
436 /* Get 'value'. */
437 isom_data_t *data = metaitem->data;
438 switch( metadata->type )
440 case ITUNES_METADATA_TYPE_STRING :
442 uint8_t *temp = lsmash_malloc( data->value_length + 1 );
443 if( !temp )
444 goto fail;
445 memcpy( temp, data->value, data->value_length );
446 temp[ data->value_length ] = 0;
447 metadata->value.string = (char *)temp;
448 break;
450 case ITUNES_METADATA_TYPE_INTEGER :
451 if( data->value_length > 8 )
453 err = LSMASH_ERR_INVALID_DATA;
454 goto fail;
456 metadata->value.integer = 0;
457 for( uint32_t i = 0; i < data->value_length; i++ )
459 int shift = (data->value_length - i - 1) * 8;
460 metadata->value.integer |= (uint64_t)data->value[i] << shift;
462 break;
463 case ITUNES_METADATA_TYPE_BOOLEAN :
464 metadata->value.boolean = !!data->value[0];
465 break;
466 default :
467 metadata->type = ITUNES_METADATA_TYPE_BINARY;
468 metadata->value.binary.subtype = data->type_code;
469 metadata->value.binary.size = data->value_length;
470 metadata->value.binary.data = lsmash_memdup( data->value, data->value_length );
471 if( !metadata->value.binary.data )
472 goto fail;
473 break;
475 return 0;
476 fail:
477 lsmash_freep( &metadata->meaning );
478 lsmash_freep( &metadata->name );
479 return err;
482 uint32_t lsmash_count_itunes_metadata( lsmash_root_t *root )
484 if( isom_check_initializer_present( root ) < 0
485 || LSMASH_IS_NON_EXISTING_BOX( root->file->initializer->moov->udta->meta->ilst ) )
486 return 0;
487 return root->file->initializer->moov->udta->meta->ilst->metaitem_list.entry_count;
490 void lsmash_cleanup_itunes_metadata( lsmash_itunes_metadata_t *metadata )
492 if( !metadata )
493 return;
494 lsmash_freep( &metadata->meaning );
495 lsmash_freep( &metadata->name );
496 if( metadata->type == ITUNES_METADATA_TYPE_STRING )
497 lsmash_freep( &metadata->value.string );
498 else if( metadata->type == ITUNES_METADATA_TYPE_BINARY )
499 lsmash_freep( &metadata->value.binary.data );