aboutsummaryrefslogtreecommitdiff
path: root/libid3tag/tag.c
diff options
context:
space:
mode:
Diffstat (limited to 'libid3tag/tag.c')
-rw-r--r--libid3tag/tag.c505
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;
}

Return to:

Send suggestions and report system problems to the System administrator.