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