]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
Provide our own copy of libmp4ff.
[paraslash.git] / mp4.c
1 /*
2  * Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
3  * FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
4  *
5  * See file COPYING.
6  */
7
8 #include "para.h"
9 #include "mp4.h"
10
11 #define USE_TAGGING
12 int32_t mp4ff_total_tracks(const mp4ff_t *f)
13 {
14         return f->total_tracks;
15 }
16
17 int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size)
18 {
19     int32_t result = 1;
20
21     result = f->stream->read(f->stream->user_data, data, size);
22
23     if (result < size)
24         f->stream->read_error++;
25
26     f->current_position += size;
27
28     return result;
29 }
30
31 /* parse atom header size */
32 static int32_t mp4ff_atom_get_size(const int8_t *data)
33 {
34     uint32_t result;
35     uint32_t a, b, c, d;
36
37     a = (uint8_t)data[0];
38     b = (uint8_t)data[1];
39     c = (uint8_t)data[2];
40     d = (uint8_t)data[3];
41
42     result = (a<<24) | (b<<16) | (c<<8) | d;
43     //if (result > 0 && result < 8) result = 8;
44
45     return (int32_t)result;
46 }
47
48 uint64_t mp4ff_read_int64(mp4ff_t *f)
49 {
50     uint8_t data[8];
51     uint64_t result = 0;
52     int8_t i;
53
54     mp4ff_read_data(f, data, 8);
55
56     for (i = 0; i < 8; i++)
57     {
58         result |= ((uint64_t)data[i]) << ((7 - i) * 8);
59     }
60
61     return result;
62 }
63
64 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
65 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1, const int8_t c1, const int8_t d1,
66                                   const int8_t a2, const int8_t b2, const int8_t c2, const int8_t d2)
67 {
68     if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
69         return 1;
70     else
71         return 0;
72 }
73
74 #define TRACK_AUDIO 1
75 #define TRACK_VIDEO   2
76 #define TRACK_SYSTEM  3
77 #define TRACK_UNKNOWN 0
78
79 /* atoms with subatoms */
80 #define ATOM_MOOV 1
81 #define ATOM_TRAK 2
82 #define ATOM_EDTS 3
83 #define ATOM_MDIA 4
84 #define ATOM_MINF 5
85 #define ATOM_STBL 6
86 #define ATOM_UDTA 7
87 #define ATOM_ILST 8 /* iTunes Metadata list */
88 #define ATOM_TITLE 9
89 #define ATOM_ARTIST 10
90 #define ATOM_WRITER 11
91 #define ATOM_ALBUM 12
92 #define ATOM_DATE 13
93 #define ATOM_TOOL 14
94 #define ATOM_COMMENT 15
95 #define ATOM_GENRE1 16
96 #define ATOM_TRACK 17
97 #define ATOM_DISC 18
98 #define ATOM_COMPILATION 19
99 #define ATOM_GENRE2 20
100 #define ATOM_TEMPO 21
101 #define ATOM_COVER 22
102 #define ATOM_DRMS 23
103 #define ATOM_SINF 24
104 #define ATOM_SCHI 25
105
106 #define SUBATOMIC 128
107
108 /* atoms without subatoms */
109 #define ATOM_FTYP 129
110 #define ATOM_MDAT 130
111 #define ATOM_MVHD 131
112 #define ATOM_TKHD 132
113 #define ATOM_TREF 133
114 #define ATOM_MDHD 134
115 #define ATOM_VMHD 135
116 #define ATOM_SMHD 136
117 #define ATOM_HMHD 137
118 #define ATOM_STSD 138
119 #define ATOM_STTS 139
120 #define ATOM_STSZ 140
121 #define ATOM_STZ2 141
122 #define ATOM_STCO 142
123 #define ATOM_STSC 143
124 #define ATOM_MP4A 144
125 #define ATOM_MP4V 145
126 #define ATOM_MP4S 146
127 #define ATOM_ESDS 147
128 #define ATOM_META 148 /* iTunes Metadata box */
129 #define ATOM_NAME 149 /* iTunes Metadata name box */
130 #define ATOM_DATA 150 /* iTunes Metadata data box */
131 #define ATOM_CTTS 151
132 #define ATOM_FRMA 152
133 #define ATOM_IVIV 153
134 #define ATOM_PRIV 154
135 #define ATOM_USER 155
136 #define ATOM_KEY  156
137 #define ATOM_ALBUM_ARTIST       157
138 #define ATOM_CONTENTGROUP   158
139 #define ATOM_LYRICS         159
140 #define ATOM_DESCRIPTION    160
141 #define ATOM_NETWORK        161
142 #define ATOM_SHOW           162
143 #define ATOM_EPISODENAME    163
144 #define ATOM_SORTTITLE      164
145 #define ATOM_SORTALBUM      165
146 #define ATOM_SORTARTIST     166
147 #define ATOM_SORTALBUMARTIST    167
148 #define ATOM_SORTWRITER     168
149 #define ATOM_SORTSHOW       169
150 #define ATOM_SEASON         170
151 #define ATOM_EPISODE        171
152 #define ATOM_PODCAST        172
153
154 #define ATOM_UNKNOWN 255
155 #define ATOM_FREE ATOM_UNKNOWN
156 #define ATOM_SKIP ATOM_UNKNOWN
157
158 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
159
160 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
161                                        const int8_t c, const int8_t d)
162 {
163     if (a == 'm')
164     {
165         if (mp4ff_atom_compare(a,b,c,d, 'm','o','o','v'))
166             return ATOM_MOOV;
167         else if (mp4ff_atom_compare(a,b,c,d, 'm','i','n','f'))
168             return ATOM_MINF;
169         else if (mp4ff_atom_compare(a,b,c,d, 'm','d','i','a'))
170             return ATOM_MDIA;
171         else if (mp4ff_atom_compare(a,b,c,d, 'm','d','a','t'))
172             return ATOM_MDAT;
173         else if (mp4ff_atom_compare(a,b,c,d, 'm','d','h','d'))
174             return ATOM_MDHD;
175         else if (mp4ff_atom_compare(a,b,c,d, 'm','v','h','d'))
176             return ATOM_MVHD;
177         else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','a'))
178             return ATOM_MP4A;
179         else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','v'))
180             return ATOM_MP4V;
181         else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','s'))
182             return ATOM_MP4S;
183         else if (mp4ff_atom_compare(a,b,c,d, 'm','e','t','a'))
184             return ATOM_META;
185     } else if (a == 't') {
186         if (mp4ff_atom_compare(a,b,c,d, 't','r','a','k'))
187             return ATOM_TRAK;
188         else if (mp4ff_atom_compare(a,b,c,d, 't','k','h','d'))
189             return ATOM_TKHD;
190         else if (mp4ff_atom_compare(a,b,c,d, 't','r','e','f'))
191             return ATOM_TREF;
192         else if (mp4ff_atom_compare(a,b,c,d, 't','r','k','n'))
193             return ATOM_TRACK;
194         else if (mp4ff_atom_compare(a,b,c,d, 't','m','p','o'))
195             return ATOM_TEMPO;
196         else if (mp4ff_atom_compare(a,b,c,d, 't','v','n','n'))
197             return ATOM_NETWORK;
198         else if (mp4ff_atom_compare(a,b,c,d, 't','v','s','h'))
199             return ATOM_SHOW;
200         else if (mp4ff_atom_compare(a,b,c,d, 't','v','e','n'))
201             return ATOM_EPISODENAME;
202         else if (mp4ff_atom_compare(a,b,c,d, 't','v','s','n'))
203             return ATOM_SEASON;
204         else if (mp4ff_atom_compare(a,b,c,d, 't','v','e','s'))
205             return ATOM_EPISODE;
206     } else if (a == 's') {
207         if (mp4ff_atom_compare(a,b,c,d, 's','t','b','l'))
208             return ATOM_STBL;
209         else if (mp4ff_atom_compare(a,b,c,d, 's','m','h','d'))
210             return ATOM_SMHD;
211         else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','d'))
212             return ATOM_STSD;
213         else if (mp4ff_atom_compare(a,b,c,d, 's','t','t','s'))
214             return ATOM_STTS;
215         else if (mp4ff_atom_compare(a,b,c,d, 's','t','c','o'))
216             return ATOM_STCO;
217         else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','c'))
218             return ATOM_STSC;
219         else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','z'))
220             return ATOM_STSZ;
221         else if (mp4ff_atom_compare(a,b,c,d, 's','t','z','2'))
222             return ATOM_STZ2;
223         else if (mp4ff_atom_compare(a,b,c,d, 's','k','i','p'))
224             return ATOM_SKIP;
225         else if (mp4ff_atom_compare(a,b,c,d, 's','i','n','f'))
226             return ATOM_SINF;
227         else if (mp4ff_atom_compare(a,b,c,d, 's','c','h','i'))
228             return ATOM_SCHI;
229         else if (mp4ff_atom_compare(a,b,c,d, 's','o','n','m'))
230             return ATOM_SORTTITLE;
231         else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','l'))
232             return ATOM_SORTALBUM;
233         else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','r'))
234             return ATOM_SORTARTIST;
235         else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','a'))
236             return ATOM_SORTALBUMARTIST;
237         else if (mp4ff_atom_compare(a,b,c,d, 's','o','c','o'))
238             return ATOM_SORTWRITER;
239         else if (mp4ff_atom_compare(a,b,c,d, 's','o','s','n'))
240             return ATOM_SORTSHOW;
241     } else if (a == COPYRIGHT_SYMBOL) {
242         if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'n','a','m'))
243             return ATOM_TITLE;
244         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'A','R','T'))
245             return ATOM_ARTIST;
246         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'w','r','t'))
247             return ATOM_WRITER;
248         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'a','l','b'))
249             return ATOM_ALBUM;
250         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'d','a','y'))
251             return ATOM_DATE;
252         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'t','o','o'))
253             return ATOM_TOOL;
254         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'c','m','t'))
255             return ATOM_COMMENT;
256         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','e','n'))
257             return ATOM_GENRE1;
258         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','r','p'))
259             return ATOM_CONTENTGROUP;
260         else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'l','y','r'))
261             return ATOM_LYRICS;
262     }
263
264     if (mp4ff_atom_compare(a,b,c,d, 'e','d','t','s'))
265         return ATOM_EDTS;
266     else if (mp4ff_atom_compare(a,b,c,d, 'e','s','d','s'))
267         return ATOM_ESDS;
268     else if (mp4ff_atom_compare(a,b,c,d, 'f','t','y','p'))
269         return ATOM_FTYP;
270     else if (mp4ff_atom_compare(a,b,c,d, 'f','r','e','e'))
271         return ATOM_FREE;
272     else if (mp4ff_atom_compare(a,b,c,d, 'h','m','h','d'))
273         return ATOM_HMHD;
274     else if (mp4ff_atom_compare(a,b,c,d, 'v','m','h','d'))
275         return ATOM_VMHD;
276     else if (mp4ff_atom_compare(a,b,c,d, 'u','d','t','a'))
277         return ATOM_UDTA;
278     else if (mp4ff_atom_compare(a,b,c,d, 'i','l','s','t'))
279         return ATOM_ILST;
280     else if (mp4ff_atom_compare(a,b,c,d, 'n','a','m','e'))
281         return ATOM_NAME;
282     else if (mp4ff_atom_compare(a,b,c,d, 'd','a','t','a'))
283         return ATOM_DATA;
284     else if (mp4ff_atom_compare(a,b,c,d, 'd','i','s','k'))
285         return ATOM_DISC;
286     else if (mp4ff_atom_compare(a,b,c,d, 'g','n','r','e'))
287         return ATOM_GENRE2;
288     else if (mp4ff_atom_compare(a,b,c,d, 'c','o','v','r'))
289         return ATOM_COVER;
290     else if (mp4ff_atom_compare(a,b,c,d, 'c','p','i','l'))
291         return ATOM_COMPILATION;
292     else if (mp4ff_atom_compare(a,b,c,d, 'c','t','t','s'))
293         return ATOM_CTTS;
294     else if (mp4ff_atom_compare(a,b,c,d, 'd','r','m','s'))
295         return ATOM_DRMS;
296     else if (mp4ff_atom_compare(a,b,c,d, 'f','r','m','a'))
297         return ATOM_FRMA;
298     else if (mp4ff_atom_compare(a,b,c,d, 'p','r','i','v'))
299         return ATOM_PRIV;
300     else if (mp4ff_atom_compare(a,b,c,d, 'i','v','i','v'))
301         return ATOM_IVIV;
302     else if (mp4ff_atom_compare(a,b,c,d, 'u','s','e','r'))
303         return ATOM_USER;
304     else if (mp4ff_atom_compare(a,b,c,d, 'k','e','y',' '))
305         return ATOM_KEY;
306     else if (mp4ff_atom_compare(a,b,c,d, 'a','A','R','T'))
307         return ATOM_ALBUM_ARTIST;
308     else if (mp4ff_atom_compare(a,b,c,d, 'd','e','s','c'))
309         return ATOM_DESCRIPTION;
310     else if (mp4ff_atom_compare(a,b,c,d, 'p','c','s','t'))
311         return ATOM_PODCAST;
312     else
313         return ATOM_UNKNOWN;
314 }
315
316 /* read atom header, return atom size, atom size is with header included */
317 uint64_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type, uint8_t *header_size)
318 {
319     uint64_t size;
320     int32_t ret;
321     int8_t atom_header[8];
322
323     ret = mp4ff_read_data(f, atom_header, 8);
324     if (ret != 8)
325         return 0;
326
327     size = mp4ff_atom_get_size(atom_header);
328     *header_size = 8;
329
330     /* check for 64 bit atom size */
331     if (size == 1)
332     {
333         *header_size = 16;
334         size = mp4ff_read_int64(f);
335     }
336
337     //printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
338
339     *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
340
341     return size;
342 }
343
344 int64_t mp4ff_position(const mp4ff_t *f)
345 {
346     return f->current_position;
347 }
348
349 static int need_parse_when_meta_only(uint8_t atom_type)
350 {
351         switch(atom_type)
352         {
353         case ATOM_EDTS:
354 //      case ATOM_MDIA:
355 //      case ATOM_MINF:
356         case ATOM_DRMS:
357         case ATOM_SINF:
358         case ATOM_SCHI:
359 //      case ATOM_STBL:
360 //      case ATOM_STSD:
361         case ATOM_STTS:
362         case ATOM_STSZ:
363         case ATOM_STZ2:
364         case ATOM_STCO:
365         case ATOM_STSC:
366 //      case ATOM_CTTS:
367         case ATOM_FRMA:
368         case ATOM_IVIV:
369         case ATOM_PRIV:
370                 return 0;
371         default:
372                 return 1;
373         }
374 }
375
376 int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position)
377 {
378     f->stream->seek(f->stream->user_data, position);
379     f->current_position = position;
380
381     return 0;
382 }
383
384 static void mp4ff_track_add(mp4ff_t *f)
385 {
386     f->total_tracks++;
387
388     if (f->total_tracks > MAX_TRACKS)
389     {
390         f->total_tracks = 0;
391         f->error++;
392         return;
393     }
394
395     f->track[f->total_tracks - 1] = malloc(sizeof(mp4ff_track_t));
396
397     memset(f->track[f->total_tracks - 1], 0, sizeof(mp4ff_track_t));
398 }
399
400 uint8_t mp4ff_read_char(mp4ff_t *f)
401 {
402     uint8_t output;
403     mp4ff_read_data(f, &output, 1);
404     return output;
405 }
406
407 uint32_t mp4ff_read_int24(mp4ff_t *f)
408 {
409     uint32_t result;
410     uint32_t a, b, c;
411     int8_t data[4];
412     
413     mp4ff_read_data(f, data, 3);
414     a = (uint8_t)data[0];
415     b = (uint8_t)data[1];
416     c = (uint8_t)data[2];
417
418     result = (a<<16) | (b<<8) | c;
419     return (uint32_t)result;
420 }
421
422 uint32_t mp4ff_read_int32(mp4ff_t *f)
423 {
424     uint32_t result;
425     uint32_t a, b, c, d;
426     int8_t data[4];
427     
428     mp4ff_read_data(f, data, 4);
429     a = (uint8_t)data[0];
430     b = (uint8_t)data[1];
431     c = (uint8_t)data[2];
432     d = (uint8_t)data[3];
433
434     result = (a<<24) | (b<<16) | (c<<8) | d;
435     return (uint32_t)result;
436 }
437
438 static int32_t mp4ff_read_stsz(mp4ff_t *f)
439 {
440     if (f->total_tracks == 0)
441         return f->error++;
442
443     mp4ff_read_char(f); /* version */
444     mp4ff_read_int24(f); /* flags */
445     f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
446     f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
447
448     if (f->track[f->total_tracks - 1]->stsz_sample_size == 0)
449     {
450         int32_t i;
451         f->track[f->total_tracks - 1]->stsz_table =
452             (int32_t*)malloc(f->track[f->total_tracks - 1]->stsz_sample_count*sizeof(int32_t));
453
454         if (!f->track[f->total_tracks - 1]->stsz_table)
455             return f->error++;
456
457         for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count && !f->stream->read_error; i++)
458         {
459             f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
460         }
461     }
462
463     return 0;
464 }
465
466 static int32_t mp4ff_read_stts(mp4ff_t *f)
467 {
468     int32_t i;
469     mp4ff_track_t * p_track;
470
471     /* CVE-2017-9223 */
472     if (f->total_tracks == 0)
473         return f->error++;
474
475     p_track = f->track[f->total_tracks - 1];
476
477     if (p_track->stts_entry_count) return 0;
478
479     mp4ff_read_char(f); /* version */
480     mp4ff_read_int24(f); /* flags */
481     p_track->stts_entry_count = mp4ff_read_int32(f);
482
483     p_track->stts_sample_count = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t));
484     p_track->stts_sample_delta = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t));
485
486     if (p_track->stts_sample_count == 0 || p_track->stts_sample_delta == 0)
487     {
488         if (p_track->stts_sample_count) {free(p_track->stts_sample_count);p_track->stts_sample_count=0;}
489         if (p_track->stts_sample_delta) {free(p_track->stts_sample_delta);p_track->stts_sample_delta=0;}
490         p_track->stts_entry_count = 0;
491         return 0;
492     }
493     else
494     {
495         for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count && !f->stream->read_error; i++) /* CVE-2017-9254 */
496         {
497             p_track->stts_sample_count[i] = mp4ff_read_int32(f);
498             p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
499         }
500         return 1;
501     }
502 }
503
504 static int32_t mp4ff_read_ctts(mp4ff_t *f)
505 {
506     int32_t i;
507     mp4ff_track_t * p_track;
508
509     if (f->total_tracks == 0)
510         return f->error++;
511
512     p_track = f->track[f->total_tracks - 1];
513     if (p_track->ctts_entry_count) return 0;
514
515     mp4ff_read_char(f); /* version */
516     mp4ff_read_int24(f); /* flags */
517     p_track->ctts_entry_count = mp4ff_read_int32(f);
518
519     p_track->ctts_sample_count = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t));
520     p_track->ctts_sample_offset = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t));
521
522     if (p_track->ctts_sample_count == 0 || p_track->ctts_sample_offset == 0)
523     {
524         if (p_track->ctts_sample_count) {free(p_track->ctts_sample_count);p_track->ctts_sample_count=0;}
525         if (p_track->ctts_sample_offset) {free(p_track->ctts_sample_offset);p_track->ctts_sample_offset=0;}
526         p_track->ctts_entry_count = 0;
527         return 0;
528     }
529     else
530     {
531         for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count && !f->stream->read_error; i++) /* CVE-2017-9257 */
532         {
533             p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
534             p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
535         }
536         return 1;
537     }
538 }
539
540 static int32_t mp4ff_read_stsc(mp4ff_t *f)
541 {
542     int32_t i;
543
544     if (f->total_tracks == 0)
545         return f->error++;
546
547     mp4ff_read_char(f); /* version */
548     mp4ff_read_int24(f); /* flags */
549     f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
550
551     f->track[f->total_tracks - 1]->stsc_first_chunk =
552         (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
553     f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
554         (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
555     f->track[f->total_tracks - 1]->stsc_sample_desc_index =
556         (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
557
558     /* CVE-2017-9219 */
559     if (!f->track[f->total_tracks - 1]->stsc_first_chunk)
560     {
561         return f->error++;
562     }
563     if (!f->track[f->total_tracks - 1]->stsc_samples_per_chunk)
564     {
565         free(f->track[f->total_tracks - 1]->stsc_first_chunk);
566         f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
567         return f->error++;
568     }
569     if (!f->track[f->total_tracks - 1]->stsc_sample_desc_index)
570     {
571         free(f->track[f->total_tracks - 1]->stsc_first_chunk);
572         f->track[f->total_tracks - 1]->stsc_first_chunk = NULL;
573         free(f->track[f->total_tracks - 1]->stsc_samples_per_chunk);
574         f->track[f->total_tracks - 1]->stsc_samples_per_chunk = NULL;
575         return f->error++;
576     }
577
578     for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count && !f->stream->read_error; i++) /* CVE-2017-9255 */
579     {
580         f->track[f->total_tracks - 1]->stsc_first_chunk[i] = mp4ff_read_int32(f);
581         f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] = mp4ff_read_int32(f);
582         f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] = mp4ff_read_int32(f);
583     }
584
585     return 0;
586 }
587
588 static int32_t mp4ff_read_stco(mp4ff_t *f)
589 {
590     int32_t i;
591
592     if (f->total_tracks == 0)
593         return f->error++;
594
595     mp4ff_read_char(f); /* version */
596     mp4ff_read_int24(f); /* flags */
597     f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
598
599     f->track[f->total_tracks - 1]->stco_chunk_offset =
600         (int32_t*)malloc(f->track[f->total_tracks - 1]->stco_entry_count*sizeof(int32_t));
601
602     /* CVE-2017-9220 */
603     if (!f->track[f->total_tracks - 1]->stco_chunk_offset)
604         return f->error++;
605
606     for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count && !f->stream->read_error; i++) /* CVE-2017-9256 */
607     {
608         f->track[f->total_tracks - 1]->stco_chunk_offset[i] = mp4ff_read_int32(f);
609     }
610
611     return 0;
612 }
613
614 uint16_t mp4ff_read_int16(mp4ff_t *f)
615 {
616     uint32_t result;
617     uint32_t a, b;
618     int8_t data[2];
619     
620     mp4ff_read_data(f, data, 2);
621     a = (uint8_t)data[0];
622     b = (uint8_t)data[1];
623
624     result = (a<<8) | b;
625     return (uint16_t)result;
626 }
627
628
629 uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f)
630 {
631     uint8_t b;
632     uint8_t numBytes = 0;
633     uint32_t length = 0;
634
635     do
636     {
637         b = mp4ff_read_char(f);
638         numBytes++;
639         length = (length << 7) | (b & 0x7F);
640     } while ((b & 0x80) && numBytes < 4);
641
642     return length;
643 }
644 static int32_t mp4ff_read_esds(mp4ff_t *f)
645 {
646     uint8_t tag;
647     uint32_t temp;
648
649     if (f->total_tracks == 0)
650         return f->error++;
651
652     mp4ff_read_char(f); /* version */
653     mp4ff_read_int24(f); /* flags */
654
655     /* get and verify ES_DescrTag */
656     tag = mp4ff_read_char(f);
657     if (tag == 0x03)
658     {
659         /* read length */
660         if (mp4ff_read_mp4_descr_length(f) < 5 + 15)
661         {
662             return 1;
663         }
664         /* skip 3 bytes */
665         mp4ff_read_int24(f);
666     } else {
667         /* skip 2 bytes */
668         mp4ff_read_int16(f);
669     }
670
671     /* get and verify DecoderConfigDescrTab */
672     if (mp4ff_read_char(f) != 0x04)
673     {
674         return 1;
675     }
676
677     /* read length */
678     temp = mp4ff_read_mp4_descr_length(f);
679     if (temp < 13) return 1;
680
681     f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
682     mp4ff_read_int32(f);//0x15000414 ????
683     f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
684     f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
685
686     /* get and verify DecSpecificInfoTag */
687     if (mp4ff_read_char(f) != 0x05)
688     {
689         return 1;
690     }
691
692     /* read length */
693     f->track[f->total_tracks - 1]->decoderConfigLen = mp4ff_read_mp4_descr_length(f);
694
695     if (f->track[f->total_tracks - 1]->decoderConfig)
696         free(f->track[f->total_tracks - 1]->decoderConfig);
697     f->track[f->total_tracks - 1]->decoderConfig = malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
698     if (f->track[f->total_tracks - 1]->decoderConfig)
699     {
700         mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig, f->track[f->total_tracks - 1]->decoderConfigLen);
701     } else {
702         f->track[f->total_tracks - 1]->decoderConfigLen = 0;
703     }
704
705     /* will skip the remainder of the atom */
706     return 0;
707 }
708 static int32_t mp4ff_read_mp4a(mp4ff_t *f)
709 {
710     uint64_t size;
711     int32_t i;
712     uint8_t atom_type = 0;
713     uint8_t header_size = 0;
714
715     if (f->total_tracks == 0)
716         return f->error++;
717
718     for (i = 0; i < 6; i++)
719     {
720         mp4ff_read_char(f); /* reserved */
721     }
722     /* data_reference_index */ mp4ff_read_int16(f);
723
724     mp4ff_read_int32(f); /* reserved */
725     mp4ff_read_int32(f); /* reserved */
726
727     f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
728     f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
729
730     mp4ff_read_int16(f);
731     mp4ff_read_int16(f);
732
733     f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
734
735     mp4ff_read_int16(f);
736
737     size = mp4ff_atom_read_header(f, &atom_type, &header_size);
738     if (atom_type == ATOM_ESDS)
739     {
740         mp4ff_read_esds(f);
741     }
742
743     return 0;
744 }
745
746 static int32_t mp4ff_read_stsd(mp4ff_t *f)
747 {
748     int32_t i;
749     uint8_t header_size = 0;
750
751     /* CVE-2017-9218 */
752     if (f->total_tracks == 0)
753         return f->error++;
754
755     mp4ff_read_char(f); /* version */
756     mp4ff_read_int24(f); /* flags */
757
758     f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
759
760     for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) /* CVE-2017-9253 */
761     {
762         uint64_t skip = mp4ff_position(f);
763         uint64_t size;
764         uint8_t atom_type = 0;
765         size = mp4ff_atom_read_header(f, &atom_type, &header_size);
766         skip += size;
767
768         if (atom_type == ATOM_MP4A)
769         {
770             f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
771             mp4ff_read_mp4a(f);
772         } else if (atom_type == ATOM_MP4V) {
773             f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
774         } else if (atom_type == ATOM_MP4S) {
775             f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
776         } else {
777             f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
778         }
779
780         mp4ff_set_position(f, skip);
781     }
782
783     return 0;
784 }
785
786 static int32_t mp4ff_read_mvhd(mp4ff_t *f)
787 {
788     int32_t i;
789
790     mp4ff_read_char(f); /* version */
791     mp4ff_read_int24(f); /* flags */
792     /* creation_time */ mp4ff_read_int32(f);
793     /* modification_time */ mp4ff_read_int32(f);
794     f->time_scale = mp4ff_read_int32(f);
795     f->duration = mp4ff_read_int32(f);
796     /* preferred_rate */ mp4ff_read_int32(f); /*mp4ff_read_fixed32(f);*/
797     /* preferred_volume */ mp4ff_read_int16(f); /*mp4ff_read_fixed16(f);*/
798     for (i = 0; i < 10; i++)
799     {
800         /* reserved */ mp4ff_read_char(f);
801     }
802     for (i = 0; i < 9; i++)
803     {
804         mp4ff_read_int32(f); /* matrix */
805     }
806     /* preview_time */ mp4ff_read_int32(f);
807     /* preview_duration */ mp4ff_read_int32(f);
808     /* poster_time */ mp4ff_read_int32(f);
809     /* selection_time */ mp4ff_read_int32(f);
810     /* selection_duration */ mp4ff_read_int32(f);
811     /* current_time */ mp4ff_read_int32(f);
812     /* next_track_id */ mp4ff_read_int32(f);
813
814     return 0;
815 }
816
817 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t *tags, const char *item, const char *value, int32_t len)
818 {
819     void *backup = (void *)tags->tags;
820
821     if (!item || (item && !*item) || !value) return 0;
822
823     tags->tags = (mp4ff_tag_t*)realloc(tags->tags, (tags->count+1) * sizeof(mp4ff_tag_t));
824     if (!tags->tags)
825     {
826         if (backup) free(backup);
827         return 0;
828     } else {
829         tags->tags[tags->count].item = strdup(item);
830         tags->tags[tags->count].len = len;
831         if (len >= 0) {
832             tags->tags[tags->count].value = malloc(len + 1);
833             if (tags->tags[tags->count].value != NULL) {
834                 memcpy(tags->tags[tags->count].value, value, len);
835                 tags->tags[tags->count].value[len] = 0;
836             }
837         }
838         else {
839             tags->tags[tags->count].value = strdup(value);
840         }
841
842         if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
843         {
844             if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
845             if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
846             tags->tags[tags->count].item = NULL;
847             tags->tags[tags->count].value = NULL;
848             tags->tags[tags->count].len = 0;
849             return 0;
850         }
851
852         tags->count++;
853         return 1;
854     }
855 }
856
857 static const char* ID3v1GenreList[] = {
858     "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
859     "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
860     "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
861     "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
862     "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk",
863     "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House",
864     "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
865     "Soul", "Punk", "Space", "Meditative", "Instrumental Pop", "Instrumental Rock",
866     "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
867     "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
868     "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
869     "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
870     "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
871     "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk", "Swing",
872     "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
873     "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
874     "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
875     "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
876     "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
877     "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet",
878     "Punk Rock", "Drum Solo", "A capella", "Euro-House", "Dance Hall",
879     "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
880     "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
881     "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover", "Contemporary C",
882     "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop",
883     "SynthPop",
884 };
885
886 const char * mp4ff_meta_index_to_genre(uint32_t idx)
887 {
888         if (idx>0 && idx<=sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]))
889         {
890                 return ID3v1GenreList[idx-1];
891         }
892         else
893         {
894                 return 0;
895         }
896 }
897
898 char * mp4ff_read_string(mp4ff_t * f,uint32_t length)
899 {
900         char * str = (char*)malloc(length + 1);
901         if (str!=0)
902         {
903                 if ((uint32_t)mp4ff_read_data(f,str,length)!=length)
904                 {
905                         free(str);
906                         str = 0;
907                 }
908                 else
909                 {
910                         str[length] = 0;
911                 }
912         }
913         return str;     
914 }
915
916 static int32_t mp4ff_set_metadata_name(mp4ff_t *f, const uint8_t atom_type, char **name)
917 {
918     static char *tag_names[] = {
919         "unknown", "title", "artist", "writer", "album",
920         "date", "tool", "comment", "genre", "track",
921         "disc", "compilation", "genre", "tempo", "cover",
922                 "album_artist", "contentgroup", "lyrics", "description",
923         "network", "show", "episodename",
924         "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
925         "sortwriter", "sortshow",
926         "season", "episode", "podcast"
927
928     };
929     uint8_t tag_idx = 0;
930
931     switch (atom_type)
932     {
933     case ATOM_TITLE: tag_idx = 1; break;
934     case ATOM_ARTIST: tag_idx = 2; break;
935     case ATOM_WRITER: tag_idx = 3; break;
936     case ATOM_ALBUM: tag_idx = 4; break;
937     case ATOM_DATE: tag_idx = 5; break;
938     case ATOM_TOOL: tag_idx = 6; break;
939     case ATOM_COMMENT: tag_idx = 7; break;
940     case ATOM_GENRE1: tag_idx = 8; break;
941     case ATOM_TRACK: tag_idx = 9; break;
942     case ATOM_DISC: tag_idx = 10; break;
943     case ATOM_COMPILATION: tag_idx = 11; break;
944     case ATOM_GENRE2: tag_idx = 12; break;
945     case ATOM_TEMPO: tag_idx = 13; break;
946     case ATOM_COVER: tag_idx = 14; break;
947         case ATOM_ALBUM_ARTIST: tag_idx = 15; break;
948     case ATOM_CONTENTGROUP: tag_idx = 16; break;
949     case ATOM_LYRICS: tag_idx = 17; break;
950     case ATOM_DESCRIPTION: tag_idx = 18; break;
951     case ATOM_NETWORK: tag_idx = 19; break;
952     case ATOM_SHOW: tag_idx = 20; break;
953     case ATOM_EPISODENAME: tag_idx = 21; break;
954     case ATOM_SORTTITLE: tag_idx = 22; break;
955     case ATOM_SORTALBUM: tag_idx = 23; break;
956     case ATOM_SORTARTIST: tag_idx = 24; break;
957     case ATOM_SORTALBUMARTIST: tag_idx = 25; break;
958     case ATOM_SORTWRITER: tag_idx = 26; break;
959     case ATOM_SORTSHOW: tag_idx = 27; break;
960     case ATOM_SEASON: tag_idx = 28; break;
961     case ATOM_EPISODE: tag_idx = 29; break;
962     case ATOM_PODCAST: tag_idx = 30; break;
963     default: tag_idx = 0; break;
964     }
965
966         *name = strdup(tag_names[tag_idx]);
967
968     return 0;
969 }
970 static int32_t mp4ff_parse_tag(mp4ff_t *f, const uint8_t parent_atom_type, const int32_t size)
971 {
972     uint8_t atom_type;
973     uint8_t header_size = 0;
974     uint64_t subsize, sumsize = 0;
975     char * name = NULL;
976         char * data = NULL;
977         uint32_t done = 0;
978     uint32_t len = 0;
979
980
981     while (sumsize < size && !f->stream->read_error) /* CVE-2017-9222 */
982     {
983                 uint64_t destpos;
984         subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
985                 destpos = mp4ff_position(f)+subsize-header_size;
986                 if (!done)
987                 {
988                         if (atom_type == ATOM_DATA)
989                         {
990                                 mp4ff_read_char(f); /* version */
991                                 mp4ff_read_int24(f); /* flags */
992                                 mp4ff_read_int32(f); /* reserved */
993
994                                 /* some need special attention */
995                                 if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO)
996                                 {
997                                         if (subsize - header_size >= 8 + 2)
998                                         {
999                                                 uint16_t val = mp4ff_read_int16(f);
1000
1001                                                 if (parent_atom_type == ATOM_TEMPO)
1002                                                 {
1003                                                         char temp[16];
1004                                                         sprintf(temp, "%.5u BPM", val);
1005                                                         mp4ff_tag_add_field(&(f->tags), "tempo", temp, -1);
1006                                                 }
1007                                                 else
1008                                                 {
1009                                                         const char * temp = mp4ff_meta_index_to_genre(val);
1010                                                         if (temp)
1011                                                         {
1012                                                                 mp4ff_tag_add_field(&(f->tags), "genre", temp, -1);
1013                                                         }
1014                                                 }
1015                                                 done = 1;
1016                                         }
1017                                 } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1018                                         /* if (!done && subsize - header_size >= 8 + 8) */
1019                                         /* modified by AJS */
1020                                         if ( !done && (subsize - header_size) >=
1021                                                 (sizeof(char) + sizeof(uint8_t)*3 + sizeof(uint32_t) + /* version + flags + reserved */
1022                                                 + (parent_atom_type == ATOM_TRACK ? sizeof(uint16_t) : 0) /* leading uint16_t if ATOM_TRACK */
1023                                                 + sizeof(uint16_t) /* track / disc */
1024                                                 + sizeof(uint16_t)) /* totaltracks / totaldiscs */
1025                                                 )
1026                                         {
1027                                                 uint16_t index,total;
1028                                                 char temp[32];
1029                                                 mp4ff_read_int16(f);
1030                                                 index = mp4ff_read_int16(f);
1031                                                 total = mp4ff_read_int16(f);
1032                         if (parent_atom_type == ATOM_TRACK)
1033                             mp4ff_read_int16(f);
1034
1035                                                 sprintf(temp,"%d",index);
1036                                                 mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "track" : "disc", temp, -1);
1037                                                 if (total>0)
1038                                                 {
1039                                                         sprintf(temp,"%d",total);
1040                                                         mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ? "totaltracks" : "totaldiscs", temp, -1);
1041                                                 }
1042                                                 done = 1;
1043                                         }
1044                                 } else
1045                                 {
1046                                         if (data) {free(data);data = NULL;}
1047                                         data = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+8)));
1048                     len = (uint32_t)(subsize-(header_size+8));
1049                                 }
1050                         } else if (atom_type == ATOM_NAME) {
1051                                 if (!done)
1052                                 {
1053                                         mp4ff_read_char(f); /* version */
1054                                         mp4ff_read_int24(f); /* flags */
1055                                         if (name) free(name);
1056                                         name = mp4ff_read_string(f,(uint32_t)(subsize-(header_size+4)));
1057                                 }
1058                         }
1059                         mp4ff_set_position(f, destpos);
1060                         sumsize += subsize;
1061                 }
1062     }
1063
1064         if (data)
1065         {
1066                 if (!done)
1067                 {
1068                         if (name == NULL) mp4ff_set_metadata_name(f, parent_atom_type, &name);
1069                         if (name) mp4ff_tag_add_field(&(f->tags), name, data, len);
1070                 }
1071
1072                 free(data);
1073         }
1074         if (name) free(name);
1075     return 1;
1076 }
1077 static int32_t mp4ff_read_mdhd(mp4ff_t *f)
1078 {
1079     uint32_t version;
1080
1081     /* CVE-2017-9221 */
1082     if (f->total_tracks == 0)
1083         return f->error++;
1084
1085     version = mp4ff_read_int32(f);
1086     if (version==1)
1087     {
1088         mp4ff_read_int64(f);//creation-time
1089         mp4ff_read_int64(f);//modification-time
1090         f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
1091         f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
1092     }
1093     else //version == 0
1094     {
1095         uint32_t temp;
1096
1097         mp4ff_read_int32(f);//creation-time
1098         mp4ff_read_int32(f);//modification-time
1099         f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
1100         temp = mp4ff_read_int32(f);
1101         f->track[f->total_tracks - 1]->duration = (temp == (uint32_t)(-1)) ? (uint64_t)(-1) : (uint64_t)(temp);
1102     }
1103     mp4ff_read_int16(f);
1104     mp4ff_read_int16(f);
1105     return 1;
1106 }
1107
1108 int32_t mp4ff_parse_metadata(mp4ff_t *f, const int32_t size)
1109 {
1110     uint64_t subsize, sumsize = 0;
1111     uint8_t atom_type;
1112     uint8_t header_size = 0;
1113
1114     while (sumsize < size)
1115     {
1116         subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1117         if (subsize == 0)
1118             break;
1119         mp4ff_parse_tag(f, atom_type, (uint32_t)(subsize-header_size));
1120         sumsize += subsize;
1121     }
1122
1123     return 0;
1124 }
1125
1126 static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size)
1127 {
1128     uint64_t subsize, sumsize = 0;
1129     uint8_t atom_type;
1130     uint8_t header_size = 0;
1131
1132     mp4ff_read_char(f); /* version */
1133     mp4ff_read_int24(f); /* flags */
1134
1135     while (sumsize < (size-(header_size+4)))
1136     {
1137         subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1138         if (subsize <= header_size+4)
1139             return 1;
1140         if (atom_type == ATOM_ILST)
1141         {
1142             mp4ff_parse_metadata(f, (uint32_t)(subsize-(header_size+4)));
1143         } else {
1144             mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
1145         }
1146         sumsize += subsize;
1147     }
1148
1149     return 0;
1150 }
1151
1152 int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type)
1153 {
1154     uint64_t dest_position = mp4ff_position(f)+size-8;
1155     if (atom_type == ATOM_STSZ)
1156     {
1157         /* sample size box */
1158         mp4ff_read_stsz(f);
1159     } else if (atom_type == ATOM_STTS) {
1160         /* time to sample box */
1161         mp4ff_read_stts(f);
1162     } else if (atom_type == ATOM_CTTS) {
1163         /* composition offset box */
1164         mp4ff_read_ctts(f);
1165     } else if (atom_type == ATOM_STSC) {
1166         /* sample to chunk box */
1167         mp4ff_read_stsc(f);
1168     } else if (atom_type == ATOM_STCO) {
1169         /* chunk offset box */
1170         mp4ff_read_stco(f);
1171     } else if (atom_type == ATOM_STSD) {
1172         /* sample description box */
1173         mp4ff_read_stsd(f);
1174     } else if (atom_type == ATOM_MVHD) {
1175         /* movie header box */
1176         mp4ff_read_mvhd(f);
1177     } else if (atom_type == ATOM_MDHD) {
1178         /* track header */
1179         mp4ff_read_mdhd(f);
1180 #ifdef USE_TAGGING
1181     } else if (atom_type == ATOM_META) {
1182         /* iTunes Metadata box */
1183         mp4ff_read_meta(f, size);
1184 #endif
1185     }
1186
1187     mp4ff_set_position(f, dest_position);
1188     return 0;
1189 }
1190
1191 /* parse atoms that are sub atoms of other atoms */
1192 int32_t parse_sub_atoms(mp4ff_t *f, const uint64_t total_size,int meta_only)
1193 {
1194     uint64_t size;
1195     uint8_t atom_type = 0;
1196     uint64_t counted_size = 0;
1197     uint8_t header_size = 0;
1198
1199     while (counted_size < total_size)
1200     {
1201         size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1202         counted_size += size;
1203
1204         /* check for end of file */
1205         if (size == 0)
1206             break;
1207
1208         /* we're starting to read a new track, update index,
1209          * so that all data and tables get written in the right place
1210          */
1211         if (atom_type == ATOM_TRAK)
1212         {
1213             mp4ff_track_add(f);
1214         }
1215
1216         /* parse subatoms */
1217                 if (meta_only && !need_parse_when_meta_only(atom_type))
1218                 {
1219                         mp4ff_set_position(f, mp4ff_position(f)+size-header_size);
1220                 } else if (atom_type < SUBATOMIC)
1221         {
1222             parse_sub_atoms(f, size-header_size,meta_only);
1223         } else {
1224             mp4ff_atom_read(f, (uint32_t)size, atom_type);
1225         }
1226     }
1227
1228     return 0;
1229 }
1230
1231 /* parse root atoms */
1232 int32_t parse_atoms(mp4ff_t *f,int meta_only)
1233 {
1234     uint64_t size;
1235     uint8_t atom_type = 0;
1236     uint8_t header_size = 0;
1237
1238     f->file_size = 0;
1239     f->stream->read_error = 0;
1240
1241     while ((size = mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0)
1242     {
1243         f->file_size += size;
1244         f->last_atom = atom_type;
1245
1246         if (atom_type == ATOM_MDAT && f->moov_read)
1247         {
1248             /* moov atom is before mdat, we can stop reading when mdat is encountered */
1249             /* file position will stay at beginning of mdat data */
1250 //            break;
1251         }
1252
1253         if (atom_type == ATOM_MOOV && size > header_size)
1254         {
1255             f->moov_read = 1;
1256             f->moov_offset = mp4ff_position(f)-header_size;
1257             f->moov_size = size;
1258         }
1259
1260         /* parse subatoms */
1261                 if (meta_only && !need_parse_when_meta_only(atom_type))
1262                 {
1263                         mp4ff_set_position(f, mp4ff_position(f)+size-header_size);
1264                 } else if (atom_type < SUBATOMIC)
1265         {
1266             parse_sub_atoms(f, size-header_size,meta_only);
1267         } else {
1268             /* skip this atom */
1269             mp4ff_set_position(f, mp4ff_position(f)+size-header_size);
1270         }
1271     }
1272
1273     return 0;
1274 }
1275
1276 int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
1277                 unsigned char** ppBuf, unsigned int* pBufSize)
1278 {
1279     if (track >= f->total_tracks)
1280     {
1281         *ppBuf = NULL;
1282         *pBufSize = 0;
1283         return 1;
1284     }
1285
1286     if (f->track[track]->decoderConfig == NULL || f->track[track]->decoderConfigLen == 0)
1287     {
1288         *ppBuf = NULL;
1289         *pBufSize = 0;
1290     } else {
1291         *ppBuf = malloc(f->track[track]->decoderConfigLen);
1292         if (*ppBuf == NULL)
1293         {
1294             *pBufSize = 0;
1295             return 1;
1296         }
1297         memcpy(*ppBuf, f->track[track]->decoderConfig, f->track[track]->decoderConfigLen);
1298         *pBufSize = f->track[track]->decoderConfigLen;
1299     }
1300 }
1301
1302 mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f)
1303 {
1304     mp4ff_t *ff = malloc(sizeof(mp4ff_t));
1305
1306     memset(ff, 0, sizeof(mp4ff_t));
1307
1308     ff->stream = f;
1309
1310     parse_atoms(ff,0);
1311
1312     if (ff->error)
1313     {
1314         free(ff);
1315         ff = NULL;
1316     }
1317
1318     return ff;
1319 }
1320
1321 int32_t mp4ff_tag_delete(mp4ff_metadata_t *tags)
1322 {
1323     uint32_t i;
1324
1325     for (i = 0; i < tags->count; i++)
1326     {
1327         if (tags->tags[i].item) free(tags->tags[i].item);
1328         if (tags->tags[i].value) free(tags->tags[i].value);
1329     }
1330
1331     if (tags->tags) free(tags->tags);
1332
1333     tags->tags = NULL;
1334     tags->count = 0;
1335
1336     return 0;
1337 }
1338 void mp4ff_close(mp4ff_t *ff)
1339 {
1340     int32_t i;
1341
1342     for (i = 0; i < ff->total_tracks; i++)
1343     {
1344         if (ff->track[i])
1345         {
1346             if (ff->track[i]->stsz_table)
1347                 free(ff->track[i]->stsz_table);
1348             if (ff->track[i]->stts_sample_count)
1349                 free(ff->track[i]->stts_sample_count);
1350             if (ff->track[i]->stts_sample_delta)
1351                 free(ff->track[i]->stts_sample_delta);
1352             if (ff->track[i]->stsc_first_chunk)
1353                 free(ff->track[i]->stsc_first_chunk);
1354             if (ff->track[i]->stsc_samples_per_chunk)
1355                 free(ff->track[i]->stsc_samples_per_chunk);
1356             if (ff->track[i]->stsc_sample_desc_index)
1357                 free(ff->track[i]->stsc_sample_desc_index);
1358             if (ff->track[i]->stco_chunk_offset)
1359                 free(ff->track[i]->stco_chunk_offset);
1360             if (ff->track[i]->decoderConfig)
1361                 free(ff->track[i]->decoderConfig);
1362                         if (ff->track[i]->ctts_sample_count)
1363                                 free(ff->track[i]->ctts_sample_count);
1364                         if (ff->track[i]->ctts_sample_offset)
1365                                 free(ff->track[i]->ctts_sample_offset);
1366 #ifdef ITUNES_DRM
1367             if (ff->track[i]->p_drms)
1368                 drms_free(ff->track[i]->p_drms);
1369 #endif
1370             free(ff->track[i]);
1371         }
1372     }
1373
1374 #ifdef USE_TAGGING
1375     mp4ff_tag_delete(&(ff->tags));
1376 #endif
1377
1378     if (ff) free(ff);
1379 }
1380
1381 static int32_t mp4ff_chunk_of_sample(const mp4ff_t *f, const int32_t track, const int32_t sample,
1382                                      int32_t *chunk_sample, int32_t *chunk)
1383 {
1384     int32_t total_entries = 0;
1385     int32_t chunk2entry;
1386     int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1387
1388     if (f->track[track] == NULL)
1389     {
1390         return -1;
1391     }
1392
1393     total_entries = f->track[track]->stsc_entry_count;
1394
1395     chunk1 = 1;
1396     chunk1samples = 0;
1397     chunk2entry = 0;
1398
1399     do
1400     {
1401         chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1402         *chunk = chunk2 - chunk1;
1403         range_samples = *chunk * chunk1samples;
1404
1405         if (sample < total + range_samples) break;
1406
1407         chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1408         chunk1 = chunk2;
1409
1410         if(chunk2entry < total_entries)
1411         {
1412             chunk2entry++;
1413             total += range_samples;
1414         }
1415     } while (chunk2entry < total_entries);
1416
1417     if (chunk1samples)
1418         *chunk = (sample - total) / chunk1samples + chunk1;
1419     else
1420         *chunk = 1;
1421
1422     *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1423
1424     return 0;
1425 }
1426
1427
1428 static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk)
1429 {
1430     const mp4ff_track_t * p_track = f->track[track];
1431
1432     if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count))
1433     {
1434         return p_track->stco_chunk_offset[p_track->stco_entry_count - 1];
1435     } else if (p_track->stco_entry_count) {
1436         return p_track->stco_chunk_offset[chunk - 1];
1437     } else {
1438         return 8;
1439     }
1440
1441     return 0;
1442 }
1443
1444 static int32_t mp4ff_sample_range_size(const mp4ff_t *f, const int32_t track,
1445                                        const int32_t chunk_sample, const int32_t sample)
1446 {
1447     int32_t i, total;
1448     const mp4ff_track_t * p_track = f->track[track];
1449
1450     if (p_track->stsz_sample_size)
1451     {
1452         return (sample - chunk_sample) * p_track->stsz_sample_size;
1453     }
1454     else
1455     {
1456         if (sample>=p_track->stsz_sample_count) return 0;//error
1457
1458         for(i = chunk_sample, total = 0; i < sample; i++)
1459         {
1460             total += p_track->stsz_table[i];
1461         }
1462     }
1463
1464     return total;
1465 }
1466 static int32_t mp4ff_sample_to_offset(const mp4ff_t *f, const int32_t track, const int32_t sample)
1467 {
1468     int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1469
1470     mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1471
1472     chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1473     chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f, track, chunk_sample, sample);
1474
1475     return chunk_offset2;
1476 }
1477
1478 int32_t mp4ff_set_sample_position(mp4ff_t *f, const int32_t track, const int32_t sample)
1479 {
1480     int32_t offset;
1481
1482     offset = mp4ff_sample_to_offset(f, track, sample);
1483     mp4ff_set_position(f, offset);
1484
1485     return 0;
1486 }
1487
1488 int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample)
1489 {
1490     int32_t bytes;
1491     const mp4ff_track_t * p_track = f->track[track];
1492
1493     if (p_track->stsz_sample_size)
1494     {
1495         bytes = p_track->stsz_sample_size;
1496     } else {
1497         bytes = p_track->stsz_table[sample];
1498     }
1499
1500     return bytes;
1501 }
1502
1503 int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample)
1504 {
1505         int32_t temp = mp4ff_audio_frame_size(f, track, sample);
1506         if (temp<0) temp = 0;
1507         return temp;
1508 }
1509
1510 uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track)
1511 {
1512         return f->track[track]->sampleRate;
1513 }
1514
1515 uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track)
1516 {
1517         return f->track[track]->channelCount;
1518 }
1519
1520 int32_t mp4ff_num_samples(const mp4ff_t *f, const int32_t track)
1521 {
1522     int32_t i;
1523     int32_t total = 0;
1524
1525     for (i = 0; i < f->track[track]->stts_entry_count; i++)
1526     {
1527         total += f->track[track]->stts_sample_count[i];
1528     }
1529     return total;
1530 }
1531
1532 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t *f)
1533 {
1534     mp4ff_t *ff = malloc(sizeof(mp4ff_t));
1535
1536     memset(ff, 0, sizeof(mp4ff_t));
1537
1538     ff->stream = f;
1539
1540     parse_atoms(ff,1);
1541
1542     if (ff->error)
1543     {
1544         free(ff);
1545         ff = NULL;
1546     }
1547
1548     return ff;
1549 }
1550
1551 int32_t mp4ff_meta_get_num_items(const mp4ff_t *f)
1552 {
1553     return f->tags.count;
1554 }
1555
1556 int32_t mp4ff_meta_get_by_index(const mp4ff_t *f, uint32_t index,
1557                                 char **item, char **value)
1558 {
1559     if (index >= f->tags.count)
1560     {
1561         *item = NULL;
1562         *value = NULL;
1563         return 0;
1564     } else {
1565                 *item = strdup(f->tags.tags[index].item);
1566                 *value = strdup(f->tags.tags[index].value);
1567                 return 1;
1568     }
1569 }
1570
1571 static uint32_t find_atom(mp4ff_t * f,uint64_t base,uint32_t size,const char * name)
1572 {
1573         uint32_t remaining = size;
1574         uint64_t atom_offset = base;
1575         for(;;)
1576         {
1577                 char atom_name[4];
1578                 uint32_t atom_size;
1579
1580                 mp4ff_set_position(f,atom_offset);
1581                 
1582                 if (remaining < 8) break;
1583                 atom_size = mp4ff_read_int32(f);
1584                 if (atom_size > remaining || atom_size < 8) break;
1585                 mp4ff_read_data(f,atom_name,4);
1586                 
1587                 if (!memcmp(atom_name,name,4))
1588                 {
1589                         mp4ff_set_position(f,atom_offset);
1590                         return 1;
1591                 }
1592                 
1593                 remaining -= atom_size;
1594                 atom_offset += atom_size;
1595         }
1596         return 0;
1597 }
1598 static uint32_t find_atom_v2(mp4ff_t * f,uint64_t base,uint32_t size,const char * name,uint32_t extraheaders,const char * name_inside)
1599 {
1600         uint64_t first_base = (uint64_t)(-1);
1601         while(find_atom(f,base,size,name))//try to find atom <name> with atom <name_inside> in it
1602         {
1603                 uint64_t mybase = mp4ff_position(f);
1604                 uint32_t mysize = mp4ff_read_int32(f);
1605
1606                 if (first_base == (uint64_t)(-1)) first_base = mybase;
1607
1608                 if (mysize < 8 + extraheaders) break;
1609
1610                 if (find_atom(f,mybase+(8+extraheaders),mysize-(8+extraheaders),name_inside))
1611                 {
1612                         mp4ff_set_position(f,mybase);
1613                         return 2;
1614                 }
1615                 base += mysize;
1616                 if (size<=mysize) {size=0;break;}
1617                 size -= mysize;
1618         }
1619
1620         if (first_base != (uint64_t)(-1))//wanted atom inside not found
1621         {
1622                 mp4ff_set_position(f,first_base);
1623                 return 1;
1624         }
1625         else return 0;  
1626 }
1627
1628 typedef struct
1629 {
1630         void * data;
1631         unsigned written;
1632         unsigned allocated;
1633         unsigned error;
1634 } membuffer;
1635
1636 #define stricmp strcasecmp
1637
1638 membuffer * membuffer_create()
1639 {
1640         const unsigned initial_size = 256;
1641
1642         membuffer * buf = (membuffer *) malloc(sizeof(membuffer));
1643         buf->data = malloc(initial_size);
1644         buf->written = 0;
1645         buf->allocated = initial_size;
1646         buf->error = buf->data == 0 ? 1 : 0;
1647
1648         return buf;
1649 }
1650
1651 unsigned membuffer_write(membuffer * buf,const void * ptr,unsigned bytes)
1652 {
1653         unsigned dest_size = buf->written + bytes;
1654
1655         if (buf->error) return 0;
1656         if (dest_size > buf->allocated)
1657         {
1658                 do
1659                 {
1660                         buf->allocated <<= 1;
1661                 } while(dest_size > buf->allocated);
1662                 
1663                 {
1664                         void * newptr = realloc(buf->data,buf->allocated);
1665                         if (newptr==0)
1666                         {
1667                                 free(buf->data);
1668                                 buf->data = 0;
1669                                 buf->error = 1;
1670                                 return 0;
1671                         }
1672                         buf->data = newptr;
1673                 }
1674         }
1675
1676         if (ptr) memcpy((char*)buf->data + buf->written,ptr,bytes);
1677         buf->written += bytes;
1678         return bytes;
1679 }
1680 #define membuffer_write_data membuffer_write
1681
1682 unsigned membuffer_write_atom_name(membuffer * buf,const char * data)
1683 {
1684         return membuffer_write_data(buf,data,4)==4 ? 1 : 0;
1685 }
1686
1687 unsigned membuffer_write_int16(membuffer * buf,uint16_t data)
1688 {
1689         uint8_t temp[2] = {(uint8_t)(data>>8),(uint8_t)data};
1690         return membuffer_write_data(buf,temp,2);
1691 }
1692
1693 unsigned membuffer_write_int32(membuffer * buf,uint32_t data)
1694 {
1695         uint8_t temp[4] = {(uint8_t)(data>>24),(uint8_t)(data>>16),(uint8_t)(data>>8),(uint8_t)data};   
1696         return membuffer_write_data(buf,temp,4);
1697 }
1698
1699 static void membuffer_write_track_tag(membuffer * buf,const char * name,uint32_t index,uint32_t total)
1700 {
1701         membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
1702         membuffer_write_atom_name(buf,name);
1703         membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 8 /*actual data*/ );
1704         membuffer_write_atom_name(buf,"data");
1705         membuffer_write_int32(buf,0);//flags
1706         membuffer_write_int32(buf,0);//reserved
1707         membuffer_write_int16(buf,0);
1708         membuffer_write_int16(buf,(uint16_t)index);//track number
1709         membuffer_write_int16(buf,(uint16_t)total);//total tracks
1710         membuffer_write_int16(buf,0);
1711 }
1712
1713 static void membuffer_write_int16_tag(membuffer * buf,const char * name,uint16_t value)
1714 {
1715         membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
1716         membuffer_write_atom_name(buf,name);
1717         membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + 2 /*actual data*/ );
1718         membuffer_write_atom_name(buf,"data");
1719         membuffer_write_int32(buf,0);//flags
1720         membuffer_write_int32(buf,0);//reserved
1721         membuffer_write_int16(buf,value);//value
1722 }
1723
1724 static uint32_t myatoi(const char * param)
1725 {
1726         return param ? atoi(param) : 0;
1727 }
1728
1729 uint32_t mp4ff_meta_genre_to_index(const char * genrestr)
1730 {
1731         unsigned n;
1732         for(n=0;n<sizeof(ID3v1GenreList)/sizeof(ID3v1GenreList[0]);n++)
1733         {
1734                 if (!stricmp(genrestr,ID3v1GenreList[n])) return n+1;
1735         }
1736         return 0;
1737 }
1738
1739 typedef struct
1740 {
1741         const char * atom;
1742         const char * name;      
1743 } stdmeta_entry;
1744
1745 static stdmeta_entry stdmetas[] = 
1746 {
1747         {"\xA9" "nam","title"},
1748         {"\xA9" "ART","artist"},
1749         {"\xA9" "wrt","writer"},
1750         {"\xA9" "alb","album"},
1751         {"\xA9" "day","date"},
1752         {"\xA9" "too","tool"},
1753         {"\xA9" "cmt","comment"},
1754 //      {"\xA9" "gen","genre"},
1755         {"cpil","compilation"},
1756 //      {"trkn","track"},
1757 //      {"disk","disc"},
1758 //      {"gnre","genre"},
1759         {"covr","cover"},
1760         /* added by AJS */
1761         {"aART","album_artist"},
1762 };
1763
1764
1765 static const char* find_standard_meta(const char * name) //returns atom name if found, 0 if not
1766 {
1767         unsigned n;
1768         for(n=0;n<sizeof(stdmetas)/sizeof(stdmetas[0]);n++)
1769         {
1770                 if (!stricmp(name,stdmetas[n].name)) return stdmetas[n].atom;
1771         }
1772     return 0;
1773 }
1774
1775 static void membuffer_write_std_tag(membuffer * buf,const char * name,const char * value)
1776 {
1777         /* added by AJS */
1778         uint32_t flags = 1;
1779
1780         /* special check for compilation flag */
1781         if ( strcmp(name, "cpil") == 0)
1782         {
1783                 flags = 21;
1784         }
1785
1786         membuffer_write_int32(buf,8 /*atom header*/ + 8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value) );
1787         membuffer_write_atom_name(buf,name);
1788         membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
1789         membuffer_write_atom_name(buf,"data");
1790         membuffer_write_int32(buf,flags);//flags
1791         membuffer_write_int32(buf,0);//reserved
1792         membuffer_write_data(buf,value,strlen(value));
1793 }
1794
1795 static void membuffer_write_custom_tag(membuffer * buf,const char * name,const char * value)
1796 {
1797         membuffer_write_int32(buf,8 /*atom header*/ + 0x1C /*weirdo itunes atom*/ + 12 /*name atom header*/ + strlen(name) + 16 /*data atom header + flags*/ + strlen(value) );
1798         membuffer_write_atom_name(buf,"----");
1799         membuffer_write_int32(buf,0x1C);//weirdo itunes atom
1800         membuffer_write_atom_name(buf,"mean");
1801         membuffer_write_int32(buf,0);
1802         membuffer_write_data(buf,"com.apple.iTunes",16);
1803         membuffer_write_int32(buf,12 + strlen(name));
1804         membuffer_write_atom_name(buf,"name");
1805         membuffer_write_int32(buf,0);
1806         membuffer_write_data(buf,name,strlen(name));
1807         membuffer_write_int32(buf,8 /*data atom header*/ + 8 /*flags + reserved*/ + strlen(value));
1808         membuffer_write_atom_name(buf,"data");
1809         membuffer_write_int32(buf,1);//flags
1810         membuffer_write_int32(buf,0);//reserved
1811         membuffer_write_data(buf,value,strlen(value));
1812 }
1813
1814 unsigned membuffer_error(const membuffer * buf)
1815 {
1816         return buf->error;
1817 }
1818
1819 void membuffer_free(membuffer * buf)
1820 {
1821         if (buf->data) free(buf->data);
1822         free(buf);
1823 }
1824
1825 unsigned membuffer_get_size(const membuffer * buf)
1826 {
1827         return buf->written;
1828 }
1829
1830 void * membuffer_detach(membuffer * buf)
1831 {
1832         void * ret;
1833
1834         if (buf->error) return 0;
1835
1836         ret = realloc(buf->data,buf->written);
1837         
1838         if (ret == 0) free(buf->data);
1839
1840         buf->data = 0;
1841         buf->error = 1;
1842         
1843         return ret;
1844 }
1845
1846 static uint32_t create_ilst(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
1847 {
1848         membuffer * buf = membuffer_create();
1849         unsigned metaptr;
1850         char * mask = (char*)malloc(data->count);
1851         memset(mask,0,data->count);
1852
1853         {
1854                 const char * tracknumber_ptr = 0, * totaltracks_ptr = 0;
1855                 const char * discnumber_ptr = 0, * totaldiscs_ptr = 0;
1856                 const char * genre_ptr = 0, * tempo_ptr = 0;
1857                 for(metaptr = 0; metaptr < data->count; metaptr++)
1858                 {
1859                         mp4ff_tag_t * tag = &data->tags[metaptr];
1860                         if (!stricmp(tag->item,"tracknumber") || !stricmp(tag->item,"track"))
1861                         {
1862                                 if (tracknumber_ptr==0) tracknumber_ptr = tag->value;
1863                                 mask[metaptr] = 1;
1864                         }
1865                         else if (!stricmp(tag->item,"totaltracks"))
1866                         {
1867                                 if (totaltracks_ptr==0) totaltracks_ptr = tag->value;
1868                                 mask[metaptr] = 1;
1869                         }
1870                         else if (!stricmp(tag->item,"discnumber") || !stricmp(tag->item,"disc"))
1871                         {
1872                                 if (discnumber_ptr==0) discnumber_ptr = tag->value;
1873                                 mask[metaptr] = 1;
1874                         }
1875                         else if (!stricmp(tag->item,"totaldiscs"))
1876                         {
1877                                 if (totaldiscs_ptr==0) totaldiscs_ptr = tag->value;
1878                                 mask[metaptr] = 1;
1879                         }
1880                         else if (!stricmp(tag->item,"genre"))
1881                         {
1882                                 if (genre_ptr==0) genre_ptr = tag->value;
1883                                 mask[metaptr] = 1;
1884                         }
1885                         else if (!stricmp(tag->item,"tempo"))
1886                         {
1887                                 if (tempo_ptr==0) tempo_ptr = tag->value;
1888                                 mask[metaptr] = 1;
1889                         }
1890
1891                 }
1892
1893                 if (tracknumber_ptr) membuffer_write_track_tag(buf,"trkn",myatoi(tracknumber_ptr),myatoi(totaltracks_ptr));
1894                 if (discnumber_ptr) membuffer_write_track_tag(buf,"disk",myatoi(discnumber_ptr),myatoi(totaldiscs_ptr));
1895                 if (tempo_ptr) membuffer_write_int16_tag(buf,"tmpo",(uint16_t)myatoi(tempo_ptr));
1896
1897                 if (genre_ptr)
1898                 {
1899                         uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1900                         if (index==0)
1901                                 membuffer_write_std_tag(buf,"©gen",genre_ptr);
1902                         else
1903                                 membuffer_write_int16_tag(buf,"gnre",(uint16_t)index);
1904                 }
1905         }
1906         
1907         for(metaptr = 0; metaptr < data->count; metaptr++)
1908         {
1909                 if (!mask[metaptr])
1910                 {
1911                         mp4ff_tag_t * tag = &data->tags[metaptr];
1912                         const char * std_meta_atom = find_standard_meta(tag->item);
1913                         if (std_meta_atom)
1914                         {
1915                                 membuffer_write_std_tag(buf,std_meta_atom,tag->value);
1916                         }
1917                         else
1918                         {
1919                                 membuffer_write_custom_tag(buf,tag->item,tag->value);
1920                         }
1921                 }
1922         }
1923
1924         free(mask);
1925
1926         if (membuffer_error(buf))
1927         {
1928                 membuffer_free(buf);
1929                 return 0;
1930         }
1931
1932         *out_size = membuffer_get_size(buf);
1933         *out_buffer = membuffer_detach(buf);
1934         membuffer_free(buf);
1935
1936         return 1;
1937 }
1938
1939 void membuffer_write_atom(membuffer * buf,const char * name,unsigned size,const void * data)
1940 {
1941         membuffer_write_int32(buf,size + 8);
1942         membuffer_write_atom_name(buf,name);
1943         membuffer_write_data(buf,data,size);
1944 }
1945
1946 void * membuffer_get_ptr(const membuffer * buf)
1947 {
1948         return buf->data;
1949 }
1950
1951 void membuffer_set_error(membuffer * buf)
1952 {
1953         buf->error = 1;
1954 }
1955
1956 unsigned membuffer_transfer_from_file(membuffer * buf,mp4ff_t * src,unsigned bytes)
1957 {
1958         unsigned oldsize;
1959         void * bufptr;
1960         
1961         oldsize = membuffer_get_size(buf);
1962         if (membuffer_write_data(buf,0,bytes) != bytes) return 0;
1963
1964         bufptr = membuffer_get_ptr(buf);
1965         if (bufptr==0) return 0;
1966         
1967         if ((unsigned)mp4ff_read_data(src,(char*)bufptr + oldsize,bytes)!=bytes)
1968         {
1969                 membuffer_set_error(buf);
1970                 return 0;
1971         }
1972         
1973         return bytes;
1974 }
1975
1976 static uint32_t create_meta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
1977 {
1978         membuffer * buf;
1979         uint32_t ilst_size;
1980         void * ilst_buffer;
1981
1982         if (!create_ilst(data,&ilst_buffer,&ilst_size)) return 0;
1983
1984         buf = membuffer_create();
1985
1986         membuffer_write_int32(buf,0);
1987         membuffer_write_atom(buf,"ilst",ilst_size,ilst_buffer);
1988         free(ilst_buffer);
1989
1990         *out_size = membuffer_get_size(buf);
1991         *out_buffer = membuffer_detach(buf);
1992         membuffer_free(buf);
1993         return 1;
1994 }
1995
1996 static uint32_t create_udta(const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
1997 {
1998         membuffer * buf;
1999         uint32_t meta_size;
2000         void * meta_buffer;
2001
2002         if (!create_meta(data,&meta_buffer,&meta_size)) return 0;
2003
2004         buf = membuffer_create();
2005
2006         membuffer_write_atom(buf,"meta",meta_size,meta_buffer);
2007
2008         free(meta_buffer);
2009
2010         *out_size = membuffer_get_size(buf);
2011         *out_buffer = membuffer_detach(buf);
2012         membuffer_free(buf);
2013         return 1;
2014 }
2015
2016 static uint32_t fix_byte_order_32(uint32_t src)
2017 {
2018     uint32_t result;
2019     uint32_t a, b, c, d;
2020     int8_t data[4];
2021     
2022     memcpy(data,&src,sizeof(src));
2023     a = (uint8_t)data[0];
2024     b = (uint8_t)data[1];
2025     c = (uint8_t)data[2];
2026     d = (uint8_t)data[3];
2027
2028     result = (a<<24) | (b<<16) | (c<<8) | d;
2029     return (uint32_t)result;
2030 }
2031
2032 static uint32_t modify_moov(mp4ff_t * f,const mp4ff_metadata_t * data,void ** out_buffer,uint32_t * out_size)
2033 {
2034         uint64_t total_base = f->moov_offset + 8;
2035         uint32_t total_size = (uint32_t)(f->moov_size - 8);
2036
2037         uint64_t udta_offset,meta_offset,ilst_offset;
2038         uint32_t udta_size,  meta_size,  ilst_size;
2039         
2040         uint32_t new_ilst_size;
2041         void * new_ilst_buffer;
2042         
2043         uint8_t * p_out;
2044         int32_t size_delta;
2045         
2046         
2047         if (!find_atom_v2(f,total_base,total_size,"udta",0,"meta"))
2048         {
2049                 membuffer * buf;
2050                 void * new_udta_buffer;
2051                 uint32_t new_udta_size;
2052                 if (!create_udta(data,&new_udta_buffer,&new_udta_size)) return 0;
2053                 
2054                 buf = membuffer_create();
2055                 mp4ff_set_position(f,total_base);
2056                 membuffer_transfer_from_file(buf,f,total_size);
2057                 
2058                 membuffer_write_atom(buf,"udta",new_udta_size,new_udta_buffer);
2059
2060                 free(new_udta_buffer);
2061         
2062                 *out_size = membuffer_get_size(buf);
2063                 *out_buffer = membuffer_detach(buf);
2064                 membuffer_free(buf);
2065                 return 1;               
2066         }
2067         else
2068         {
2069                 udta_offset = mp4ff_position(f);
2070                 udta_size = mp4ff_read_int32(f);
2071                 if (!find_atom_v2(f,udta_offset+8,udta_size-8,"meta",4,"ilst"))
2072                 {
2073                         membuffer * buf;
2074                         void * new_meta_buffer;
2075                         uint32_t new_meta_size;
2076                         if (!create_meta(data,&new_meta_buffer,&new_meta_size)) return 0;
2077                         
2078                         buf = membuffer_create();
2079                         mp4ff_set_position(f,total_base);
2080                         membuffer_transfer_from_file(buf,f,(uint32_t)(udta_offset - total_base));
2081                         
2082                         membuffer_write_int32(buf,udta_size + 8 + new_meta_size);
2083                         membuffer_write_atom_name(buf,"udta");
2084                         membuffer_transfer_from_file(buf,f,udta_size);
2085                                                 
2086                         membuffer_write_atom(buf,"meta",new_meta_size,new_meta_buffer);
2087                         free(new_meta_buffer);
2088                 
2089                         *out_size = membuffer_get_size(buf);
2090                         *out_buffer = membuffer_detach(buf);
2091                         membuffer_free(buf);
2092                         return 1;               
2093                 }
2094                 meta_offset = mp4ff_position(f);
2095                 meta_size = mp4ff_read_int32(f);
2096                 if (!find_atom(f,meta_offset+12,meta_size-12,"ilst")) return 0;//shouldn't happen, find_atom_v2 above takes care of it
2097                 ilst_offset = mp4ff_position(f);
2098                 ilst_size = mp4ff_read_int32(f);
2099
2100                 if (!create_ilst(data,&new_ilst_buffer,&new_ilst_size)) return 0;
2101                 
2102                 size_delta = new_ilst_size - (ilst_size - 8);
2103
2104                 *out_size = total_size + size_delta;
2105                 *out_buffer = malloc(*out_size);
2106                 if (*out_buffer == 0)
2107                 {
2108                         free(new_ilst_buffer);
2109                         return 0;
2110                 }
2111
2112                 p_out = (uint8_t*)*out_buffer;
2113                 
2114                 mp4ff_set_position(f,total_base);
2115                 mp4ff_read_data(f,p_out,(uint32_t)(udta_offset - total_base )); p_out += (uint32_t)(udta_offset - total_base );
2116                 *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
2117                 mp4ff_read_data(f,p_out,4); p_out += 4;
2118                 mp4ff_read_data(f,p_out,(uint32_t)(meta_offset - udta_offset - 8)); p_out += (uint32_t)(meta_offset - udta_offset - 8);
2119                 *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
2120                 mp4ff_read_data(f,p_out,4); p_out += 4;
2121                 mp4ff_read_data(f,p_out,(uint32_t)(ilst_offset - meta_offset - 8)); p_out += (uint32_t)(ilst_offset - meta_offset - 8);
2122                 *(uint32_t*)p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta); p_out += 4;
2123                 mp4ff_read_data(f,p_out,4); p_out += 4;
2124
2125                 memcpy(p_out,new_ilst_buffer,new_ilst_size);
2126                 p_out += new_ilst_size;
2127
2128                 mp4ff_set_position(f,ilst_offset + ilst_size);
2129                 mp4ff_read_data(f,p_out,(uint32_t)(total_size - (ilst_offset - total_base) - ilst_size));
2130
2131                 free(new_ilst_buffer);
2132         }
2133         return 1;
2134 }
2135
2136 int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size)
2137 {
2138     int32_t result = 1;
2139
2140     result = f->stream->write(f->stream->user_data, data, size);
2141
2142     f->current_position += size;
2143
2144     return result;
2145 }
2146
2147 int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data)
2148 {
2149         uint32_t result;
2150     uint32_t a, b, c, d;
2151     int8_t temp[4];
2152     
2153     *(uint32_t*)temp = data;
2154     a = (uint8_t)temp[0];
2155     b = (uint8_t)temp[1];
2156     c = (uint8_t)temp[2];
2157     d = (uint8_t)temp[3];
2158
2159     result = (a<<24) | (b<<16) | (c<<8) | d;
2160
2161     return mp4ff_write_data(f,(uint8_t*)&result,sizeof(result));
2162 }
2163
2164 int32_t mp4ff_truncate(mp4ff_t * f)
2165 {
2166         return f->stream->truncate(f->stream->user_data);
2167 }
2168
2169 int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data)
2170 {
2171         void * new_moov_data;
2172         uint32_t new_moov_size;
2173
2174     mp4ff_t *ff = malloc(sizeof(mp4ff_t));
2175
2176     memset(ff, 0, sizeof(mp4ff_t));
2177     ff->stream = f;
2178         mp4ff_set_position(ff,0);
2179
2180     parse_atoms(ff,1);
2181
2182
2183         if (!modify_moov(ff,data,&new_moov_data,&new_moov_size))
2184         {
2185                 mp4ff_close(ff);
2186                 return 0;
2187         }
2188
2189     /* copy moov atom to end of the file */
2190     if (ff->last_atom != ATOM_MOOV)
2191     {
2192         char *free_data = "free";
2193
2194         /* rename old moov to free */
2195         mp4ff_set_position(ff, ff->moov_offset + 4);
2196         mp4ff_write_data(ff, free_data, 4);
2197         
2198         mp4ff_set_position(ff, ff->file_size);
2199                 mp4ff_write_int32(ff,new_moov_size + 8);
2200                 mp4ff_write_data(ff,"moov",4);
2201                 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2202     }
2203         else
2204         {
2205         mp4ff_set_position(ff, ff->moov_offset);
2206                 mp4ff_write_int32(ff,new_moov_size + 8);
2207                 mp4ff_write_data(ff,"moov",4);
2208                 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2209         }
2210
2211         mp4ff_truncate(ff);
2212
2213         mp4ff_close(ff);
2214     return 1;
2215 }
2216
2217 /* find a metadata item by name */
2218 /* returns 0 if item found, 1 if no such item */
2219 static int32_t mp4ff_meta_find_by_name(const mp4ff_t *f, const char *item, char **value)
2220 {
2221     uint32_t i;
2222
2223     for (i = 0; i < f->tags.count; i++)
2224     {
2225         if (!stricmp(f->tags.tags[i].item, item))
2226         {
2227                         *value = strdup(f->tags.tags[i].value);
2228             return 1;
2229         }
2230     }
2231
2232     *value = NULL;
2233
2234     /* not found */
2235     return 0;
2236 }
2237
2238 int32_t mp4ff_meta_get_artist(const mp4ff_t *f, char **value)
2239 {
2240     return mp4ff_meta_find_by_name(f, "artist", value);
2241 }
2242
2243 int32_t mp4ff_meta_get_title(const mp4ff_t *f, char **value)
2244 {
2245     return mp4ff_meta_find_by_name(f, "title", value);
2246 }
2247
2248
2249 int32_t mp4ff_meta_get_date(const mp4ff_t *f, char **value)
2250 {
2251     return mp4ff_meta_find_by_name(f, "date", value);
2252 }
2253
2254 int32_t mp4ff_meta_get_album(const mp4ff_t *f, char **value)
2255 {
2256     return mp4ff_meta_find_by_name(f, "album", value);
2257 }
2258
2259 int32_t mp4ff_meta_get_comment(const mp4ff_t *f, char **value)
2260 {
2261     return mp4ff_meta_find_by_name(f, "comment", value);
2262 }