{
return a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2;
}
-
enum atoms {
/* atoms with subatoms */
ATOM_MOOV = 1,
"Anime", "JPop", "SynthPop",
};
-static const char *meta_index_to_genre(uint32_t idx)
-{
- if (idx > 0 && idx <= sizeof (ID3v1GenreList) / sizeof (ID3v1GenreList[0])) {
- return ID3v1GenreList[idx - 1];
- } else {
- return 0;
- }
-}
-
static char *read_string(struct mp4 *f, uint32_t length)
{
char *str = para_malloc(length + 1);
switch (atom_type) {
case ATOM_TITLE: return "title";
case ATOM_ARTIST: return "artist";
- case ATOM_WRITER: return "writer";
case ATOM_ALBUM: return "album";
case ATOM_DATE: return "date";
- case ATOM_TOOL: return "tool";
case ATOM_COMMENT: return "comment";
- case ATOM_GENRE1: return "genre";
- case ATOM_TRACK: return "track";
- case ATOM_DISC: return "disc";
- case ATOM_COMPILATION: return "compilation";
- case ATOM_GENRE2: return "genre";
- case ATOM_TEMPO: return "tempo";
- case ATOM_COVER: return "cover";
- case ATOM_ALBUM_ARTIST: return "album_artist";
- case ATOM_CONTENTGROUP: return "contentgroup";
- case ATOM_LYRICS: return "lyrics";
- case ATOM_DESCRIPTION: return "description";
- case ATOM_NETWORK: return "network";
- case ATOM_SHOW: return "show";
- case ATOM_EPISODENAME: return "episodename";
- case ATOM_SORTTITLE: return "sorttitle";
- case ATOM_SORTALBUM: return "sortalbum";
- case ATOM_SORTARTIST: return "sortartist";
- case ATOM_SORTALBUMARTIST: return "sortalbumartist";
- case ATOM_SORTWRITER: return "sortwriter";
- case ATOM_SORTSHOW: return "sortshow";
- case ATOM_SEASON: return "season";
- case ATOM_EPISODE: return "episode";
- case ATOM_PODCAST: return "podcast";
default: return "unknown";
}
}
-static uint32_t min_body_size(uint8_t atom_type)
-{
- switch(atom_type) {
- case ATOM_GENRE2:
- case ATOM_TEMPO:
- return 10;
- case ATOM_TRACK:
- return sizeof (char) /* version */
- + sizeof(uint8_t) * 3 /* flags */
- + sizeof(uint32_t) /* reserved */
- + sizeof(uint16_t) /* leading uint16_t */
- + sizeof(uint16_t) /* track */
- + sizeof(uint16_t); /* totaltracks */
- case ATOM_DISC:
- return sizeof (char) /* version */
- + sizeof(uint8_t) * 3 /* flags */
- + sizeof(uint32_t) /* reserved */
- + sizeof(uint16_t) /* disc */
- + sizeof(uint16_t); /* totaldiscs */
- default: assert(false);
- }
-}
-
-static int32_t parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
+static void parse_tag(struct mp4 *f, uint8_t parent, int32_t size)
{
- uint8_t atom_type;
- uint8_t header_size = 0;
uint64_t subsize, sumsize;
char *name = NULL;
char *data = NULL;
- uint32_t done = 0;
uint32_t len = 0;
uint64_t destpos;
sumsize < size && !f->read_error; /* CVE-2017-9222 */
set_position(f, destpos), sumsize += subsize
) {
+ uint8_t atom_type;
+ uint8_t header_size = 0;
subsize = atom_read_header(f, &atom_type, &header_size);
destpos = get_position(f) + subsize - header_size;
- if (done)
- continue;
if (atom_type == ATOM_NAME) {
read_char(f); /* version */
read_int24(f); /* flags */
read_char(f); /* version */
read_int24(f); /* flags */
read_int32(f); /* reserved */
-
- /* some need special attention */
- if (parent == ATOM_GENRE2 || parent == ATOM_TEMPO) {
- uint16_t val;
- if (subsize - header_size < min_body_size(parent))
- continue;
- val = read_int16(f);
- if (parent == ATOM_TEMPO) {
- char temp[16];
- sprintf(temp, "%.5u BPM", val);
- tag_add_field(&(f-> tags), "tempo",
- temp, -1);
- } else {
- const char *tmp = meta_index_to_genre(val);
- if (tmp)
- tag_add_field (&(f->tags),
- "genre", tmp, -1);
- }
- done = 1;
- } else if (parent == ATOM_TRACK || parent == ATOM_DISC) {
- uint16_t index, total;
- char temp[32];
- if (subsize - header_size < min_body_size(parent))
- continue;
- read_int16(f);
- index = read_int16(f);
- total = read_int16(f);
- if (parent == ATOM_TRACK)
- read_int16(f);
- sprintf(temp, "%d", index);
- tag_add_field(&(f->tags), parent == ATOM_TRACK?
- "track" : "disc", temp, -1);
- if (total > 0) {
- sprintf(temp, "%d", total);
- tag_add_field(& (f-> tags),
- parent == ATOM_TRACK?
- "totaltracks" : "totaldiscs", temp, -1);
- }
- done = 1;
- } else {
- free(data);
- data = read_string(f, subsize - (header_size + 8));
- len = subsize - (header_size + 8);
- }
+ free(data);
+ data = read_string(f, subsize - (header_size + 8));
+ len = subsize - (header_size + 8);
}
if (data) {
- if (!done) {
- if (!name)
- name = para_strdup(get_metadata_name(parent));
- tag_add_field(&(f->tags), name, data, len);
- }
+ if (!name)
+ name = para_strdup(get_metadata_name(parent));
+ tag_add_field(&(f->tags), name, data, len);
free(data);
}
free(name);
- return 1;
}
static int32_t read_mdhd(struct mp4 *f)
static int32_t parse_metadata(struct mp4 *f, int32_t size)
{
- uint64_t subsize, sumsize = 0;
- uint8_t atom_type;
- uint8_t header_size = 0;
+ uint64_t sumsize = 0;
while (sumsize < size) {
+ uint8_t atom_type;
+ uint64_t subsize, destpos;
+ uint8_t header_size = 0;
subsize = atom_read_header(f, &atom_type, &header_size);
if (subsize == 0)
break;
- parse_tag(f, atom_type, (uint32_t)(subsize - header_size));
+ destpos = get_position(f) + subsize - header_size;
+ switch (atom_type) {
+ case ATOM_ARTIST:
+ case ATOM_TITLE:
+ case ATOM_ALBUM:
+ case ATOM_COMMENT:
+ case ATOM_DATE:
+ parse_tag(f, atom_type, subsize - header_size);
+ }
+ set_position(f, destpos);
sumsize += subsize;
}