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