]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
mp4: Kill pointless macro membuffer_write_data.
[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 static unsigned membuffer_write_atom_name(membuffer * buf, const char *data)
1714 {
1715         return membuffer_write(buf, data, 4) == 4 ? 1 : 0;
1716 }
1717
1718 static unsigned membuffer_write_int16(membuffer * buf, uint16_t data)
1719 {
1720         uint8_t temp[2] = { (uint8_t) (data >> 8), (uint8_t) data };
1721         return membuffer_write(buf, temp, 2);
1722 }
1723
1724 static unsigned membuffer_write_int32(membuffer * buf, uint32_t data)
1725 {
1726         uint8_t temp[4] = { (uint8_t) (data >> 24), (uint8_t) (data >> 16),
1727                 (uint8_t) (data >> 8), (uint8_t) data };
1728         return membuffer_write(buf, temp, 4);
1729 }
1730
1731 static void membuffer_write_track_tag(membuffer * buf, const char *name,
1732                 uint32_t index, uint32_t total)
1733 {
1734         membuffer_write_int32(buf,
1735                 8 /*atom header */  + 8 /*data atom header */  +
1736                 8 /*flags + reserved */  + 8 /*actual data */ );
1737         membuffer_write_atom_name(buf, name);
1738         membuffer_write_int32(buf,
1739                 8 /*data atom header */  +
1740                 8 /*flags + reserved */  + 8 /*actual data */ );
1741         membuffer_write_atom_name(buf, "data");
1742         membuffer_write_int32(buf, 0);  //flags
1743         membuffer_write_int32(buf, 0);  //reserved
1744         membuffer_write_int16(buf, 0);
1745         membuffer_write_int16(buf, (uint16_t) index);   //track number
1746         membuffer_write_int16(buf, (uint16_t) total);   //total tracks
1747         membuffer_write_int16(buf, 0);
1748 }
1749
1750 static void membuffer_write_int16_tag(membuffer * buf, const char *name,
1751                 uint16_t value)
1752 {
1753         membuffer_write_int32(buf,
1754                 8 /*atom header */  + 8 /*data atom header */  +
1755                 8 /*flags + reserved */  + 2 /*actual data */ );
1756         membuffer_write_atom_name(buf, name);
1757         membuffer_write_int32(buf,
1758                 8 /*data atom header */  +
1759                 8 /*flags + reserved */  + 2 /*actual data */ );
1760         membuffer_write_atom_name(buf, "data");
1761         membuffer_write_int32(buf, 0);  //flags
1762         membuffer_write_int32(buf, 0);  //reserved
1763         membuffer_write_int16(buf, value);      //value
1764 }
1765
1766 static uint32_t myatoi(const char *param)
1767 {
1768         return param ? atoi(param) : 0;
1769 }
1770
1771 static uint32_t mp4ff_meta_genre_to_index(const char *genrestr)
1772 {
1773         unsigned n;
1774         for (n = 0; n < sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0]); n++) {
1775                 if (!stricmp(genrestr, ID3v1GenreList[n]))
1776                         return n + 1;
1777         }
1778         return 0;
1779 }
1780
1781 typedef struct {
1782         const char *atom;
1783         const char *name;
1784 } stdmeta_entry;
1785
1786 static stdmeta_entry stdmetas[] = {
1787         {"\xA9" "nam", "title"},
1788         {"\xA9" "ART", "artist"},
1789         {"\xA9" "wrt", "writer"},
1790         {"\xA9" "alb", "album"},
1791         {"\xA9" "day", "date"},
1792         {"\xA9" "too", "tool"},
1793         {"\xA9" "cmt", "comment"},
1794         {"cpil", "compilation"},
1795         {"covr", "cover"},
1796         {"aART", "album_artist"},
1797 };
1798
1799 static const char *find_standard_meta(const char *name) //returns atom name if found, 0 if not
1800 {
1801         unsigned n;
1802         for (n = 0; n < sizeof (stdmetas) / sizeof (stdmetas[0]); n++) {
1803                 if (!stricmp(name, stdmetas[n].name))
1804                         return stdmetas[n].atom;
1805         }
1806         return 0;
1807 }
1808
1809 static void membuffer_write_std_tag(membuffer * buf, const char *name,
1810                 const char *value)
1811 {
1812         uint32_t flags = 1;
1813
1814         /* special check for compilation flag */
1815         if (strcmp(name, "cpil") == 0) {
1816                 flags = 21;
1817         }
1818
1819         membuffer_write_int32(buf,
1820                 8 /*atom header */  + 8 /*data atom header */  +
1821                 8 /*flags + reserved */  + strlen(value));
1822         membuffer_write_atom_name(buf, name);
1823         membuffer_write_int32(buf,
1824                 8 /*data atom header */  +
1825                 8 /*flags + reserved */  + strlen(value));
1826         membuffer_write_atom_name(buf, "data");
1827         membuffer_write_int32(buf, flags);      //flags
1828         membuffer_write_int32(buf, 0);  //reserved
1829         membuffer_write(buf, value, strlen(value));
1830 }
1831
1832 static void membuffer_write_custom_tag(membuffer * buf, const char *name,
1833                 const char *value)
1834 {
1835         membuffer_write_int32(buf,
1836                 8 /*atom header */  +
1837                 0x1C /*weirdo itunes atom */  +
1838                 12 /*name atom header */  + strlen(name) +
1839                 16 /*data atom header + flags */  + strlen(value));
1840         membuffer_write_atom_name(buf, "----");
1841         membuffer_write_int32(buf, 0x1C);       //weirdo itunes atom
1842         membuffer_write_atom_name(buf, "mean");
1843         membuffer_write_int32(buf, 0);
1844         membuffer_write(buf, "com.apple.iTunes", 16);
1845         membuffer_write_int32(buf, 12 + strlen(name));
1846         membuffer_write_atom_name(buf, "name");
1847         membuffer_write_int32(buf, 0);
1848         membuffer_write(buf, name, strlen(name));
1849         membuffer_write_int32(buf,
1850                 8 /*data atom header */  +
1851                 8 /*flags + reserved */  + strlen(value));
1852         membuffer_write_atom_name(buf, "data");
1853         membuffer_write_int32(buf, 1);  //flags
1854         membuffer_write_int32(buf, 0);  //reserved
1855         membuffer_write(buf, value, strlen(value));
1856 }
1857
1858 static unsigned membuffer_error(const membuffer * buf)
1859 {
1860         return buf->error;
1861 }
1862
1863 static void membuffer_free(membuffer * buf)
1864 {
1865         if (buf->data)
1866                 free(buf->data);
1867         free(buf);
1868 }
1869
1870 static unsigned membuffer_get_size(const membuffer * buf)
1871 {
1872         return buf->written;
1873 }
1874
1875 static void *membuffer_detach(membuffer * buf)
1876 {
1877         void *ret;
1878
1879         if (buf->error)
1880                 return 0;
1881
1882         ret = realloc(buf->data, buf->written);
1883
1884         if (ret == 0)
1885                 free(buf->data);
1886
1887         buf->data = 0;
1888         buf->error = 1;
1889
1890         return ret;
1891 }
1892
1893 static uint32_t create_ilst(const mp4ff_metadata_t * data, void **out_buffer,
1894                 uint32_t * out_size)
1895 {
1896         membuffer *buf = membuffer_create();
1897         unsigned metaptr;
1898         char *mask = (char *) malloc(data->count);
1899         memset(mask, 0, data->count);
1900
1901         {
1902                 const char *tracknumber_ptr = 0, *totaltracks_ptr = 0;
1903                 const char *discnumber_ptr = 0, *totaldiscs_ptr = 0;
1904                 const char *genre_ptr = 0, *tempo_ptr = 0;
1905                 for (metaptr = 0; metaptr < data->count; metaptr++) {
1906                         mp4ff_tag_t *tag = &data->tags[metaptr];
1907                         if (!stricmp(tag->item, "tracknumber") || !stricmp(tag->item, "track")) {
1908                                 if (tracknumber_ptr == 0)
1909                                         tracknumber_ptr = tag->value;
1910                                 mask[metaptr] = 1;
1911                         } else if (!stricmp(tag->item, "totaltracks")) {
1912                                 if (totaltracks_ptr == 0)
1913                                         totaltracks_ptr = tag->value;
1914                                 mask[metaptr] = 1;
1915                         } else if (!stricmp(tag->item, "discnumber")
1916                                         || !stricmp(tag->item, "disc")) {
1917                                 if (discnumber_ptr == 0)
1918                                         discnumber_ptr = tag->value;
1919                                 mask[metaptr] = 1;
1920                         } else if (!stricmp(tag->item, "totaldiscs")) {
1921                                 if (totaldiscs_ptr == 0)
1922                                         totaldiscs_ptr = tag->value;
1923                                 mask[metaptr] = 1;
1924                         } else if (!stricmp(tag->item, "genre")) {
1925                                 if (genre_ptr == 0)
1926                                         genre_ptr = tag->value;
1927                                 mask[metaptr] = 1;
1928                         } else if (!stricmp(tag->item, "tempo")) {
1929                                 if (tempo_ptr == 0)
1930                                         tempo_ptr = tag->value;
1931                                 mask[metaptr] = 1;
1932                         }
1933
1934                 }
1935
1936                 if (tracknumber_ptr)
1937                         membuffer_write_track_tag(buf, "trkn",
1938                                                   myatoi(tracknumber_ptr),
1939                                                   myatoi(totaltracks_ptr));
1940                 if (discnumber_ptr)
1941                         membuffer_write_track_tag(buf, "disk",
1942                                                   myatoi(discnumber_ptr),
1943                                                   myatoi(totaldiscs_ptr));
1944                 if (tempo_ptr)
1945                         membuffer_write_int16_tag(buf, "tmpo",
1946                                                   (uint16_t) myatoi(tempo_ptr));
1947
1948                 if (genre_ptr) {
1949                         uint32_t index = mp4ff_meta_genre_to_index(genre_ptr);
1950                         if (index == 0)
1951                                 membuffer_write_std_tag(buf, "©gen",
1952                                                         genre_ptr);
1953                         else
1954                                 membuffer_write_int16_tag(buf, "gnre",
1955                                                           (uint16_t) index);
1956                 }
1957         }
1958
1959         for (metaptr = 0; metaptr < data->count; metaptr++) {
1960                 if (!mask[metaptr]) {
1961                         mp4ff_tag_t *tag = &data->tags[metaptr];
1962                         const char *std_meta_atom = find_standard_meta(tag->item);
1963                         if (std_meta_atom) {
1964                                 membuffer_write_std_tag(buf, std_meta_atom,
1965                                                         tag->value);
1966                         } else {
1967                                 membuffer_write_custom_tag(buf, tag->item,
1968                                         tag->value);
1969                         }
1970                 }
1971         }
1972
1973         free(mask);
1974
1975         if (membuffer_error(buf)) {
1976                 membuffer_free(buf);
1977                 return 0;
1978         }
1979
1980         *out_size = membuffer_get_size(buf);
1981         *out_buffer = membuffer_detach(buf);
1982         membuffer_free(buf);
1983
1984         return 1;
1985 }
1986
1987 static void membuffer_write_atom(membuffer * buf, const char *name, unsigned size,
1988                           const void *data)
1989 {
1990         membuffer_write_int32(buf, size + 8);
1991         membuffer_write_atom_name(buf, name);
1992         membuffer_write(buf, data, size);
1993 }
1994
1995 static void *membuffer_get_ptr(const membuffer * buf)
1996 {
1997         return buf->data;
1998 }
1999
2000 static void membuffer_set_error(membuffer * buf)
2001 {
2002         buf->error = 1;
2003 }
2004
2005 static unsigned membuffer_transfer_from_file(membuffer * buf, mp4ff_t * src,
2006                 unsigned bytes)
2007 {
2008         unsigned oldsize;
2009         void *bufptr;
2010
2011         oldsize = membuffer_get_size(buf);
2012         if (membuffer_write(buf, 0, bytes) != bytes)
2013                 return 0;
2014
2015         bufptr = membuffer_get_ptr(buf);
2016         if (bufptr == 0)
2017                 return 0;
2018
2019         if ((unsigned) mp4ff_read_data(src, (char *) bufptr + oldsize, bytes) !=
2020                 bytes) {
2021                 membuffer_set_error(buf);
2022                 return 0;
2023         }
2024
2025         return bytes;
2026 }
2027
2028 static uint32_t create_meta(const mp4ff_metadata_t * data, void **out_buffer,
2029                 uint32_t * out_size)
2030 {
2031         membuffer *buf;
2032         uint32_t ilst_size;
2033         void *ilst_buffer;
2034
2035         if (!create_ilst(data, &ilst_buffer, &ilst_size))
2036                 return 0;
2037
2038         buf = membuffer_create();
2039
2040         membuffer_write_int32(buf, 0);
2041         membuffer_write_atom(buf, "ilst", ilst_size, ilst_buffer);
2042         free(ilst_buffer);
2043
2044         *out_size = membuffer_get_size(buf);
2045         *out_buffer = membuffer_detach(buf);
2046         membuffer_free(buf);
2047         return 1;
2048 }
2049
2050 static uint32_t create_udta(const mp4ff_metadata_t * data, void **out_buffer,
2051 uint32_t * out_size)
2052 {
2053         membuffer *buf;
2054         uint32_t meta_size;
2055         void *meta_buffer;
2056
2057         if (!create_meta(data, &meta_buffer, &meta_size))
2058                 return 0;
2059
2060         buf = membuffer_create();
2061
2062         membuffer_write_atom(buf, "meta", meta_size, meta_buffer);
2063
2064         free(meta_buffer);
2065
2066         *out_size = membuffer_get_size(buf);
2067         *out_buffer = membuffer_detach(buf);
2068         membuffer_free(buf);
2069         return 1;
2070 }
2071
2072 static uint32_t fix_byte_order_32(uint32_t src)
2073 {
2074         uint32_t result;
2075         uint32_t a, b, c, d;
2076         int8_t data[4];
2077
2078         memcpy(data, &src, sizeof (src));
2079         a = (uint8_t) data[0];
2080         b = (uint8_t) data[1];
2081         c = (uint8_t) data[2];
2082         d = (uint8_t) data[3];
2083
2084         result = (a << 24) | (b << 16) | (c << 8) | d;
2085         return (uint32_t) result;
2086 }
2087
2088 static uint32_t modify_moov(mp4ff_t * f, const mp4ff_metadata_t * data,
2089                 void **out_buffer, uint32_t * out_size)
2090 {
2091         uint64_t total_base = f->moov_offset + 8;
2092         uint32_t total_size = (uint32_t) (f->moov_size - 8);
2093
2094         uint64_t udta_offset, meta_offset, ilst_offset;
2095         uint32_t udta_size, meta_size, ilst_size;
2096
2097         uint32_t new_ilst_size;
2098         void *new_ilst_buffer;
2099
2100         uint8_t *p_out;
2101         int32_t size_delta;
2102
2103         if (!find_atom_v2(f, total_base, total_size, "udta", 0, "meta")) {
2104                 membuffer *buf;
2105                 void *new_udta_buffer;
2106                 uint32_t new_udta_size;
2107                 if (!create_udta(data, &new_udta_buffer, &new_udta_size))
2108                         return 0;
2109
2110                 buf = membuffer_create();
2111                 mp4ff_set_position(f, total_base);
2112                 membuffer_transfer_from_file(buf, f, total_size);
2113
2114                 membuffer_write_atom(buf, "udta", new_udta_size,
2115                         new_udta_buffer);
2116
2117                 free(new_udta_buffer);
2118
2119                 *out_size = membuffer_get_size(buf);
2120                 *out_buffer = membuffer_detach(buf);
2121                 membuffer_free(buf);
2122                 return 1;
2123         } else {
2124                 udta_offset = mp4ff_position(f);
2125                 udta_size = mp4ff_read_int32(f);
2126                 if (!find_atom_v2 (f, udta_offset + 8, udta_size - 8, "meta", 4, "ilst")) {
2127                         membuffer *buf;
2128                         void *new_meta_buffer;
2129                         uint32_t new_meta_size;
2130                         if (!create_meta(data, &new_meta_buffer, &new_meta_size))
2131                                 return 0;
2132
2133                         buf = membuffer_create();
2134                         mp4ff_set_position(f, total_base);
2135                         membuffer_transfer_from_file(buf, f,
2136                                 (uint32_t)(udta_offset - total_base));
2137
2138                         membuffer_write_int32(buf, udta_size + 8 + new_meta_size);
2139                         membuffer_write_atom_name(buf, "udta");
2140                         membuffer_transfer_from_file(buf, f, udta_size);
2141
2142                         membuffer_write_atom(buf, "meta", new_meta_size,
2143                                 new_meta_buffer);
2144                         free(new_meta_buffer);
2145
2146                         *out_size = membuffer_get_size(buf);
2147                         *out_buffer = membuffer_detach(buf);
2148                         membuffer_free(buf);
2149                         return 1;
2150                 }
2151                 meta_offset = mp4ff_position(f);
2152                 meta_size = mp4ff_read_int32(f);
2153                 if (!find_atom(f, meta_offset + 12, meta_size - 12, "ilst"))
2154                         return 0;       //shouldn't happen, find_atom_v2 above takes care of it
2155                 ilst_offset = mp4ff_position(f);
2156                 ilst_size = mp4ff_read_int32(f);
2157
2158                 if (!create_ilst(data, &new_ilst_buffer, &new_ilst_size))
2159                         return 0;
2160
2161                 size_delta = new_ilst_size - (ilst_size - 8);
2162
2163                 *out_size = total_size + size_delta;
2164                 *out_buffer = malloc(*out_size);
2165                 if (*out_buffer == 0) {
2166                         free(new_ilst_buffer);
2167                         return 0;
2168                 }
2169
2170                 p_out = (uint8_t *) * out_buffer;
2171
2172                 mp4ff_set_position(f, total_base);
2173                 mp4ff_read_data(f, p_out,
2174                                 (uint32_t) (udta_offset - total_base));
2175                 p_out += (uint32_t) (udta_offset - total_base);
2176                 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2177                 p_out += 4;
2178                 mp4ff_read_data(f, p_out, 4);
2179                 p_out += 4;
2180                 mp4ff_read_data(f, p_out,
2181                                 (uint32_t) (meta_offset - udta_offset - 8));
2182                 p_out += (uint32_t) (meta_offset - udta_offset - 8);
2183                 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2184                 p_out += 4;
2185                 mp4ff_read_data(f, p_out, 4);
2186                 p_out += 4;
2187                 mp4ff_read_data(f, p_out,
2188                                 (uint32_t) (ilst_offset - meta_offset - 8));
2189                 p_out += (uint32_t) (ilst_offset - meta_offset - 8);
2190                 *(uint32_t *) p_out = fix_byte_order_32(mp4ff_read_int32(f) + size_delta);
2191                 p_out += 4;
2192                 mp4ff_read_data(f, p_out, 4);
2193                 p_out += 4;
2194
2195                 memcpy(p_out, new_ilst_buffer, new_ilst_size);
2196                 p_out += new_ilst_size;
2197
2198                 mp4ff_set_position(f, ilst_offset + ilst_size);
2199                 mp4ff_read_data(f, p_out, (uint32_t) (total_size
2200                         - (ilst_offset - total_base) - ilst_size));
2201
2202                 free(new_ilst_buffer);
2203         }
2204         return 1;
2205 }
2206
2207 static int32_t mp4ff_write_data(mp4ff_t * f, void *data, uint32_t size)
2208 {
2209         int32_t result = 1;
2210
2211         result = f->stream->write(f->stream->user_data, data, size);
2212
2213         f->current_position += size;
2214
2215         return result;
2216 }
2217
2218 static int32_t mp4ff_write_int32(mp4ff_t * f, const uint32_t data)
2219 {
2220         uint32_t result;
2221         uint32_t a, b, c, d;
2222         int8_t temp[4];
2223
2224         *(uint32_t *) temp = data;
2225         a = (uint8_t) temp[0];
2226         b = (uint8_t) temp[1];
2227         c = (uint8_t) temp[2];
2228         d = (uint8_t) temp[3];
2229
2230         result = (a << 24) | (b << 16) | (c << 8) | d;
2231
2232         return mp4ff_write_data(f, (uint8_t *) & result, sizeof (result));
2233 }
2234
2235 static int32_t mp4ff_truncate(mp4ff_t * f)
2236 {
2237         return f->stream->truncate(f->stream->user_data);
2238 }
2239
2240 int32_t mp4ff_meta_update(mp4ff_callback_t * f, const mp4ff_metadata_t * data)
2241 {
2242         void *new_moov_data;
2243         uint32_t new_moov_size;
2244
2245         mp4ff_t *ff = malloc(sizeof (mp4ff_t));
2246
2247         memset(ff, 0, sizeof (mp4ff_t));
2248         ff->stream = f;
2249         mp4ff_set_position(ff, 0);
2250
2251         parse_atoms(ff, 1);
2252
2253         if (!modify_moov(ff, data, &new_moov_data, &new_moov_size)) {
2254                 mp4ff_close(ff);
2255                 return 0;
2256         }
2257
2258         /* copy moov atom to end of the file */
2259         if (ff->last_atom != ATOM_MOOV) {
2260                 char *free_data = "free";
2261
2262                 /* rename old moov to free */
2263                 mp4ff_set_position(ff, ff->moov_offset + 4);
2264                 mp4ff_write_data(ff, free_data, 4);
2265
2266                 mp4ff_set_position(ff, ff->file_size);
2267                 mp4ff_write_int32(ff, new_moov_size + 8);
2268                 mp4ff_write_data(ff, "moov", 4);
2269                 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2270         } else {
2271                 mp4ff_set_position(ff, ff->moov_offset);
2272                 mp4ff_write_int32(ff, new_moov_size + 8);
2273                 mp4ff_write_data(ff, "moov", 4);
2274                 mp4ff_write_data(ff, new_moov_data, new_moov_size);
2275         }
2276
2277         mp4ff_truncate(ff);
2278
2279         mp4ff_close(ff);
2280         return 1;
2281 }
2282
2283 /* find a metadata item by name */
2284 /* returns 0 if item found, 1 if no such item */
2285 static int32_t mp4ff_meta_find_by_name(const mp4ff_t * f, const char *item,
2286                 char **value)
2287 {
2288         uint32_t i;
2289
2290         for (i = 0; i < f->tags.count; i++) {
2291                 if (!stricmp(f->tags.tags[i].item, item)) {
2292                         *value = strdup(f->tags.tags[i].value);
2293                         return 1;
2294                 }
2295         }
2296
2297         *value = NULL;
2298
2299         /* not found */
2300         return 0;
2301 }
2302
2303 int32_t mp4ff_meta_get_artist(const mp4ff_t * f, char **value)
2304 {
2305         return mp4ff_meta_find_by_name(f, "artist", value);
2306 }
2307
2308 int32_t mp4ff_meta_get_title(const mp4ff_t * f, char **value)
2309 {
2310         return mp4ff_meta_find_by_name(f, "title", value);
2311 }
2312
2313 int32_t mp4ff_meta_get_date(const mp4ff_t * f, char **value)
2314 {
2315         return mp4ff_meta_find_by_name(f, "date", value);
2316 }
2317
2318 int32_t mp4ff_meta_get_album(const mp4ff_t * f, char **value)
2319 {
2320         return mp4ff_meta_find_by_name(f, "album", value);
2321 }
2322
2323 int32_t mp4ff_meta_get_comment(const mp4ff_t * f, char **value)
2324 {
2325         return mp4ff_meta_find_by_name(f, "comment", value);
2326 }