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