diff options
Diffstat (limited to 'libid3tag/tag.c')
-rw-r--r-- | libid3tag/tag.c | 505 |
1 files changed, 233 insertions, 272 deletions
diff --git a/libid3tag/tag.c b/libid3tag/tag.c index 11e3b13..c23a967 100644 --- a/libid3tag/tag.c +++ b/libid3tag/tag.c @@ -401,324 +401,285 @@ static struct id3_tag * v1_parse(id3_byte_t const *data) { struct id3_tag *tag; + char title[31], artist[31], album[31], year[5], comment[31]; + unsigned int genre, track; tag = id3_tag_new(); - if (tag) { - char title[31], - artist[31], - album[31], - year[5], - comment[31]; - unsigned int genre, - track; - - tag->version = 0x0100; - - tag->options |= ID3_TAG_OPTION_ID3V1; - tag->options &= ~ID3_TAG_OPTION_COMPRESSION; - - tag->restrictions = - ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 | - ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS; - - title[30] = artist[30] = album[30] = year[4] = - comment[30] = 0; - - memcpy(title, &data[3], 30); - memcpy(artist, &data[33], 30); - memcpy(album, &data[63], 30); - memcpy(year, &data[93], 4); - memcpy(comment, &data[97], 30); - - genre = data[127]; - - track = 0; - if (comment[28] == 0 && comment[29] != 0) { - track = comment[29]; - tag->version = 0x0101; - } + if (!tag) + return NULL; + + tag->version = 0x0100; + + tag->options |= ID3_TAG_OPTION_ID3V1; + tag->options &= ~ID3_TAG_OPTION_COMPRESSION; + + tag->restrictions = + ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 | + ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS; + + title[30] = artist[30] = album[30] = year[4] = comment[30] = 0; + + memcpy(title, &data[3], 30); + memcpy(artist, &data[33], 30); + memcpy(album, &data[63], 30); + memcpy(year, &data[93], 4); + memcpy(comment, &data[97], 30); + + genre = data[127]; + + track = 0; + if (comment[28] == 0 && comment[29] != 0) { + track = comment[29]; + tag->version = 0x0101; + } - /* - * populate tag frames - */ - - if (v1_attachstr(tag, ID3_FRAME_TITLE, title, 0) == -1 || - v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 || - v1_attachstr(tag, ID3_FRAME_ALBUM, album, 0) == -1 || - v1_attachstr(tag, ID3_FRAME_YEAR, year, 0) == -1 || - (track - && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) - || (genre < 0xff - && v1_attachstr(tag, ID3_FRAME_GENRE, 0, - genre) == -1) - || v1_attachstr(tag, ID3_FRAME_COMMENT, comment, - 0) == -1) { - id3_tag_delete(tag); - tag = 0; - } + /* + * populate tag frames + */ + + if (v1_attachstr(tag, ID3_FRAME_TITLE, title, 0) == -1 || + v1_attachstr(tag, ID3_FRAME_ARTIST, artist, 0) == -1 || + v1_attachstr(tag, ID3_FRAME_ALBUM, album, 0) == -1 || + v1_attachstr(tag, ID3_FRAME_YEAR, year, 0) == -1 || + (track && v1_attachstr(tag, ID3_FRAME_TRACK, 0, track) == -1) + || (genre < 0xff + && v1_attachstr(tag, ID3_FRAME_GENRE, 0, + genre) == -1) + || v1_attachstr(tag, ID3_FRAME_COMMENT, comment, + 0) == -1) { + id3_tag_delete(tag); + tag = 0; } return tag; } -static struct id3_tag * -v2_parse(id3_byte_t const *ptr) +static int +v3_parse_3(struct id3_tag *tag, id3_byte_t const **pptr, + id3_byte_t const **pend) { - struct id3_tag *tag; - id3_byte_t *mem = 0; - - tag = id3_tag_new(); - if (tag) { - id3_byte_t const *end; - id3_length_t size; - - parse_header(&ptr, &tag->version, &tag->flags, &size); - - tag->paddedsize = 10 + size; - - if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) && - ID3_TAG_VERSION_MAJOR(tag->version) < 4) { - mem = malloc(size); - if (mem == 0) - goto fail; + id3_byte_t const *ehptr, *ehend; + id3_length_t ehsize; + id3_byte_t const *ptr = *pptr; + id3_byte_t const *end = *pend; + + enum { + EH_FLAG_CRC = 0x8000 /* CRC data present */ + }; + + if (end - ptr < 4) + return 1; + + ehsize = id3_parse_uint(&ptr, 4); + + if (ehsize > end - ptr) + return 1; + + ehptr = ptr; + ehend = ptr + ehsize; + + ptr = ehend; + + if (ehend - ehptr >= 6) { + int ehflags; + id3_length_t padsize; + + ehflags = id3_parse_uint(&ehptr, 2); + padsize = id3_parse_uint(&ehptr, 4); + + if (padsize > end - ptr) + return 1; + + end -= padsize; + + if (ehflags & EH_FLAG_CRC) { + unsigned long crc; + + if (ehend - ehptr < 4) + return 1; + + crc = id3_parse_uint(&ehptr, 4); + + if (crc != id3_crc_compute(ptr, end - ptr)) + return 1; + tag->extendedflags |= + ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; + } + } - memcpy(mem, ptr, size); + *pptr = ptr; + *pend = end; + return 0; +} - size = id3_util_deunsynchronise(mem, size); - ptr = mem; +static int +verify_extended(id3_byte_t const *flagsptr, + id3_byte_t const *dataptr, id3_byte_t const *ehend, + unsigned int bytes) +{ + unsigned int datalen; + int ehflags; + + while (bytes--) { + for (ehflags = id3_parse_uint(&flagsptr, 1); ehflags; + ehflags = (ehflags << 1) & 0xff) { + if (ehflags & 0x80) { + if (dataptr == ehend) + return 1; + datalen = id3_parse_uint(&dataptr, 1); + if (datalen > 0x7f || datalen > ehend - dataptr) + return 1; + dataptr += datalen; + } } + } + return 0; +} - end = ptr + size; +int +v3_parse_4(struct id3_tag *tag, id3_byte_t const **pptr, id3_byte_t const **pend) +{ + id3_byte_t const *ptr = *pptr; + id3_byte_t const *end = *pend; + id3_byte_t const *ehptr, *ehend; + id3_length_t ehsize; + unsigned int bytes; + + if (end - ptr < 4) + return 1; + + ehptr = ptr; + ehsize = id3_parse_syncsafe(&ptr, 4); + + if (ehsize < 6 || ehsize > end - ehptr) + return 1; + ehend = ehptr + ehsize; + + bytes = id3_parse_uint(&ptr, 1); + + if (bytes < 1 || bytes > ehend - ptr) + return 1; + + ehptr = ptr + bytes; - if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) { - switch (ID3_TAG_VERSION_MAJOR(tag->version)) { - case 2: - goto fail; + /* + * verify extended header size + */ + if (verify_extended(ptr, ehptr, ehend, bytes)) + return 1; - case 3: - { - id3_byte_t const *ehptr, - *ehend; - id3_length_t ehsize; + tag->extendedflags = id3_parse_uint(&ptr, 1); - enum { - EH_FLAG_CRC = 0x8000 /* CRC - * data - * present - */ - }; + ptr = ehend; - if (end - ptr < 4) - goto fail; + if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) { + bytes = id3_parse_uint(&ehptr, 1); + ehptr += bytes; + } - ehsize = id3_parse_uint(&ptr, 4); + if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) { + unsigned long crc; - if (ehsize > end - ptr) - goto fail; + bytes = id3_parse_uint(&ehptr, 1); + if (bytes < 5) + return 1; - ehptr = ptr; - ehend = ptr + ehsize; + crc = id3_parse_syncsafe(&ehptr, 5); + ehptr += bytes - 5; - ptr = ehend; + if (crc != id3_crc_compute(ptr, end - ptr)) + return 1; + } + + if (tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) { + bytes = id3_parse_uint(&ehptr, 1); + if (bytes < 1) + return 1; + tag->restrictions = id3_parse_uint(&ehptr, 1); + ehptr += bytes - 1; + } - if (ehend - ehptr >= 6) { - int ehflags; - id3_length_t padsize; + *pptr = ptr; + *pend = end; + return 0; +} - ehflags = - id3_parse_uint(&ehptr, - 2); - padsize = - id3_parse_uint(&ehptr, - 4); +static struct id3_tag * +v2_parse(id3_byte_t const *ptr) +{ + struct id3_tag *tag; + id3_byte_t *mem = 0; + id3_byte_t const *end; + id3_length_t size; - if (padsize > end - ptr) - goto fail; + tag = id3_tag_new(); + if (!tag) + return NULL; + + parse_header(&ptr, &tag->version, &tag->flags, &size); - end -= padsize; + tag->paddedsize = 10 + size; - if (ehflags & EH_FLAG_CRC) { - unsigned long crc; + if ((tag->flags & ID3_TAG_FLAG_UNSYNCHRONISATION) && + ID3_TAG_VERSION_MAJOR(tag->version) < 4) { + mem = malloc(size); + if (mem == 0) + goto fail; - if (ehend - ehptr < - 4) - goto fail; + memcpy(mem, ptr, size); - crc = - id3_parse_uint - (&ehptr, 4); + size = id3_util_deunsynchronise(mem, size); + ptr = mem; + } - if (crc != - id3_crc_compute - (ptr, - end - ptr)) - goto fail; + end = ptr + size; - tag-> - extendedflags - |= - ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT; - } - } - } - break; + if (tag->flags & ID3_TAG_FLAG_EXTENDEDHEADER) { + switch (ID3_TAG_VERSION_MAJOR(tag->version)) { + case 2: + goto fail; - case 4: - { - id3_byte_t const *ehptr, - *ehend; - id3_length_t ehsize; - unsigned int bytes; - - if (end - ptr < 4) - goto fail; - - ehptr = ptr; - ehsize = - id3_parse_syncsafe(&ptr, 4); - - if (ehsize < 6 - || ehsize > end - ehptr) - goto fail; - - ehend = ehptr + ehsize; - - bytes = id3_parse_uint(&ptr, 1); - - if (bytes < 1 - || bytes > ehend - ptr) - goto fail; - - ehptr = ptr + bytes; - - /* - * verify extended header size - */ - { - id3_byte_t const *flagsptr - = ptr, - *dataptr = ehptr; - unsigned int datalen; - int ehflags; - - while (bytes--) { - for (ehflags = - id3_parse_uint - (&flagsptr, - 1); ehflags; - ehflags = - (ehflags << 1) - & 0xff) { - if (ehflags - & 0x80) - { - if (dataptr == ehend) - goto fail; - datalen - = - id3_parse_uint - (&dataptr, - 1); - if (datalen > 0x7f || datalen > ehend - dataptr) - goto fail; - dataptr - += - datalen; - } - } - } - } - - tag->extendedflags = - id3_parse_uint(&ptr, 1); - - ptr = ehend; - - if (tag-> - extendedflags & - ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE) - { - bytes = - id3_parse_uint(&ehptr, - 1); - ehptr += bytes; - } - - if (tag-> - extendedflags & - ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT) - { - unsigned long crc; - - bytes = - id3_parse_uint(&ehptr, - 1); - if (bytes < 5) - goto fail; - - crc = - id3_parse_syncsafe - (&ehptr, 5); - ehptr += bytes - 5; - - if (crc != - id3_crc_compute(ptr, - end - - ptr)) - goto fail; - } - - if (tag-> - extendedflags & - ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS) - { - bytes = - id3_parse_uint(&ehptr, - 1); - if (bytes < 1) - goto fail; - - tag->restrictions = - id3_parse_uint(&ehptr, - 1); - ehptr += bytes - 1; - } - } - break; - } - } + case 3: + if (v3_parse_3(tag, &ptr, &end)) + goto fail; + + break; - /* - * frames - */ + case 4: + if (v3_parse_4(tag, &ptr, &end)) + goto fail; + break; + } + } - while (ptr < end) { - struct id3_frame *frame; + /* + * frames + */ - if (*ptr == 0) - break; /* padding */ + while (ptr < end) { + struct id3_frame *frame; - frame = - id3_frame_parse(&ptr, end - ptr, tag->version); - if (frame == 0 - || id3_tag_attachframe(tag, frame) == -1) - goto fail; - } + if (*ptr == 0) + break; /* padding */ - if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 && - id3_compat_fixup(tag) == -1) + frame = id3_frame_parse(&ptr, end - ptr, tag->version); + if (frame == 0 || id3_tag_attachframe(tag, frame) == -1) goto fail; } + if (ID3_TAG_VERSION_MAJOR(tag->version) < 4 && + id3_compat_fixup(tag) == -1) + goto fail; + if (0) { - fail: + fail: id3_tag_delete(tag); tag = 0; } if (mem) free(mem); - + return tag; } |