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