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