]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
mp4: free(NULL) is OK.
[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         free(f->track[f->total_tracks - 1]->decoderConfig);
648         f->track[f->total_tracks - 1]->decoderConfig =
649                 para_malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
650         if (f->track[f->total_tracks - 1]->decoderConfig) {
651                 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig,
652                                 f->track[f->total_tracks -
653                                          1]->decoderConfigLen);
654         }
655         /* will skip the remainder of the atom */
656         return 0;
657 }
658 static int32_t mp4ff_read_mp4a(mp4ff_t * f)
659 {
660         int32_t i;
661         uint8_t atom_type = 0;
662         uint8_t header_size = 0;
663
664         if (f->total_tracks == 0)
665                 return f->error++;
666
667         for (i = 0; i < 6; i++) {
668                 mp4ff_read_char(f);     /* reserved */
669         }
670         /* data_reference_index */ mp4ff_read_int16(f);
671
672         mp4ff_read_int32(f);    /* reserved */
673         mp4ff_read_int32(f);    /* reserved */
674
675         f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
676         f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
677
678         mp4ff_read_int16(f);
679         mp4ff_read_int16(f);
680
681         f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
682
683         mp4ff_read_int16(f);
684
685         mp4ff_atom_read_header(f, &atom_type, &header_size);
686         if (atom_type == ATOM_ESDS) {
687                 mp4ff_read_esds(f);
688         }
689
690         return 0;
691 }
692
693 static int32_t mp4ff_read_stsd(mp4ff_t * f)
694 {
695         int32_t i;
696         uint8_t header_size = 0;
697
698         /* CVE-2017-9218 */
699         if (f->total_tracks == 0)
700                 return f->error++;
701
702         mp4ff_read_char(f);     /* version */
703         mp4ff_read_int24(f);    /* flags */
704
705         f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
706
707         for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count && !f->stream->read_error; i++) {       /* CVE-2017-9253 */
708                 uint64_t skip = mp4ff_position(f);
709                 uint64_t size;
710                 uint8_t atom_type = 0;
711                 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
712                 skip += size;
713
714                 if (atom_type == ATOM_MP4A) {
715                         f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
716                         mp4ff_read_mp4a(f);
717                 } else if (atom_type == ATOM_MP4V) {
718                         f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
719                 } else if (atom_type == ATOM_MP4S) {
720                         f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
721                 } else {
722                         f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
723                 }
724
725                 mp4ff_set_position(f, skip);
726         }
727
728         return 0;
729 }
730
731 static int32_t mp4ff_read_mvhd(mp4ff_t * f)
732 {
733         int32_t i;
734
735         mp4ff_read_char(f);     /* version */
736         mp4ff_read_int24(f);    /* flags */
737         /* creation_time */ mp4ff_read_int32(f);
738         /* modification_time */ mp4ff_read_int32(f);
739         f->time_scale = mp4ff_read_int32(f);
740         f->duration = mp4ff_read_int32(f);
741                                                         /* preferred_rate */ mp4ff_read_int32(f);
742                                                         /*mp4ff_read_fixed32(f); */
743                                                         /* preferred_volume */ mp4ff_read_int16(f);
744                                                         /*mp4ff_read_fixed16(f); */
745         for (i = 0; i < 10; i++) {
746                 /* reserved */ mp4ff_read_char(f);
747         }
748         for (i = 0; i < 9; i++) {
749                 mp4ff_read_int32(f);    /* matrix */
750         }
751         /* preview_time */ mp4ff_read_int32(f);
752         /* preview_duration */ mp4ff_read_int32(f);
753         /* poster_time */ mp4ff_read_int32(f);
754         /* selection_time */ mp4ff_read_int32(f);
755         /* selection_duration */ mp4ff_read_int32(f);
756         /* current_time */ mp4ff_read_int32(f);
757         /* next_track_id */ mp4ff_read_int32(f);
758
759         return 0;
760 }
761
762 static int32_t mp4ff_tag_add_field(mp4ff_metadata_t * tags, const char *item,
763                 const char *value, int32_t len)
764 {
765         void *backup = (void *) tags->tags;
766
767         if (!item || (item && !*item) || !value)
768                 return 0;
769
770         tags->tags = (mp4ff_tag_t *) realloc(tags->tags,
771                 (tags->count + 1) * sizeof (mp4ff_tag_t));
772         if (!tags->tags) {
773                 free(backup);
774                 return 0;
775         } else {
776                 tags->tags[tags->count].item = strdup(item);
777                 tags->tags[tags->count].len = len;
778                 if (len >= 0) {
779                         tags->tags[tags->count].value = para_malloc(len + 1);
780                         memcpy(tags->tags[tags->count].value, value, len);
781                         tags->tags[tags->count].value[len] = 0;
782                 } else {
783                         tags->tags[tags->count].value = strdup(value);
784                 }
785
786                 if (!tags->tags[tags->count].item || !tags->tags[tags->count].value) {
787                         free(tags->tags[tags->count].item);
788                         free(tags->tags[tags->count].value);
789                         tags->tags[tags->count].item = NULL;
790                         tags->tags[tags->count].value = NULL;
791                         tags->tags[tags->count].len = 0;
792                         return 0;
793                 }
794
795                 tags->count++;
796                 return 1;
797         }
798 }
799
800 static const char *ID3v1GenreList[] = {
801         "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk",
802         "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
803         "Other", "Pop", "R&B", "Rap", "Reggae", "Rock",
804         "Techno", "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
805         "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
806         "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid",
807         "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass",
808         "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
809         "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
810         "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream",
811         "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40",
812         "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret",
813         "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi",
814         "Tribal", "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical",
815         "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", "National Folk",
816         "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic",
817         "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
818         "Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
819         "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
820         "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
821         "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba",
822         "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
823         "Duet", "Punk Rock", "Drum Solo", "A capella", "Euro-House",
824         "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore", "Terror",
825         "Indie", "BritPop", "NegerPunk", "Polsk Punk", "Beat",
826         "Christian Gangsta", "Heavy Metal", "Black Metal", "Crossover",
827         "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal",
828         "Anime", "JPop", "SynthPop",
829 };
830
831 static const char *mp4ff_meta_index_to_genre(uint32_t idx)
832 {
833         if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
834                 return ID3v1GenreList[idx - 1];
835         } else {
836                 return 0;
837         }
838 }
839
840 static char *mp4ff_read_string(mp4ff_t * f, uint32_t length)
841 {
842         char *str = para_malloc(length + 1);
843         if ((uint32_t)mp4ff_read_data(f, str, length) != length) {
844                 free(str);
845                 str = NULL;
846         } else
847                 str[length] = 0;
848         return str;
849 }
850
851 static int32_t mp4ff_set_metadata_name(const uint8_t atom_type, char **name)
852 {
853         static char *tag_names[] = {
854                 "unknown", "title", "artist", "writer", "album",
855                 "date", "tool", "comment", "genre", "track",
856                 "disc", "compilation", "genre", "tempo", "cover",
857                 "album_artist", "contentgroup", "lyrics", "description",
858                 "network", "show", "episodename",
859                 "sorttitle", "sortalbum", "sortartist", "sortalbumartist",
860                 "sortwriter", "sortshow",
861                 "season", "episode", "podcast"
862         };
863         uint8_t tag_idx = 0;
864
865         switch (atom_type) {
866         case ATOM_TITLE:
867                 tag_idx = 1;
868                 break;
869         case ATOM_ARTIST:
870                 tag_idx = 2;
871                 break;
872         case ATOM_WRITER:
873                 tag_idx = 3;
874                 break;
875         case ATOM_ALBUM:
876                 tag_idx = 4;
877                 break;
878         case ATOM_DATE:
879                 tag_idx = 5;
880                 break;
881         case ATOM_TOOL:
882                 tag_idx = 6;
883                 break;
884         case ATOM_COMMENT:
885                 tag_idx = 7;
886                 break;
887         case ATOM_GENRE1:
888                 tag_idx = 8;
889                 break;
890         case ATOM_TRACK:
891                 tag_idx = 9;
892                 break;
893         case ATOM_DISC:
894                 tag_idx = 10;
895                 break;
896         case ATOM_COMPILATION:
897                 tag_idx = 11;
898                 break;
899         case ATOM_GENRE2:
900                 tag_idx = 12;
901                 break;
902         case ATOM_TEMPO:
903                 tag_idx = 13;
904                 break;
905         case ATOM_COVER:
906                 tag_idx = 14;
907                 break;
908         case ATOM_ALBUM_ARTIST:
909                 tag_idx = 15;
910                 break;
911         case ATOM_CONTENTGROUP:
912                 tag_idx = 16;
913                 break;
914         case ATOM_LYRICS:
915                 tag_idx = 17;
916                 break;
917         case ATOM_DESCRIPTION:
918                 tag_idx = 18;
919                 break;
920         case ATOM_NETWORK:
921                 tag_idx = 19;
922                 break;
923         case ATOM_SHOW:
924                 tag_idx = 20;
925                 break;
926         case ATOM_EPISODENAME:
927                 tag_idx = 21;
928                 break;
929         case ATOM_SORTTITLE:
930                 tag_idx = 22;
931                 break;
932         case ATOM_SORTALBUM:
933                 tag_idx = 23;
934                 break;
935         case ATOM_SORTARTIST:
936                 tag_idx = 24;
937                 break;
938         case ATOM_SORTALBUMARTIST:
939                 tag_idx = 25;
940                 break;
941         case ATOM_SORTWRITER:
942                 tag_idx = 26;
943                 break;
944         case ATOM_SORTSHOW:
945                 tag_idx = 27;
946                 break;
947         case ATOM_SEASON:
948                 tag_idx = 28;
949                 break;
950         case ATOM_EPISODE:
951                 tag_idx = 29;
952                 break;
953         case ATOM_PODCAST:
954                 tag_idx = 30;
955                 break;
956         default:
957                 tag_idx = 0;
958                 break;
959         }
960
961         *name = strdup(tag_names[tag_idx]);
962
963         return 0;
964 }
965
966 static int32_t mp4ff_parse_tag(mp4ff_t * f, const uint8_t parent_atom_type,
967                 const int32_t size)
968 {
969         uint8_t atom_type;
970         uint8_t header_size = 0;
971         uint64_t subsize, sumsize = 0;
972         char *name = NULL;
973         char *data = NULL;
974         uint32_t done = 0;
975         uint32_t len = 0;
976
977         while (sumsize < size && !f->stream->read_error) {      /* CVE-2017-9222 */
978                 uint64_t destpos;
979                 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
980                 destpos = mp4ff_position(f) + subsize - header_size;
981                 if (done)
982                         continue;
983                 if (atom_type == ATOM_DATA) {
984                         mp4ff_read_char(f);     /* version */
985                         mp4ff_read_int24(f);    /* flags */
986                         mp4ff_read_int32(f);    /* reserved */
987
988                         /* some need special attention */
989                         if (parent_atom_type == ATOM_GENRE2 || parent_atom_type == ATOM_TEMPO) {
990                                 if (subsize - header_size >= 8 + 2) {
991                                         uint16_t val = mp4ff_read_int16(f);
992
993                                         if (parent_atom_type == ATOM_TEMPO) {
994                                                 char temp[16];
995                                                 sprintf(temp,
996                                                         "%.5u BPM",
997                                                         val);
998                                                 mp4ff_tag_add_field(&(f-> tags), "tempo", temp, -1);
999                                         } else {
1000                                                 const char *temp = mp4ff_meta_index_to_genre(val);
1001                                                 if (temp) {
1002                                                         mp4ff_tag_add_field (&(f->tags), "genre", temp, -1);
1003                                                 }
1004                                         }
1005                                         done = 1;
1006                                 }
1007                         } else if (parent_atom_type == ATOM_TRACK || parent_atom_type == ATOM_DISC) {
1008                                 if (!done && (subsize - header_size) >= (sizeof (char) + sizeof (uint8_t) * 3 + sizeof (uint32_t) +     /* version + flags + reserved */
1009                                                                          +(parent_atom_type == ATOM_TRACK ? sizeof (uint16_t) : 0)      /* leading uint16_t if ATOM_TRACK */
1010                                                                          +sizeof (uint16_t)     /* track / disc */
1011                                                                          +sizeof (uint16_t))    /* totaltracks / totaldiscs */) {
1012                                         uint16_t index, total;
1013                                         char temp[32];
1014                                         mp4ff_read_int16(f);
1015                                         index = mp4ff_read_int16(f);
1016                                         total = mp4ff_read_int16(f);
1017                                         if (parent_atom_type == ATOM_TRACK)
1018                                                 mp4ff_read_int16(f);
1019
1020                                         sprintf(temp, "%d", index);
1021                                         mp4ff_tag_add_field(&(f->tags), parent_atom_type == ATOM_TRACK ?
1022                                                 "track" : "disc", temp, -1);
1023                                         if (total > 0) {
1024                                                 sprintf(temp, "%d",
1025                                                         total);
1026                                                 mp4ff_tag_add_field(& (f-> tags),
1027                                                         parent_atom_type == ATOM_TRACK?
1028                                                         "totaltracks" : "totaldiscs", temp, -1);
1029                                         }
1030                                         done = 1;
1031                                 }
1032                         } else {
1033                                 free(data);
1034                                 data = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 8)));
1035                                 len = (uint32_t) (subsize - (header_size + 8));
1036                         }
1037                 } else if (atom_type == ATOM_NAME) {
1038                         if (!done) {
1039                                 mp4ff_read_char(f);     /* version */
1040                                 mp4ff_read_int24(f);    /* flags */
1041                                 free(name);
1042                                 name = mp4ff_read_string(f, (uint32_t) (subsize - (header_size + 4)));
1043                         }
1044                 }
1045                 mp4ff_set_position(f, destpos);
1046                 sumsize += subsize;
1047         }
1048
1049         if (data) {
1050                 if (!done) {
1051                         if (name == NULL)
1052                                 mp4ff_set_metadata_name(parent_atom_type, &name);
1053                         if (name)
1054                                 mp4ff_tag_add_field(&(f->tags), name, data, len);
1055                 }
1056
1057                 free(data);
1058         }
1059         free(name);
1060         return 1;
1061 }
1062
1063 static int32_t mp4ff_read_mdhd(mp4ff_t * f)
1064 {
1065         uint32_t version;
1066
1067         /* CVE-2017-9221 */
1068         if (f->total_tracks == 0)
1069                 return f->error++;
1070
1071         version = mp4ff_read_int32(f);
1072         if (version == 1) {
1073                 mp4ff_read_int64(f);    //creation-time
1074                 mp4ff_read_int64(f);    //modification-time
1075                 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1076                 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);  //duration
1077         } else                  //version == 0
1078         {
1079                 uint32_t temp;
1080
1081                 mp4ff_read_int32(f);    //creation-time
1082                 mp4ff_read_int32(f);    //modification-time
1083                 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f); //timescale
1084                 temp = mp4ff_read_int32(f);
1085                 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t) (-1)) ? (uint64_t) (-1) : (uint64_t) (temp);
1086         }
1087         mp4ff_read_int16(f);
1088         mp4ff_read_int16(f);
1089         return 1;
1090 }
1091
1092 static int32_t mp4ff_parse_metadata(mp4ff_t * f, const int32_t size)
1093 {
1094         uint64_t subsize, sumsize = 0;
1095         uint8_t atom_type;
1096         uint8_t header_size = 0;
1097
1098         while (sumsize < size) {
1099                 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1100                 if (subsize == 0)
1101                         break;
1102                 mp4ff_parse_tag(f, atom_type,
1103                                 (uint32_t) (subsize - header_size));
1104                 sumsize += subsize;
1105         }
1106
1107         return 0;
1108 }
1109
1110 static int32_t mp4ff_read_meta(mp4ff_t * f, const uint64_t size)
1111 {
1112         uint64_t subsize, sumsize = 0;
1113         uint8_t atom_type;
1114         uint8_t header_size = 0;
1115
1116         mp4ff_read_char(f);     /* version */
1117         mp4ff_read_int24(f);    /* flags */
1118
1119         while (sumsize < (size - (header_size + 4))) {
1120                 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
1121                 if (subsize <= header_size + 4)
1122                         return 1;
1123                 if (atom_type == ATOM_ILST) {
1124                         mp4ff_parse_metadata(f, (uint32_t) (subsize - (header_size + 4)));
1125                 } else {
1126                         mp4ff_set_position(f, mp4ff_position(f) + subsize - header_size);
1127                 }
1128                 sumsize += subsize;
1129         }
1130
1131         return 0;
1132 }
1133
1134 static int32_t mp4ff_atom_read(mp4ff_t * f, const int32_t size,
1135                         const uint8_t atom_type)
1136 {
1137         uint64_t dest_position = mp4ff_position(f) + size - 8;
1138         if (atom_type == ATOM_STSZ) {
1139                 /* sample size box */
1140                 mp4ff_read_stsz(f);
1141         } else if (atom_type == ATOM_STTS) {
1142                 /* time to sample box */
1143                 mp4ff_read_stts(f);
1144         } else if (atom_type == ATOM_CTTS) {
1145                 /* composition offset box */
1146                 mp4ff_read_ctts(f);
1147         } else if (atom_type == ATOM_STSC) {
1148                 /* sample to chunk box */
1149                 mp4ff_read_stsc(f);
1150         } else if (atom_type == ATOM_STCO) {
1151                 /* chunk offset box */
1152                 mp4ff_read_stco(f);
1153         } else if (atom_type == ATOM_STSD) {
1154                 /* sample description box */
1155                 mp4ff_read_stsd(f);
1156         } else if (atom_type == ATOM_MVHD) {
1157                 /* movie header box */
1158                 mp4ff_read_mvhd(f);
1159         } else if (atom_type == ATOM_MDHD) {
1160                 /* track header */
1161                 mp4ff_read_mdhd(f);
1162         } else if (atom_type == ATOM_META) {
1163                 /* iTunes Metadata box */
1164                 mp4ff_read_meta(f, size);
1165         }
1166
1167         mp4ff_set_position(f, dest_position);
1168         return 0;
1169 }
1170
1171 /* parse atoms that are sub atoms of other atoms */
1172 static int32_t parse_sub_atoms(mp4ff_t * f, const uint64_t total_size, int meta_only)
1173 {
1174         uint64_t size;
1175         uint8_t atom_type = 0;
1176         uint64_t counted_size = 0;
1177         uint8_t header_size = 0;
1178
1179         while (counted_size < total_size) {
1180                 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
1181                 counted_size += size;
1182
1183                 /* check for end of file */
1184                 if (size == 0)
1185                         break;
1186
1187                 /* we're starting to read a new track, update index,
1188                  * so that all data and tables get written in the right place
1189                  */
1190                 if (atom_type == ATOM_TRAK) {
1191                         mp4ff_track_add(f);
1192                 }
1193
1194                 /* parse subatoms */
1195                 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1196                         mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1197                 } else if (atom_type < SUBATOMIC) {
1198                         parse_sub_atoms(f, size - header_size, meta_only);
1199                 } else {
1200                         mp4ff_atom_read(f, (uint32_t) size, atom_type);
1201                 }
1202         }
1203
1204         return 0;
1205 }
1206
1207 /* parse root atoms */
1208 static int32_t parse_atoms(mp4ff_t * f, int meta_only)
1209 {
1210         uint64_t size;
1211         uint8_t atom_type = 0;
1212         uint8_t header_size = 0;
1213
1214         f->file_size = 0;
1215         f->stream->read_error = 0;
1216
1217         while ((size =
1218                 mp4ff_atom_read_header(f, &atom_type, &header_size)) != 0) {
1219                 f->file_size += size;
1220                 f->last_atom = atom_type;
1221
1222                 if (atom_type == ATOM_MOOV && size > header_size) {
1223                         f->moov_offset = mp4ff_position(f) - header_size;
1224                         f->moov_size = size;
1225                 }
1226
1227                 /* parse subatoms */
1228                 if (meta_only && !need_parse_when_meta_only(atom_type)) {
1229                         mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1230                 } else if (atom_type < SUBATOMIC) {
1231                         parse_sub_atoms(f, size - header_size, meta_only);
1232                 } else {
1233                         /* skip this atom */
1234                         mp4ff_set_position(f, mp4ff_position(f) + size - header_size);
1235                 }
1236         }
1237
1238         return 0;
1239 }
1240
1241 void mp4ff_get_decoder_config(const mp4ff_t * f, const int track,
1242                                  unsigned char **ppBuf, unsigned int *pBufSize)
1243 {
1244         if (track >= f->total_tracks) {
1245                 *ppBuf = NULL;
1246                 *pBufSize = 0;
1247                 return;
1248         }
1249
1250         if (f->track[track]->decoderConfig == NULL
1251                 || f->track[track]->decoderConfigLen == 0) {
1252                 *ppBuf = NULL;
1253                 *pBufSize = 0;
1254         } else {
1255                 *ppBuf = para_malloc(f->track[track]->decoderConfigLen);
1256                 memcpy(*ppBuf, f->track[track]->decoderConfig,
1257                         f->track[track]->decoderConfigLen);
1258                 *pBufSize = f->track[track]->decoderConfigLen;
1259         }
1260 }
1261
1262 mp4ff_t *mp4ff_open_read(mp4ff_callback_t * f)
1263 {
1264         mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1265
1266         ff->stream = f;
1267
1268         parse_atoms(ff, 0);
1269
1270         if (ff->error) {
1271                 free(ff);
1272                 ff = NULL;
1273         }
1274
1275         return ff;
1276 }
1277
1278 static int32_t mp4ff_tag_delete(mp4ff_metadata_t * tags)
1279 {
1280         uint32_t i;
1281
1282         for (i = 0; i < tags->count; i++) {
1283                 free(tags->tags[i].item);
1284                 free(tags->tags[i].value);
1285         }
1286         free(tags->tags);
1287         tags->tags = NULL;
1288         tags->count = 0;
1289
1290         return 0;
1291 }
1292
1293 void mp4ff_close(mp4ff_t * ff)
1294 {
1295         int32_t i;
1296
1297         for (i = 0; i < ff->total_tracks; i++) {
1298                 if (ff->track[i]) {
1299                         free(ff->track[i]->stsz_table);
1300                         free(ff->track[i]->stts_sample_count);
1301                         free(ff->track[i]->stts_sample_delta);
1302                         free(ff->track[i]->stsc_first_chunk);
1303                         free(ff->track[i]->stsc_samples_per_chunk);
1304                         free(ff->track[i]->stsc_sample_desc_index);
1305                         free(ff->track[i]->stco_chunk_offset);
1306                         free(ff->track[i]->decoderConfig);
1307                         free(ff->track[i]->ctts_sample_count);
1308                         free(ff->track[i]->ctts_sample_offset);
1309                         free(ff->track[i]);
1310                 }
1311         }
1312
1313         mp4ff_tag_delete(&(ff->tags));
1314         free(ff);
1315 }
1316
1317 static int32_t mp4ff_chunk_of_sample(const mp4ff_t * f, const int32_t track,
1318                 const int32_t sample, int32_t * chunk_sample, int32_t * chunk)
1319 {
1320         int32_t total_entries = 0;
1321         int32_t chunk2entry;
1322         int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
1323
1324         *chunk_sample = 0;
1325         *chunk = 1;
1326         if (f->track[track] == NULL) {
1327                 return -1;
1328         }
1329
1330         total_entries = f->track[track]->stsc_entry_count;
1331
1332         chunk1 = 1;
1333         chunk1samples = 0;
1334         chunk2entry = 0;
1335
1336         do {
1337                 chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
1338                 *chunk = chunk2 - chunk1;
1339                 range_samples = *chunk * chunk1samples;
1340
1341                 if (sample < total + range_samples)
1342                         break;
1343
1344                 chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
1345                 chunk1 = chunk2;
1346
1347                 if (chunk2entry < total_entries) {
1348                         chunk2entry++;
1349                         total += range_samples;
1350                 }
1351         } while (chunk2entry < total_entries);
1352
1353         if (chunk1samples)
1354                 *chunk = (sample - total) / chunk1samples + chunk1;
1355         else
1356                 *chunk = 1;
1357
1358         *chunk_sample = total + (*chunk - chunk1) * chunk1samples;
1359
1360         return 0;
1361 }
1362
1363 static int32_t mp4ff_chunk_to_offset(const mp4ff_t * f, const int32_t track,
1364                 const int32_t chunk)
1365 {
1366         const mp4ff_track_t *p_track = f->track[track];
1367
1368         if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count)) {
1369                 return p_track->stco_chunk_offset[p_track->stco_entry_count -
1370                                                   1];
1371         } else if (p_track->stco_entry_count) {
1372                 return p_track->stco_chunk_offset[chunk - 1];
1373         } else {
1374                 return 8;
1375         }
1376
1377         return 0;
1378 }
1379
1380 static int32_t mp4ff_sample_range_size(const mp4ff_t * f, const int32_t track,
1381                 const int32_t chunk_sample, const int32_t sample)
1382 {
1383         int32_t i, total;
1384         const mp4ff_track_t *p_track = f->track[track];
1385
1386         if (p_track->stsz_sample_size) {
1387                 return (sample - chunk_sample) * p_track->stsz_sample_size;
1388         } else {
1389                 if (sample >= p_track->stsz_sample_count)
1390                         return 0;       //error
1391
1392                 for (i = chunk_sample, total = 0; i < sample; i++) {
1393                         total += p_track->stsz_table[i];
1394                 }
1395         }
1396
1397         return total;
1398 }
1399 static int32_t mp4ff_sample_to_offset(const mp4ff_t * f, const int32_t track,
1400                 const int32_t sample)
1401 {
1402         int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
1403
1404         mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
1405
1406         chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
1407         chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f,
1408                 track, chunk_sample, sample);
1409         return chunk_offset2;
1410 }
1411
1412 void mp4ff_set_sample_position(mp4ff_t *f, const int32_t track,
1413                 const int32_t sample)
1414 {
1415         int32_t offset = mp4ff_sample_to_offset(f, track, sample);
1416         mp4ff_set_position(f, offset);
1417 }
1418
1419 int32_t mp4ff_get_sample_size(const mp4ff_t *f, int track, int sample)
1420 {
1421         const mp4ff_track_t *t = f->track[track];
1422
1423         if (t->stsz_sample_size != 0)
1424                 return t->stsz_sample_size;
1425         return t->stsz_table[sample];
1426 }
1427
1428 uint32_t mp4ff_get_sample_rate(const mp4ff_t * f, const int32_t track)
1429 {
1430         return f->track[track]->sampleRate;
1431 }
1432
1433 uint32_t mp4ff_get_channel_count(const mp4ff_t * f, const int32_t track)
1434 {
1435         return f->track[track]->channelCount;
1436 }
1437
1438 int32_t mp4ff_num_samples(const mp4ff_t * f, const int32_t track)
1439 {
1440         int32_t i;
1441         int32_t total = 0;
1442
1443         for (i = 0; i < f->track[track]->stts_entry_count; i++) {
1444                 total += f->track[track]->stts_sample_count[i];
1445         }
1446         return total;
1447 }
1448
1449 mp4ff_t *mp4ff_open_read_metaonly(mp4ff_callback_t * f)
1450 {
1451         mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
1452
1453         ff->stream = f;
1454
1455         parse_atoms(ff, 1);
1456
1457         if (ff->error) {
1458                 free(ff);
1459                 ff = NULL;
1460         }
1461
1462         return ff;
1463 }
1464
1465 int32_t mp4ff_meta_get_num_items(const mp4ff_t * f)
1466 {
1467         return f->tags.count;
1468 }
1469
1470 int32_t mp4ff_meta_get_by_index(const mp4ff_t * f, uint32_t index,
1471                                 char **item, char **value)
1472 {
1473         if (index >= f->tags.count) {
1474                 *item = NULL;
1475                 *value = NULL;
1476                 return 0;
1477         } else {
1478                 *item = strdup(f->tags.tags[index].item);
1479                 *value = strdup(f->tags.tags[index].value);
1480                 return 1;
1481         }
1482 }
1483
1484 static uint32_t find_atom(mp4ff_t * f, uint64_t base, uint32_t size,
1485                           const char *name)
1486 {
1487         uint32_t remaining = size;
1488         uint64_t atom_offset = base;
1489         for (;;) {
1490                 char atom_name[4];
1491                 uint32_t atom_size;
1492
1493                 mp4ff_set_position(f, atom_offset);
1494
1495                 if (remaining < 8)
1496                         break;
1497                 atom_size = mp4ff_read_int32(f);
1498                 if (atom_size > remaining || atom_size < 8)
1499                         break;
1500                 mp4ff_read_data(f, atom_name, 4);
1501
1502                 if (!memcmp(atom_name, name, 4)) {
1503                         mp4ff_set_position(f, atom_offset);
1504                         return 1;
1505                 }
1506
1507                 remaining -= atom_size;
1508                 atom_offset += atom_size;
1509         }
1510         return 0;
1511 }
1512 static uint32_t find_atom_v2(mp4ff_t * f, uint64_t base, uint32_t size,
1513                 const char *name, uint32_t extraheaders, const char *name_inside)
1514 {
1515         uint64_t first_base = (uint64_t) (-1);
1516         while (find_atom(f, base, size, name))  //try to find atom <name> with atom <name_inside> in it
1517         {
1518                 uint64_t mybase = mp4ff_position(f);
1519                 uint32_t mysize = mp4ff_read_int32(f);
1520
1521                 if (first_base == (uint64_t) (-1))
1522                         first_base = mybase;
1523
1524                 if (mysize < 8 + extraheaders)
1525                         break;
1526
1527                 if (find_atom (f, mybase + (8 + extraheaders),
1528                                 mysize - (8 + extraheaders), name_inside)) {
1529                         mp4ff_set_position(f, mybase);
1530                         return 2;
1531                 }
1532                 base += mysize;
1533                 if (size <= mysize) {
1534                         size = 0;
1535                         break;
1536                 }
1537                 size -= mysize;
1538         }
1539
1540         if (first_base != (uint64_t) (-1))      //wanted atom inside not found
1541         {
1542                 mp4ff_set_position(f, first_base);
1543                 return 1;
1544         } else
1545                 return 0;
1546 }
1547
1548 typedef struct {
1549         void *data;
1550         unsigned written;
1551         unsigned allocated;
1552         unsigned error;
1553 } membuffer;
1554
1555 #define stricmp strcasecmp
1556
1557 static membuffer *membuffer_create(void)
1558 {
1559         const unsigned initial_size = 256;
1560
1561         membuffer *buf = para_malloc(sizeof (membuffer));
1562         buf->data = para_malloc(initial_size);
1563         buf->written = 0;
1564         buf->allocated = initial_size;
1565         buf->error = buf->data == 0 ? 1 : 0;
1566
1567         return buf;
1568 }
1569
1570 static unsigned membuffer_write(membuffer * buf, const void *ptr, unsigned bytes)
1571 {
1572         unsigned dest_size = buf->written + bytes;
1573
1574         if (buf->error)
1575                 return 0;
1576         if (dest_size > buf->allocated) {
1577                 do {
1578                         buf->allocated <<= 1;
1579                 } while (dest_size > buf->allocated);
1580
1581                 {
1582                         void *newptr = realloc(buf->data, buf->allocated);
1583                         if (newptr == 0) {
1584                                 free(buf->data);
1585                                 buf->data = 0;
1586                                 buf->error = 1;
1587                                 return 0;
1588                         }
1589                         buf->data = newptr;
1590                 }
1591         }
1592
1593         if (ptr)
1594                 memcpy((char *) buf->data + buf->written, ptr, bytes);
1595         buf->written += bytes;
1596         return bytes;
1597 }
1598
1599 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1600 {
1601         return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1602 }
1603
1604 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1605 {
1606         uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1607         return membuffer_write(buf, temp, 2);
1608 }
1609
1610 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1611 {
1612         uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1613                 (uint8_t) (data >> 8), (uint8_t) data };
1614         return membuffer_write(buf, temp, 4);
1615 }
1616
1617 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1618                 uint32_t index, uint32_t total)
1619 {
1620         membuffer_write_int32(buf,
1621                 8 /*atom header */  + 8 /*data atom header */  +
1622                 8 /*flags + reserved */  + 8 /*actual data */ );
1623         membuffer_write_atom_name(buf, name);
1624         membuffer_write_int32(buf,
1625                 8 /*data atom header */  +
1626                 8 /*flags + reserved */  + 8 /*actual data */ );
1627         membuffer_write_atom_name(buf, "data");
1628         membuffer_write_int32(buf, 0);  //flags
1629         membuffer_write_int32(buf, 0);  //reserved
1630         membuffer_write_int16(buf, 0);
1631         membuffer_write_int16(buf, (uint16_t) index);   //track number
1632         membuffer_write_int16(buf, (uint16_t) total);   //total tracks
1633         membuffer_write_int16(buf, 0);
1634 }
1635
1636 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1637                 uint16_t value)
1638 {
1639         membuffer_write_int32(buf,
1640                 8 /*atom header */  + 8 /*data atom header */  +
1641                 8 /*flags + reserved */  + 2 /*actual data */ );
1642         membuffer_write_atom_name(buf, name);
1643         membuffer_write_int32(buf,
1644                 8 /*data atom header */  +
1645                 8 /*flags + reserved */  + 2 /*actual data */ );
1646         membuffer_write_atom_name(buf, "data");
1647         membuffer_write_int32(buf, 0);  //flags
1648         membuffer_write_int32(buf, 0);  //reserved
1649         membuffer_write_int16(buf, value);      //value
1650 }
1651
1652 static uint32_t myatoi(const char *param)
1653 {
1654         return param ? atoi(param) : 0;
1655 }
1656
1657 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1658 {
1659         unsigned n;
1660         for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1661                 if (!stricmp(genrestr, ID3v1GenreList[n]))
1662                         return n + 1;
1663         }
1664         return 0;
1665 }
1666
1667 typedef struct {
1668         const char *atom;
1669         const char *name;
1670 } stdmeta_entry;
1671
1672 static stdmeta_entry stdmetas[] = {
1673         {"\xA9" "nam", "title"},
1674         {"\xA9" "ART", "artist"},
1675         {"\xA9" "wrt", "writer"},
1676         {"\xA9" "alb", "album"},
1677         {"\xA9" "day", "date"},
1678         {"\xA9" "too", "tool"},
1679         {"\xA9" "cmt", "comment"},
1680         {"cpil", "compilation"},
1681         {"covr", "cover"},
1682         {"aART", "album_artist"},
1683 };
1684
1685 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1686 {
1687         unsigned n;
1688         for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1689                 if (!stricmp(name, stdmetas[n].name))
1690                         return stdmetas[n].atom;
1691         }
1692         return 0;
1693 }
1694
1695 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1696                 const char *value)
1697 {
1698         uint32_t flags = 1;
1699
1700         /* special check for compilation flag */
1701         if (strcmp(name, "cpil") == 0) {
1702                 flags = 21;
1703         }
1704
1705         membuffer_write_int32(buf,
1706                 8 /*atom header */  + 8 /*data atom header */  +
1707                 8 /*flags + reserved */  + strlen(value));
1708         membuffer_write_atom_name(buf, name);
1709         membuffer_write_int32(buf,
1710                 8 /*data atom header */  +
1711                 8 /*flags + reserved */  + strlen(value));
1712         membuffer_write_atom_name(buf, "data");
1713         membuffer_write_int32(buf, flags);      //flags
1714         membuffer_write_int32(buf, 0);  //reserved
1715         membuffer_write(buf, value, strlen(value));
1716 }
1717
1718 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1719                 const char *value)
1720 {
1721         membuffer_write_int32(buf,
1722                 8 /*atom header */  +
1723                 0x1C /*weirdo itunes atom */  +
1724                 12 /*name atom header */  + strlen(name) +
1725                 16 /*data atom header + flags */  + strlen(value));
1726         membuffer_write_atom_name(buf, "----");
1727         membuffer_write_int32(buf, 0x1C);       //weirdo itunes atom
1728         membuffer_write_atom_name(buf, "mean");
1729         membuffer_write_int32(buf, 0);
1730         membuffer_write(buf, "com.apple.iTunes", 16);
1731         membuffer_write_int32(buf, 12 + strlen(name));
1732         membuffer_write_atom_name(buf, "name");
1733         membuffer_write_int32(buf, 0);
1734         membuffer_write(buf, name, strlen(name));
1735         membuffer_write_int32(buf,
1736                 8 /*data atom header */  +
1737                 8 /*flags + reserved */  + strlen(value));
1738         membuffer_write_atom_name(buf, "data");
1739         membuffer_write_int32(buf, 1);  //flags
1740         membuffer_write_int32(buf, 0);  //reserved
1741         membuffer_write(buf, value, strlen(value));
1742 }
1743
1744 static unsigned membuffer_error(const membuffer * buf)
1745 {
1746         return buf->error;
1747 }
1748
1749 static void membuffer_free(membuffer * buf)
1750 {
1751         free(buf->data);
1752         free(buf);
1753 }
1754
1755 static unsigned membuffer_get_size(const membuffer * buf)
1756 {
1757         return buf->written;
1758 }
1759
1760 static void *membuffer_detach(membuffer * buf)
1761 {
1762         void *ret;
1763
1764         if (buf->error)
1765                 return 0;
1766
1767         ret = realloc(buf->data, buf->written);
1768
1769         if (ret == 0)
1770                 free(buf->data);
1771
1772         buf->data = 0;
1773         buf->error = 1;
1774
1775         return ret;
1776 }
1777
1778 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1779                 uint32_t * out_size)
1780 {
1781         membuffer *buf = membuffer_create();
1782         unsigned metaptr;
1783         char *mask = para_calloc(data->count);
1784         {
1785                 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1786                 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1787                 const char *genre_ptr = 0, *tempo_ptr = 0;
1788                 for (metaptr = 0; metaptr < data->count; metaptr++) {
1789                         mp4ff_tag_t *tag = &data->tags[metaptr];
1790                         if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1791                                 if (tracknumber_ptr == 0)
1792                                         tracknumber_ptr = tag->value;
1793                                 mask[metaptr] = 1;
1794                         } else if (!stricmp(tag->item, "totaltracks")) {
1795                                 if (totaltracks_ptr == 0)
1796                                         totaltracks_ptr = tag->value;
1797                                 mask[metaptr] = 1;
1798                         } else if (!stricmp(tag->item, "discnumber")
1799                                         || !stricmp(tag->item, "disc")) {
1800                                 if (discnumber_ptr == 0)
1801                                         discnumber_ptr = tag->value;
1802                                 mask[metaptr] = 1;
1803                         } else if (!stricmp(tag->item, "totaldiscs")) {
1804                                 if (totaldiscs_ptr == 0)
1805                                         totaldiscs_ptr = tag->value;
1806                                 mask[metaptr] = 1;
1807                         } else if (!stricmp(tag->item, "genre")) {
1808                                 if (genre_ptr == 0)
1809                                         genre_ptr = tag->value;
1810                                 mask[metaptr] = 1;
1811                         } else if (!stricmp(tag->item, "tempo")) {
1812                                 if (tempo_ptr == 0)
1813                                         tempo_ptr = tag->value;
1814                                 mask[metaptr] = 1;
1815                         }
1816
1817                 }
1818
1819                 if (tracknumber_ptr)
1820                         membuffer_write_track_tag(buf, "trkn",
1821                                                   myatoi(tracknumber_ptr),
1822                                                   myatoi(totaltracks_ptr));
1823                 if (discnumber_ptr)
1824                         membuffer_write_track_tag(buf, "disk",
1825                                                   myatoi(discnumber_ptr),
1826                                                   myatoi(totaldiscs_ptr));
1827                 if (tempo_ptr)
1828                         membuffer_write_int16_tag(buf, "tmpo",
1829                                                   (uint16_t) myatoi(tempo_ptr));
1830
1831                 if (genre_ptr) {
1832                         uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1833                         if (index == 0)
1834                                 membuffer_write_std_tag(buf, "©gen",
1835                                                         genre_ptr);
1836                         else
1837                                 membuffer_write_int16_tag(buf, "gnre",
1838                                                           (uint16_t) index);
1839                 }
1840         }
1841
1842         for (metaptr = 0; metaptr < data->count; metaptr++) {
1843                 if (!mask[metaptr]) {
1844                         mp4ff_tag_t *tag = &data->tags[metaptr];
1845                         const char *std_meta_atom = find_standard_meta(tag->item);
1846                         if (std_meta_atom) {
1847                                 membuffer_write_std_tag(buf, std_meta_atom,
1848                                                         tag->value);
1849                         } else {
1850                                 membuffer_write_custom_tag(buf, tag->item,
1851                                         tag->value);
1852                         }
1853                 }
1854         }
1855
1856         free(mask);
1857
1858         if (membuffer_error(buf)) {
1859                 membuffer_free(buf);
1860                 return 0;
1861         }
1862
1863         *out_size = membuffer_get_size(buf);
1864         *out_buffer = membuffer_detach(buf);
1865         membuffer_free(buf);
1866
1867         return 1;
1868 }
1869
1870 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1871                           const void *data)
1872 {
1873         membuffer_write_int32(buf, size + 8);
1874         membuffer_write_atom_name(buf, name);
1875         membuffer_write(buf, data, size);
1876 }
1877
1878 static void *membuffer_get_ptr(const membuffer * buf)
1879 {
1880         return buf->data;
1881 }
1882
1883 static void membuffer_set_error(membuffer * buf)
1884 {
1885         buf->error = 1;
1886 }
1887
1888 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
1889                 unsigned bytes)
1890 {
1891         unsigned oldsize;
1892         void *bufptr;
1893
1894         oldsize = membuffer_get_size(buf);
1895         if (membuffer_write(buf, 0, bytes) != bytes)
1896                 return 0;
1897
1898         bufptr = membuffer_get_ptr(buf);
1899         if (bufptr == 0)
1900                 return 0;
1901
1902         if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
1903                 bytes) {
1904                 membuffer_set_error(buf);
1905                 return 0;
1906         }
1907
1908         return bytes;
1909 }
1910
1911 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
1912                 uint32_t * out_size)
1913 {
1914         membuffer *buf;
1915         uint32_t ilst_size;
1916         void *ilst_buffer;
1917
1918         if (!create_ilst(data, &ilst_buffer, &ilst_size))
1919                 return 0;
1920
1921         buf = membuffer_create();
1922
1923         membuffer_write_int32(buf, 0);
1924         membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
1925         free(ilst_buffer);
1926
1927         *out_size = membuffer_get_size(buf);
1928         *out_buffer = membuffer_detach(buf);
1929         membuffer_free(buf);
1930         return 1;
1931 }
1932
1933 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
1934 uint32_t * out_size)
1935 {
1936         membuffer *buf;
1937         uint32_t meta_size;
1938         void *meta_buffer;
1939
1940         if (!create_meta(data, &meta_buffer, &meta_size))
1941                 return 0;
1942
1943         buf = membuffer_create();
1944
1945         membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
1946
1947         free(meta_buffer);
1948
1949         *out_size = membuffer_get_size(buf);
1950         *out_buffer = membuffer_detach(buf);
1951         membuffer_free(buf);
1952         return 1;
1953 }
1954
1955 static uint32_t fix_byte_order_32(uint32_t src)
1956 {
1957         uint32_t result;
1958         uint32_t a, b, c, d;
1959         int8_t data[4];
1960
1961         memcpy(data, &src, sizeof (src));
1962         a = (uint8_t) data[0];
1963         b = (uint8_t) data[1];
1964         c = (uint8_t) data[2];
1965         d = (uint8_t) data[3];
1966
1967         result = (a << 24) | (b << 16) | (c << 8) | d;
1968         return (uint32_t) result;
1969 }
1970
1971 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
1972                 void **out_buffer, uint32_t * out_size)
1973 {
1974         uint64_t total_base = f->moov_offset + 8;
1975         uint32_t total_size = (uint32_t) (f->moov_size - 8);
1976
1977         uint64_t udta_offset, meta_offset, ilst_offset;
1978         uint32_t udta_size, meta_size, ilst_size;
1979
1980         uint32_t new_ilst_size;
1981         void *new_ilst_buffer;
1982
1983         uint8_t *p_out;
1984         int32_t size_delta;
1985
1986         if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
1987                 membuffer *buf;
1988                 void *new_udta_buffer;
1989                 uint32_t new_udta_size;
1990                 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
1991                         return 0;
1992
1993                 buf = membuffer_create();
1994                 mp4ff_set_position(f, total_base);
1995                 membuffer_transfer_from_file(buf, f, total_size);
1996
1997                 membuffer_write_atom(buf, "udta", new_udta_size,
1998                         new_udta_buffer);
1999
2000                 free(new_udta_buffer);
2001
2002                 *out_size = membuffer_get_size(buf);
2003                 *out_buffer = membuffer_detach(buf);
2004                 membuffer_free(buf);
2005                 return 1;
2006         } else {
2007                 udta_offset = mp4ff_position(f);
2008                 udta_size = mp4ff_read_int32(f);
2009                 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2010                         membuffer *buf;
2011                         void *new_meta_buffer;
2012                         uint32_t new_meta_size;
2013                         if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2014                                 return 0;
2015
2016                         buf = membuffer_create();
2017                         mp4ff_set_position(f, total_base);
2018                         membuffer_transfer_from_file(buf, f,
2019                                 (uint32_t)(udta_offset - total_base));
2020
2021                         membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2022                         membuffer_write_atom_name(buf, "udta");
2023                         membuffer_transfer_from_file(buf, f, udta_size);
2024
2025                         membuffer_write_atom(buf, "meta", new_meta_size,
2026                                 new_meta_buffer);
2027                         free(new_meta_buffer);
2028
2029                         *out_size = membuffer_get_size(buf);
2030                         *out_buffer = membuffer_detach(buf);
2031                         membuffer_free(buf);
2032                         return 1;
2033                 }
2034                 meta_offset = mp4ff_position(f);
2035                 meta_size = mp4ff_read_int32(f);
2036                 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2037                         return 0;       //shouldn't happen, find_atom_v2 above takes care of it
2038                 ilst_offset = mp4ff_position(f);
2039                 ilst_size = mp4ff_read_int32(f);
2040
2041                 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2042                         return 0;
2043
2044                 size_delta = new_ilst_size - (ilst_size - 8);
2045
2046                 *out_size = total_size + size_delta;
2047                 *out_buffer = para_malloc(*out_size);
2048                 p_out = (uint8_t *) * out_buffer;
2049
2050                 mp4ff_set_position(f, total_base);
2051                 mp4ff_read_data(f, p_out,
2052                                 (uint32_t) (udta_offset - total_base));
2053                 p_out += (uint32_t) (udta_offset - total_base);
2054                 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2055                 p_out += 4;
2056                 mp4ff_read_data(f, p_out, 4);
2057                 p_out += 4;
2058                 mp4ff_read_data(f, p_out,
2059                                 (uint32_t) (meta_offset - udta_offset - 8));
2060                 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2061                 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2062                 p_out += 4;
2063                 mp4ff_read_data(f, p_out, 4);
2064                 p_out += 4;
2065                 mp4ff_read_data(f, p_out,
2066                                 (uint32_t) (ilst_offset - meta_offset - 8));
2067                 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2068                 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2069                 p_out += 4;
2070                 mp4ff_read_data(f, p_out, 4);
2071                 p_out += 4;
2072
2073                 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2074                 p_out += new_ilst_size;
2075
2076                 mp4ff_set_position(f, ilst_offset + ilst_size);
2077                 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2078                         - (ilst_offset - total_base) - ilst_size));
2079
2080                 free(new_ilst_buffer);
2081         }
2082         return 1;
2083 }
2084
2085 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2086 {
2087         int32_t result = 1;
2088
2089         result = f->stream->write(f->stream->user_data, data, size);
2090
2091         f->current_position += size;
2092
2093         return result;
2094 }
2095
2096 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2097 {
2098         uint32_t result;
2099         uint32_t a, b, c, d;
2100         int8_t temp[4];
2101
2102         *(uint32_t *) temp = data;
2103         a = (uint8_t) temp[0];
2104         b = (uint8_t) temp[1];
2105         c = (uint8_t) temp[2];
2106         d = (uint8_t) temp[3];
2107
2108         result = (a << 24) | (b << 16) | (c << 8) | d;
2109
2110         return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2111 }
2112
2113 static int32_t mp4ff_truncate(mp4ff_t * f)
2114 {
2115         return f->stream->truncate(f->stream->user_data);
2116 }
2117
2118 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2119 {
2120         void *new_moov_data;
2121         uint32_t new_moov_size;
2122
2123         mp4ff_t *ff = para_calloc(sizeof(mp4ff_t));
2124         ff->stream = f;
2125         mp4ff_set_position(ff, 0);
2126
2127         parse_atoms(ff, 1);
2128
2129         if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2130                 mp4ff_close(ff);
2131                 return 0;
2132         }
2133
2134         /* copy moov atom to end of the file */
2135         if (ff->last_atom != ATOM_MOOV) {
2136                 char *free_data = "free";
2137
2138                 /* rename old moov to free */
2139                 mp4ff_set_position(ff, ff->moov_offset + 4);
2140                 mp4ff_write_data(ff, free_data, 4);
2141
2142                 mp4ff_set_position(ff, ff->file_size);
2143                 mp4ff_write_int32(ff, new_moov_size + 8);
2144                 mp4ff_write_data(ff, "moov", 4);
2145                 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2146         } else {
2147                 mp4ff_set_position(ff, ff->moov_offset);
2148                 mp4ff_write_int32(ff, new_moov_size + 8);
2149                 mp4ff_write_data(ff, "moov", 4);
2150                 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2151         }
2152
2153         mp4ff_truncate(ff);
2154
2155         mp4ff_close(ff);
2156         return 1;
2157 }
2158
2159 /* find a metadata item by name */
2160 /* returns 0 if item found, 1 if no such item */
2161 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2162                 char **value)
2163 {
2164         uint32_t i;
2165
2166         for (i = 0; i < f->tags.count; i++) {
2167                 if (!stricmp(f->tags.tags[i].item, item)) {
2168                         *value = strdup(f->tags.tags[i].value);
2169                         return 1;
2170                 }
2171         }
2172
2173         *value = NULL;
2174
2175         /* not found */
2176         return 0;
2177 }
2178
2179 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2180 {
2181         return mp4ff_meta_find_by_name(f, "artist", value);
2182 }
2183
2184 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2185 {
2186         return mp4ff_meta_find_by_name(f, "title", value);
2187 }
2188
2189 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2190 {
2191         return mp4ff_meta_find_by_name(f, "date", value);
2192 }
2193
2194 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2195 {
2196         return mp4ff_meta_find_by_name(f, "album", value);
2197 }
2198
2199 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2200 {
2201         return mp4ff_meta_find_by_name(f, "comment", value);
2202 }