+static char *get_tag(unsigned char *p, int size)
+{
+ char *buf;
+
+ assert(size > 0);
+ buf = para_malloc(size + 1);
+
+ memcpy(buf, p, size);
+ buf[size] = '\0';
+ PARA_DEBUG_LOG("size: %d: %s\n", size, buf);
+ return buf;
+}
+
+static char *read_tags(unsigned char *buf, size_t buflen)
+{
+ unsigned char *p = buf;
+ char *title = NULL, *artist = NULL, *album = NULL, *year = NULL,
+ *comment = NULL, *result;
+
+ while (p + 32 < buf + buflen) {
+ unsigned char *q, type1[5], type2[5];
+ uint64_t size1, size2;
+ int ret, ret2;
+
+ ret = read_atom_header(p, &size1, type1);
+ ret2 = read_atom_header(p + ret, &size2, type2);
+
+ if (size2 <= 16 || atom_cmp(type2, "data")) {
+ p += size1;
+ continue;
+ }
+ size2 -= 16;
+ q = p + ret + ret2 + 8;
+ if (q + size2 > buf + buflen)
+ break;
+ if (!atom_cmp(type1, "©ART"))
+ artist = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©alb"))
+ album = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©nam"))
+ title = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©cmt"))
+ comment = get_tag(q, size2);
+ else if (!atom_cmp(type1, "©day"))
+ year = get_tag(q, size2);
+ p += size1;
+ }
+ result = make_taginfo(title, artist, album, year, comment);
+ free(title);
+ free(artist);
+ free(album);
+ free(year);
+ free(comment);
+ return result;
+}
+
+static char *read_meta(unsigned char *buf, size_t buflen)
+{
+ unsigned char *p = buf;
+
+ while (p + 4 < buf + buflen) {
+
+ if (p[0] != 'i' || p[1] != 'l' || p[2] != 's' || p[3] != 't') {
+ p++;
+ continue;
+ }
+ p += 4;
+ return read_tags(p, buflen - (p - buf));
+ }
+ return make_taginfo(NULL, NULL, NULL, NULL, NULL);
+}
+
+static char *aac_get_taginfo(unsigned char *buf, size_t buflen)