]> git.tuebingen.mpg.de Git - paraslash.git/blob - mp4.c
mp4: Use read/write functions from portable_io.h.
[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 #define TRACK_AUDIO 1
55 #define TRACK_VIDEO   2
56 #define TRACK_SYSTEM  3
57 #define TRACK_UNKNOWN 0
58
59 /* atoms with subatoms */
60 #define ATOM_MOOV 1
61 #define ATOM_TRAK 2
62 #define ATOM_EDTS 3
63 #define ATOM_MDIA 4
64 #define ATOM_MINF 5
65 #define ATOM_STBL 6
66 #define ATOM_UDTA 7
67 #define ATOM_ILST 8             /* iTunes Metadata list */
68 #define ATOM_TITLE 9
69 #define ATOM_ARTIST 10
70 #define ATOM_WRITER 11
71 #define ATOM_ALBUM 12
72 #define ATOM_DATE 13
73 #define ATOM_TOOL 14
74 #define ATOM_COMMENT 15
75 #define ATOM_GENRE1 16
76 #define ATOM_TRACK 17
77 #define ATOM_DISC 18
78 #define ATOM_COMPILATION 19
79 #define ATOM_GENRE2 20
80 #define ATOM_TEMPO 21
81 #define ATOM_COVER 22
82 #define ATOM_DRMS 23
83 #define ATOM_SINF 24
84 #define ATOM_SCHI 25
85
86 #define SUBATOMIC 128
87
88 /* atoms without subatoms */
89 #define ATOM_FTYP 129
90 #define ATOM_MDAT 130
91 #define ATOM_MVHD 131
92 #define ATOM_TKHD 132
93 #define ATOM_TREF 133
94 #define ATOM_MDHD 134
95 #define ATOM_VMHD 135
96 #define ATOM_SMHD 136
97 #define ATOM_HMHD 137
98 #define ATOM_STSD 138
99 #define ATOM_STTS 139
100 #define ATOM_STSZ 140
101 #define ATOM_STZ2 141
102 #define ATOM_STCO 142
103 #define ATOM_STSC 143
104 #define ATOM_MP4A 144
105 #define ATOM_MP4V 145
106 #define ATOM_MP4S 146
107 #define ATOM_ESDS 147
108 #define ATOM_META 148           /* iTunes Metadata box */
109 #define ATOM_NAME 149           /* iTunes Metadata name box */
110 #define ATOM_DATA 150           /* iTunes Metadata data box */
111 #define ATOM_CTTS 151
112 #define ATOM_FRMA 152
113 #define ATOM_IVIV 153
114 #define ATOM_PRIV 154
115 #define ATOM_USER 155
116 #define ATOM_KEY  156
117 #define ATOM_ALBUM_ARTIST       157
118 #define ATOM_CONTENTGROUP   158
119 #define ATOM_LYRICS         159
120 #define ATOM_DESCRIPTION    160
121 #define ATOM_NETWORK        161
122 #define ATOM_SHOW           162
123 #define ATOM_EPISODENAME    163
124 #define ATOM_SORTTITLE      164
125 #define ATOM_SORTALBUM      165
126 #define ATOM_SORTARTIST     166
127 #define ATOM_SORTALBUMARTIST    167
128 #define ATOM_SORTWRITER     168
129 #define ATOM_SORTSHOW       169
130 #define ATOM_SEASON         170
131 #define ATOM_EPISODE        171
132 #define ATOM_PODCAST        172
133
134 #define ATOM_UNKNOWN 255
135 #define ATOM_FREE ATOM_UNKNOWN
136 #define ATOM_SKIP ATOM_UNKNOWN
137
138 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
139
140 static uint8_t atom_name_to_type(const int8_t a, const int8_t b,
141                 const int8_t c, const int8_t d)
142 {
143         if (a == 'm') {
144                 if (atom_compare(a, b, c, d, 'm', 'o', 'o', 'v'))
145                         return ATOM_MOOV;
146                 else if (atom_compare(a, b, c, d, 'm', 'i', 'n', 'f'))
147                         return ATOM_MINF;
148                 else if (atom_compare(a, b, c, d, 'm', 'd', 'i', 'a'))
149                         return ATOM_MDIA;
150                 else if (atom_compare(a, b, c, d, 'm', 'd', 'a', 't'))
151                         return ATOM_MDAT;
152                 else if (atom_compare(a, b, c, d, 'm', 'd', 'h', 'd'))
153                         return ATOM_MDHD;
154                 else if (atom_compare(a, b, c, d, 'm', 'v', 'h', 'd'))
155                         return ATOM_MVHD;
156                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'a'))
157                         return ATOM_MP4A;
158                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 'v'))
159                         return ATOM_MP4V;
160                 else if (atom_compare(a, b, c, d, 'm', 'p', '4', 's'))
161                         return ATOM_MP4S;
162                 else if (atom_compare(a, b, c, d, 'm', 'e', 't', 'a'))
163                         return ATOM_META;
164         } else if (a == 't') {
165                 if (atom_compare(a, b, c, d, 't', 'r', 'a', 'k'))
166                         return ATOM_TRAK;
167                 else if (atom_compare(a, b, c, d, 't', 'k', 'h', 'd'))
168                         return ATOM_TKHD;
169                 else if (atom_compare(a, b, c, d, 't', 'r', 'e', 'f'))
170                         return ATOM_TREF;
171                 else if (atom_compare(a, b, c, d, 't', 'r', 'k', 'n'))
172                         return ATOM_TRACK;
173                 else if (atom_compare(a, b, c, d, 't', 'm', 'p', 'o'))
174                         return ATOM_TEMPO;
175                 else if (atom_compare(a, b, c, d, 't', 'v', 'n', 'n'))
176                         return ATOM_NETWORK;
177                 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'h'))
178                         return ATOM_SHOW;
179                 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 'n'))
180                         return ATOM_EPISODENAME;
181                 else if (atom_compare(a, b, c, d, 't', 'v', 's', 'n'))
182                         return ATOM_SEASON;
183                 else if (atom_compare(a, b, c, d, 't', 'v', 'e', 's'))
184                         return ATOM_EPISODE;
185         } else if (a == 's') {
186                 if (atom_compare(a, b, c, d, 's', 't', 'b', 'l'))
187                         return ATOM_STBL;
188                 else if (atom_compare(a, b, c, d, 's', 'm', 'h', 'd'))
189                         return ATOM_SMHD;
190                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'd'))
191                         return ATOM_STSD;
192                 else if (atom_compare(a, b, c, d, 's', 't', 't', 's'))
193                         return ATOM_STTS;
194                 else if (atom_compare(a, b, c, d, 's', 't', 'c', 'o'))
195                         return ATOM_STCO;
196                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'c'))
197                         return ATOM_STSC;
198                 else if (atom_compare(a, b, c, d, 's', 't', 's', 'z'))
199                         return ATOM_STSZ;
200                 else if (atom_compare(a, b, c, d, 's', 't', 'z', '2'))
201                         return ATOM_STZ2;
202                 else if (atom_compare(a, b, c, d, 's', 'k', 'i', 'p'))
203                         return ATOM_SKIP;
204                 else if (atom_compare(a, b, c, d, 's', 'i', 'n', 'f'))
205                         return ATOM_SINF;
206                 else if (atom_compare(a, b, c, d, 's', 'c', 'h', 'i'))
207                         return ATOM_SCHI;
208                 else if (atom_compare(a, b, c, d, 's', 'o', 'n', 'm'))
209                         return ATOM_SORTTITLE;
210                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'l'))
211                         return ATOM_SORTALBUM;
212                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'r'))
213                         return ATOM_SORTARTIST;
214                 else if (atom_compare(a, b, c, d, 's', 'o', 'a', 'a'))
215                         return ATOM_SORTALBUMARTIST;
216                 else if (atom_compare(a, b, c, d, 's', 'o', 'c', 'o'))
217                         return ATOM_SORTWRITER;
218                 else if (atom_compare(a, b, c, d, 's', 'o', 's', 'n'))
219                         return ATOM_SORTSHOW;
220         } else if (a == COPYRIGHT_SYMBOL) {
221                 if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'n', 'a', 'm'))
222                         return ATOM_TITLE;
223                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'A', 'R', 'T'))
224                         return ATOM_ARTIST;
225                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'w', 'r', 't'))
226                         return ATOM_WRITER;
227                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'a', 'l', 'b'))
228                         return ATOM_ALBUM;
229                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'd', 'a', 'y'))
230                         return ATOM_DATE;
231                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 't', 'o', 'o'))
232                         return ATOM_TOOL;
233                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'c', 'm', 't'))
234                         return ATOM_COMMENT;
235                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'e', 'n'))
236                         return ATOM_GENRE1;
237                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'g', 'r', 'p'))
238                         return ATOM_CONTENTGROUP;
239                 else if (atom_compare(a, b, c, d, COPYRIGHT_SYMBOL, 'l', 'y', 'r'))
240                         return ATOM_LYRICS;
241         }
242
243         if (atom_compare(a, b, c, d, 'e', 'd', 't', 's'))
244                 return ATOM_EDTS;
245         else if (atom_compare(a, b, c, d, 'e', 's', 'd', 's'))
246                 return ATOM_ESDS;
247         else if (atom_compare(a, b, c, d, 'f', 't', 'y', 'p'))
248                 return ATOM_FTYP;
249         else if (atom_compare(a, b, c, d, 'f', 'r', 'e', 'e'))
250                 return ATOM_FREE;
251         else if (atom_compare(a, b, c, d, 'h', 'm', 'h', 'd'))
252                 return ATOM_HMHD;
253         else if (atom_compare(a, b, c, d, 'v', 'm', 'h', 'd'))
254                 return ATOM_VMHD;
255         else if (atom_compare(a, b, c, d, 'u', 'd', 't', 'a'))
256                 return ATOM_UDTA;
257         else if (atom_compare(a, b, c, d, 'i', 'l', 's', 't'))
258                 return ATOM_ILST;
259         else if (atom_compare(a, b, c, d, 'n', 'a', 'm', 'e'))
260                 return ATOM_NAME;
261         else if (atom_compare(a, b, c, d, 'd', 'a', 't', 'a'))
262                 return ATOM_DATA;
263         else if (atom_compare(a, b, c, d, 'd', 'i', 's', 'k'))
264                 return ATOM_DISC;
265         else if (atom_compare(a, b, c, d, 'g', 'n', 'r', 'e'))
266                 return ATOM_GENRE2;
267         else if (atom_compare(a, b, c, d, 'c', 'o', 'v', 'r'))
268                 return ATOM_COVER;
269         else if (atom_compare(a, b, c, d, 'c', 'p', 'i', 'l'))
270                 return ATOM_COMPILATION;
271         else if (atom_compare(a, b, c, d, 'c', 't', 't', 's'))
272                 return ATOM_CTTS;
273         else if (atom_compare(a, b, c, d, 'd', 'r', 'm', 's'))
274                 return ATOM_DRMS;
275         else if (atom_compare(a, b, c, d, 'f', 'r', 'm', 'a'))
276                 return ATOM_FRMA;
277         else if (atom_compare(a, b, c, d, 'p', 'r', 'i', 'v'))
278                 return ATOM_PRIV;
279         else if (atom_compare(a, b, c, d, 'i', 'v', 'i', 'v'))
280                 return ATOM_IVIV;
281         else if (atom_compare(a, b, c, d, 'u', 's', 'e', 'r'))
282                 return ATOM_USER;
283         else if (atom_compare(a, b, c, d, 'k', 'e', 'y', ' '))
284                 return ATOM_KEY;
285         else if (atom_compare(a, b, c, d, 'a', 'A', 'R', 'T'))
286                 return ATOM_ALBUM_ARTIST;
287         else if (atom_compare(a, b, c, d, 'd', 'e', 's', 'c'))
288                 return ATOM_DESCRIPTION;
289         else if (atom_compare(a, b, c, d, 'p', 'c', 's', 't'))
290                 return ATOM_PODCAST;
291         else
292                 return ATOM_UNKNOWN;
293 }
294
295 /* read atom header, return atom size, atom size is with header included */
296 static uint64_t atom_read_header(mp4ff_t * f, uint8_t * atom_type,
297                                 uint8_t * header_size)
298 {
299         uint64_t size;
300         int32_t ret;
301         int8_t atom_header[8];
302
303         ret = read_data(f, atom_header, 8);
304         if (ret != 8)
305                 return 0;
306
307         size = read_u32_be(atom_header);
308         *header_size = 8;
309
310         /* check for 64 bit atom size */
311         if (size == 1) {
312                 *header_size = 16;
313                 size = read_int64(f);
314         }
315         *atom_type = atom_name_to_type(atom_header[4], atom_header[5],
316                 atom_header[6], atom_header[7]);
317         return size;
318 }
319
320 static int64_t get_position(const mp4ff_t * f)
321 {
322         return f->current_position;
323 }
324
325 static int need_parse_when_meta_only(uint8_t atom_type)
326 {
327         switch (atom_type) {
328         case ATOM_EDTS:
329         case ATOM_DRMS:
330         case ATOM_SINF:
331         case ATOM_SCHI:
332         case ATOM_STTS:
333         case ATOM_STSZ:
334         case ATOM_STZ2:
335         case ATOM_STCO:
336         case ATOM_STSC:
337         case ATOM_FRMA:
338         case ATOM_IVIV:
339         case ATOM_PRIV:
340                 return 0;
341         default:
342                 return 1;
343         }
344 }
345
346 static int32_t set_position(mp4ff_t * f, const int64_t position)
347 {
348         f->stream->seek(f->stream->user_data, position);
349         f->current_position = position;
350
351         return 0;
352 }
353
354 static void track_add(mp4ff_t * f)
355 {
356         f->total_tracks++;
357
358         if (f->total_tracks > MAX_TRACKS) {
359                 f->total_tracks = 0;
360                 f->error++;
361                 return;
362         }
363         f->track[f->total_tracks - 1] = para_calloc(sizeof (mp4ff_track_t));
364 }
365
366 static uint8_t read_char(mp4ff_t * f)
367 {
368         uint8_t output;
369         read_data(f, &output, 1);
370         return output;
371 }
372
373 static uint32_t read_int24(mp4ff_t * f)
374 {
375         int8_t data[4];
376
377         read_data(f, data, 3);
378         return read_u24_be(data);
379 }
380
381 static uint32_t read_int32(mp4ff_t * f)
382 {
383         int8_t data[4];
384
385         read_data(f, data, 4);
386         return read_u32_be(data);
387 }
388
389 static int32_t read_stsz(mp4ff_t * f)
390 {
391         int32_t i;
392         mp4ff_track_t *t;
393
394         if (f->total_tracks == 0)
395                 return f->error++;
396         t = f->track[f->total_tracks - 1];
397         read_char(f);   /* version */
398         read_int24(f);  /* flags */
399         t->stsz_sample_size = read_int32(f);
400         t->stsz_sample_count = read_int32(f);
401         if (t->stsz_sample_size != 0)
402                 return 0;
403         t->stsz_table = para_malloc(t->stsz_sample_count * sizeof(int32_t));
404         for (i = 0; i < t->stsz_sample_count && !f->stream->read_error; i++)
405                 t->stsz_table[i] = read_int32(f);
406         return 0;
407 }
408
409 static int32_t read_stts(mp4ff_t * f)
410 {
411         int32_t i;
412         mp4ff_track_t *t;
413
414         /* CVE-2017-9223 */
415         if (f->total_tracks == 0)
416                 return f->error++;
417         t = f->track[f->total_tracks - 1];
418         if (t->stts_entry_count)
419                 return 0;
420         read_char(f);   /* version */
421         read_int24(f);  /* flags */
422         t->stts_entry_count = read_int32(f);
423
424         t->stts_sample_count = para_malloc(t->stts_entry_count
425                 * sizeof(int32_t));
426         t->stts_sample_delta = para_malloc(t->stts_entry_count
427                 * sizeof (int32_t));
428         /* CVE-2017-9254 */
429         for (i = 0; i < t->stts_entry_count && !f->stream->read_error; i++) {
430                 t->stts_sample_count[i] = read_int32(f);
431                 t->stts_sample_delta[i] = read_int32(f);
432         }
433         return 1;
434 }
435
436 static int32_t read_ctts(mp4ff_t * f)
437 {
438         int32_t i;
439         mp4ff_track_t *t;
440
441         if (f->total_tracks == 0)
442                 return f->error++;
443         t = f->track[f->total_tracks - 1];
444         if (t->ctts_entry_count)
445                 return 0;
446
447         read_char(f);   /* version */
448         read_int24(f);  /* flags */
449         t->ctts_entry_count = read_int32(f);
450
451         t->ctts_sample_count = para_malloc(t->ctts_entry_count
452                 * sizeof (int32_t));
453         t->ctts_sample_offset = para_malloc(t->ctts_entry_count
454                 * sizeof (int32_t));
455
456         /* CVE-2017-9257 */
457         for (i = 0; i < t->ctts_entry_count && !f->stream->read_error; i++) {
458                 t->ctts_sample_count[i] = read_int32(f);
459                 t->ctts_sample_offset[i] = read_int32(f);
460         }
461         return 1;
462 }
463
464 static int32_t read_stsc(mp4ff_t * f)
465 {
466         int32_t i;
467         mp4ff_track_t *t;
468
469         if (f->total_tracks == 0)
470                 return f->error++;
471         t = f->track[f->total_tracks - 1];
472
473         read_char(f);   /* version */
474         read_int24(f);  /* flags */
475         t->stsc_entry_count = read_int32(f);
476         t->stsc_first_chunk = para_malloc(t->stsc_entry_count * sizeof(int32_t));
477         t->stsc_samples_per_chunk = para_malloc(t->stsc_entry_count
478                 * sizeof (int32_t));
479         t->stsc_sample_desc_index = para_malloc(t->stsc_entry_count *
480                 sizeof (int32_t));
481
482         /* CVE-2017-9255 */
483         for (i = 0; i < t->stsc_entry_count && !f->stream->read_error; i++) {
484                 t->stsc_first_chunk[i] = read_int32(f);
485                 t->stsc_samples_per_chunk[i] = read_int32(f);
486                 t->stsc_sample_desc_index[i] = read_int32(f);
487         }
488         return 0;
489 }
490
491 static int32_t read_stco(mp4ff_t * f)
492 {
493         int32_t i;
494         mp4ff_track_t *t;
495
496         if (f->total_tracks == 0)
497                 return f->error++;
498         t = f->track[f->total_tracks - 1];
499
500         read_char(f);   /* version */
501         read_int24(f);  /* flags */
502         t->stco_entry_count = read_int32(f);
503         t->stco_chunk_offset = para_malloc(t->stco_entry_count
504                 * sizeof(int32_t));
505         /* CVE-2017-9256 */
506         for (i = 0; i < t->stco_entry_count && !f->stream->read_error; i++)
507                 t->stco_chunk_offset[i] = read_int32(f);
508         return 0;
509 }
510
511 static uint16_t read_int16(mp4ff_t * f)
512 {
513         int8_t data[2];
514
515         read_data(f, data, 2);
516         return read_u16_be(data);
517 }
518
519 static uint32_t read_mp4_descr_length(mp4ff_t * f)
520 {
521         uint8_t b;
522         uint8_t numBytes = 0;
523         uint32_t length = 0;
524
525         do {
526                 b = read_char(f);
527                 numBytes++;
528                 length = (length << 7) | (b & 0x7F);
529         } while ((b & 0x80) && numBytes < 4);
530
531         return length;
532 }
533 static int32_t read_esds(mp4ff_t * f)
534 {
535         uint8_t tag;
536         uint32_t temp;
537         mp4ff_track_t *t;
538
539         if (f->total_tracks == 0)
540                 return f->error++;
541         t = f->track[f->total_tracks - 1];
542         read_char(f);   /* version */
543         read_int24(f);  /* flags */
544         /* get and verify ES_DescrTag */
545         tag = read_char(f);
546         if (tag == 0x03) {
547                 /* read length */
548                 if (read_mp4_descr_length(f) < 5 + 15) {
549                         return 1;
550                 }
551                 /* skip 3 bytes */
552                 read_int24(f);
553         } else {
554                 /* skip 2 bytes */
555                 read_int16(f);
556         }
557
558         /* get and verify DecoderConfigDescrTab */
559         if (read_char(f) != 0x04) {
560                 return 1;
561         }
562
563         /* read length */
564         temp = read_mp4_descr_length(f);
565         if (temp < 13)
566                 return 1;
567
568         t->audioType = read_char(f);
569         read_int32(f);  //0x15000414 ????
570         t->maxBitrate = read_int32(f);
571         t->avgBitrate = read_int32(f);
572
573         /* get and verify DecSpecificInfoTag */
574         if (read_char(f) != 0x05) {
575                 return 1;
576         }
577
578         /* read length */
579         t->decoderConfigLen = read_mp4_descr_length(f);
580         free(t->decoderConfig);
581         t->decoderConfig = para_malloc(t->decoderConfigLen);
582         read_data(f, t->decoderConfig, t->decoderConfigLen);
583         /* will skip the remainder of the atom */
584         return 0;
585 }
586
587 static int32_t read_mp4a(mp4ff_t * f)
588 {
589         int32_t i;
590         uint8_t atom_type = 0;
591         uint8_t header_size = 0;
592         mp4ff_track_t *t;
593
594         if (f->total_tracks == 0)
595                 return f->error++;
596         t = f->track[f->total_tracks - 1];
597
598         for (i = 0; i < 6; i++) {
599                 read_char(f);   /* reserved */
600         }
601         /* data_reference_index */ read_int16(f);
602
603         read_int32(f);  /* reserved */
604         read_int32(f);  /* reserved */
605
606         t->channelCount = read_int16(f);
607         t->sampleSize = read_int16(f);
608
609         read_int16(f);
610         read_int16(f);
611
612         t->sampleRate = read_int16(f);
613
614         read_int16(f);
615
616         atom_read_header(f, &atom_type, &header_size);
617         if (atom_type == ATOM_ESDS)
618                 read_esds(f);
619         return 0;
620 }
621
622 static int32_t read_stsd(mp4ff_t * f)
623 {
624         int32_t i;
625         uint8_t header_size = 0;
626         mp4ff_track_t *t;
627
628         /* CVE-2017-9218 */
629         if (f->total_tracks == 0)
630                 return f->error++;
631         t = f->track[f->total_tracks - 1];
632
633         read_char(f);   /* version */
634         read_int24(f);  /* flags */
635
636         t->stsd_entry_count = read_int32(f);
637
638         /* CVE-2017-9253 */
639         for (i = 0; i < t->stsd_entry_count && !f->stream->read_error; i++) {
640                 uint64_t skip = get_position(f);
641                 uint64_t size;
642                 uint8_t atom_type = 0;
643                 size = atom_read_header(f, &atom_type, &header_size);
644                 skip += size;
645
646                 if (atom_type == ATOM_MP4A) {
647                         t->type = TRACK_AUDIO;
648                         read_mp4a(f);
649                 } else if (atom_type == ATOM_MP4V) {
650                         t->type = TRACK_VIDEO;
651                 } else if (atom_type == ATOM_MP4S) {
652                         t->type = TRACK_SYSTEM;
653                 } else {
654                         t->type = TRACK_UNKNOWN;
655                 }
656                 set_position(f, skip);
657         }
658
659         return 0;
660 }
661
662 static int32_t read_mvhd(mp4ff_t * f)
663 {
664         int32_t i;
665
666         read_char(f);   /* version */
667         read_int24(f);  /* flags */
668         /* creation_time */ read_int32(f);
669         /* modification_time */ read_int32(f);
670         f->time_scale = read_int32(f);
671         f->duration = read_int32(f);
672                                                         /* preferred_rate */ read_int32(f);
673                                                         /*mp4ff_read_fixed32(f); */
674                                                         /* preferred_volume */ read_int16(f);
675                                                         /*mp4ff_read_fixed16(f); */
676         for (i = 0; i < 10; i++) {
677                 /* reserved */ read_char(f);
678         }
679         for (i = 0; i < 9; i++) {
680                 read_int32(f);  /* matrix */
681         }
682         /* preview_time */ read_int32(f);
683         /* preview_duration */ read_int32(f);
684         /* poster_time */ read_int32(f);
685         /* selection_time */ read_int32(f);
686         /* selection_duration */ read_int32(f);
687         /* current_time */ read_int32(f);
688         /* next_track_id */ read_int32(f);
689
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 }