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