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