ref: 2c3c95d2b5554390590cba77ddf19ea76fc71785
parent: 158fe58a780379917fd3c118cd0ed913df4a152e
author: Doug Cook <idigdoug@users.sourceforge.net>
date: Sat Mar 17 22:22:23 EDT 2012
Fix mp3 format's direct use of format_t.fp
--- a/src/mp3-util.h
+++ b/src/mp3-util.h
@@ -97,34 +97,143 @@
return NULL;
}
+struct tag_info_node
+{
+ struct tag_info_node * next;
+ off_t start;
+ off_t end;
+};
+
+struct tag_info {
+ sox_format_t * ft;
+ struct tag_info_node * head;
+ struct id3_tag * tag;
+};
+
+static int add_tag(struct tag_info * info)
+{
+ struct tag_info_node * current;
+ off_t start, end;
+ id3_byte_t query[ID3_TAG_QUERYSIZE];
+ id3_byte_t * buffer;
+ long size;
+ int result = 0;
+
+ /* Ensure we're at the start of a valid tag and get its size. */
+ if (ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) ||
+ !(size = id3_tag_query(query, ID3_TAG_QUERYSIZE))) {
+ return 0;
+ }
+ if (size < 0) {
+ if (0 != lsx_seeki(info->ft, size, SEEK_CUR) ||
+ ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) ||
+ (size = id3_tag_query(query, ID3_TAG_QUERYSIZE)) <= 0) {
+ return 0;
+ }
+ }
+
+ /* Don't read a tag more than once. */
+ start = lsx_tell(info->ft);
+ end = start + size;
+ for (current = info->head; current; current = current->next) {
+ if (start == current->start && end == current->end) {
+ return 1;
+ } else if (start < current->end && current->start < end) {
+ return 0;
+ }
+ }
+
+ buffer = lsx_malloc(size);
+ if (!buffer) {
+ return 0;
+ }
+ memcpy(buffer, query, ID3_TAG_QUERYSIZE);
+ if ((unsigned long)size - ID3_TAG_QUERYSIZE ==
+ lsx_readbuf(info->ft, buffer + ID3_TAG_QUERYSIZE, size - ID3_TAG_QUERYSIZE)) {
+ struct id3_tag * tag = id3_tag_parse(buffer, size);
+ if (tag) {
+ current = lsx_malloc(sizeof(struct tag_info_node));
+ if (current) {
+ current->next = info->head;
+ current->start = start;
+ current->end = end;
+ info->head = current;
+ if (info->tag && (info->tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) {
+ struct id3_frame * frame;
+ unsigned i;
+ for (i = 0; frame = id3_tag_findframe(tag, NULL, i); i++) {
+ id3_tag_attachframe(info->tag, frame);
+ }
+ id3_tag_delete(tag);
+ } else {
+ if (info->tag) {
+ id3_tag_delete(info->tag);
+ }
+ info->tag = tag;
+ }
+ }
+ }
+ }
+ free(buffer);
+ return result;
+}
+
static void read_comments(sox_format_t * ft)
{
- struct id3_file * id3struct;
- struct id3_tag * tag;
+ struct tag_info info;
id3_utf8_t * utf8;
- int i, fd = dup(fileno((FILE*)ft->fp));
+ int i;
+ int has_id3v1 = 0;
- if ((id3struct = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY))) {
- if ((tag = id3_file_tag(id3struct)) && tag->frames)
- for (i = 0; id3tagmap[i][0]; ++i)
- if ((utf8 = utf8_id3tag_findframe(tag, id3tagmap[i][0], 0))) {
- char * comment = lsx_malloc(strlen(id3tagmap[i][1]) + 1 + strlen((char *)utf8) + 1);
- sprintf(comment, "%s=%s", id3tagmap[i][1], utf8);
- sox_append_comment(&ft->oob.comments, comment);
- free(comment);
- free(utf8);
- }
- if ((utf8 = utf8_id3tag_findframe(tag, "TLEN", 0))) {
- unsigned long tlen = strtoul((char *)utf8, NULL, 10);
- if (tlen > 0 && tlen < ULONG_MAX) {
- ft->signal.length= tlen; /* In ms; convert to samples later */
- lsx_debug("got exact duration from ID3 TLEN");
- }
+ info.ft = ft;
+ info.head = NULL;
+ info.tag = NULL;
+
+ /*
+ We look for:
+ ID3v1 at end (EOF - 128).
+ ID3v2 at start.
+ ID3v2 at end (but before ID3v1 from end if there was one).
+ */
+
+ if (0 == lsx_seeki(ft, -128, SEEK_END)) {
+ has_id3v1 =
+ add_tag(&info) &&
+ 1 == ID3_TAG_VERSION_MAJOR(id3_tag_version(info.tag));
+ }
+ if (0 == lsx_seeki(ft, 0, SEEK_SET)) {
+ add_tag(&info);
+ }
+ if (0 == lsx_seeki(ft, has_id3v1 ? -138 : -10, SEEK_END)) {
+ add_tag(&info);
+ }
+ if (info.tag && info.tag->frames) {
+ for (i = 0; id3tagmap[i][0]; ++i) {
+ if ((utf8 = utf8_id3tag_findframe(info.tag, id3tagmap[i][0], 0))) {
+ char * comment = lsx_malloc(strlen(id3tagmap[i][1]) + 1 + strlen((char *)utf8) + 1);
+ sprintf(comment, "%s=%s", id3tagmap[i][1], utf8);
+ sox_append_comment(&ft->oob.comments, comment);
+ free(comment);
free(utf8);
}
- id3_file_close(id3struct);
+ }
+ if ((utf8 = utf8_id3tag_findframe(info.tag, "TLEN", 0))) {
+ unsigned long tlen = strtoul((char *)utf8, NULL, 10);
+ if (tlen > 0 && tlen < ULONG_MAX) {
+ ft->signal.length= tlen; /* In ms; convert to samples later */
+ lsx_debug("got exact duration from ID3 TLEN");
+ }
+ free(utf8);
+ }
}
- else close(fd);
+ while (info.head) {
+ struct tag_info_node * head = info.head;
+ info.head = head->next;
+ free(head);
+ }
+ if (info.tag) {
+ id3_tag_delete(info.tag);
+ }
}
#endif /* USING_ID3TAG */
--- a/src/mp3.c
+++ b/src/mp3.c
@@ -385,7 +385,7 @@
if (ft->seekable) {
#ifdef USING_ID3TAG
read_comments(ft);
- rewind((FILE*)ft->fp);
+ lsx_rewind(ft);
if (!ft->signal.length)
#endif
if (!ignore_length)
@@ -404,7 +404,7 @@
* can be processed later.
*/
ReadSize = lsx_readbuf(ft, p->mp3_buffer, p->mp3_buffer_size);
- if (ReadSize != p->mp3_buffer_size && ferror((FILE*)ft->fp))
+ if (ReadSize != p->mp3_buffer_size && lsx_error(ft))
return SOX_EOF;
p->mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize);
@@ -568,7 +568,7 @@
uint64_t to_skip_samples = 0;
/* Reset all */
- rewind((FILE*)ft->fp);
+ lsx_rewind(ft);
mad_timer_reset(&p->Timer);
p->FrameCount = 0;
@@ -585,12 +585,13 @@
to_skip_samples = offset;
while(sox_true) { /* Read data from the MP3 file */
- int read, padding = 0;
+ size_t padding = 0;
+ size_t read;
size_t leftover = p->Stream.bufend - p->Stream.next_frame;
memcpy(p->mp3_buffer, p->Stream.this_frame, leftover);
- read = fread(p->mp3_buffer + leftover, (size_t) 1, p->mp3_buffer_size - leftover, (FILE*)ft->fp);
- if (read <= 0) {
+ read = lsx_readbuf(ft, p->mp3_buffer + leftover, p->mp3_buffer_size - leftover);
+ if (read == 0) {
lsx_debug("seek failure. unexpected EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", p->FrameCount, leftover);
break;
}
@@ -615,7 +616,7 @@
tagsize = tagtype(p->Stream.this_frame, (size_t) available);
if (tagsize) { /* It's some ID3 tags, so just skip */
if (tagsize >= available) {
- fseeko((FILE*)ft->fp, (off_t)(tagsize - available), SEEK_CUR);
+ lsx_seeki(ft, (off_t)(tagsize - available), SEEK_CUR);
depadded = sox_false;
}
p->mad_stream_skip(&p->Stream, min(tagsize, available));
@@ -728,18 +729,17 @@
static int get_id3v2_tag_size(sox_format_t * ft)
{
- FILE *fp = ft->fp;
size_t bytes_read;
int id3v2_size;
unsigned char id3v2_header[10];
- if (fseeko(fp, (off_t)0, SEEK_SET) != 0) {
+ if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0) {
lsx_warn("cannot update id3 tag - failed to seek to beginning");
return SOX_EOF;
}
/* read 10 bytes in case there's an ID3 version 2 header here */
- bytes_read = fread(id3v2_header, (size_t)1, sizeof(id3v2_header), fp);
+ bytes_read = lsx_readbuf(ft, id3v2_header, sizeof(id3v2_header));
if (bytes_read != sizeof(id3v2_header)) {
lsx_warn("cannot update id3 tag - failed to read id3 header");
return SOX_EOF; /* not readable, maybe opened Write-Only */
@@ -764,7 +764,6 @@
static void rewrite_id3v2_tag(sox_format_t * ft, size_t id3v2_size, uint64_t num_samples)
{
priv_t *p = (priv_t *)ft->priv;
- FILE *fp = ft->fp;
size_t new_size;
unsigned char * buffer;
@@ -790,7 +789,7 @@
num_samples = 0;
}
p->lame_set_num_samples(p->gfp, (unsigned long)num_samples);
- lsx_debug("updated MP3 TLEN to %" PRIu64 " samples", num_samples);
+ lsx_debug("updated MP3 TLEN to %ul samples", (unsigned long)num_samples);
new_size = p->lame_get_id3v2_tag(p->gfp, buffer, id3v2_size);
@@ -810,9 +809,9 @@
else
lsx_warn("cannot update track length info - failed to adjust tag size");
} else {
- fseeko(fp, (off_t)0, SEEK_SET);
+ lsx_seeki(ft, 0, SEEK_SET);
/* Overwrite the Id3v2 tag (this time TLEN should be accurate) */
- if (fwrite(buffer, id3v2_size, (size_t)1, fp) != 1) {
+ if (lsx_writebuf(ft, buffer, id3v2_size) != 1) {
lsx_debug("Rewrote Id3v2 tag (%" PRIuPTR " bytes)", id3v2_size);
}
}
@@ -823,18 +822,17 @@
static void rewrite_tags(sox_format_t * ft, uint64_t num_samples)
{
priv_t *p = (priv_t *)ft->priv;
- FILE *fp = ft->fp;
off_t file_size;
size_t id3v2_size;
- if (fseeko(fp, (off_t)0, SEEK_END)) {
+ if (lsx_seeki(ft, 0, SEEK_END)) {
lsx_warn("cannot update tags - seek to end failed");
return;
}
/* Get file size */
- file_size = ftello(fp);
+ file_size = lsx_tell(ft);
if (file_size == 0) {
lsx_warn("cannot update tags - file size is 0");
@@ -850,7 +848,7 @@
size_t lametag_size;
uint8_t buffer[MAXFRAMESIZE];
- if (fseeko(fp, (off_t)id3v2_size, SEEK_SET)) {
+ if (lsx_seeki(ft, (off_t)id3v2_size, SEEK_SET)) {
lsx_warn("cannot write VBR tag - seek to tag block failed");
return;
}
@@ -865,7 +863,7 @@
return;
}
- if (fwrite(buffer, lametag_size, (size_t)1, fp) != 1) {
+ if (lsx_writebuf(ft, buffer, lametag_size) != lametag_size) {
lsx_warn("cannot write VBR tag - VBR tag write failed");
} else {
lsx_debug("rewrote VBR tag (%" PRIuPTR " bytes)", lametag_size);