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