Rockbox.org home
release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Rockbox mail archive

Subject: [PATCH] id3v2 -> overcoming 300 byte limit
From: Bill Napier (napier_at_pobox.com)
Date: 2002-08-29


This patch overcomes the current 300 byte limit to id3v2 tags. The
code will now go through and read in all of you v2 tag. Those of you
who have your titles (and other info) appearing late in your id3v2 tag
will now be able to make use of them.

It does this by using a temporary 300 byte buffer to read in the data
from disk. It is then parsed in this buffer looking for the
information that we are interested in. Everytime we see some
information we are interested in, we copy that data into the
mp3entry->id3v2buf data buffer. In this patch, the buffer is declared
static because I didn't feel comfortable putting 300 bytes on the
stack. To make it thread safe, it should really use some mutex's to
protect the temp buffer.

One other things to consider is the size of the mp3entry->id3v2buf
buffer. I left it at 300 bytes (seemed good enough to me), but should
we think about resizing it (my thinking was smaller...).

CAVEAT: If you tag won't fit in the 300 byte buffer, we skip it. This
shouldn't affect you unless you have album/title/artist fields that
are really, really, really long.

BTW - If you notice that some of your longer strings aren't being
fully displayed in the WPS, that's due to a buffer limit of 64 char's
in wps.c (took me quite a bit to track that one down. Couldn't figure
out why it was still reading my v1 tags...)

Bill Napier
napier_at_pobox.com

-------- Begin Patch --------
Index: firmware/id3.c
===================================================================
RCS file: /cvsroot/rockbox/firmware/id3.c,v
retrieving revision 1.39
diff -u -b -r1.39 id3.c
--- firmware/id3.c 22 Aug 2002 07:59:31 -0000 1.39
+++ firmware/id3.c 28 Aug 2002 21:53:28 -0000
@@ -49,6 +49,12 @@
                              ((b3 & 0x7F) << (1*7)) | \
                              ((b4 & 0x7F) << (0*7)))
 
+#define BYTES_TO_INT(b1,b2,b3,b4) (((b1 & 0xFF) << (3*8)) | \
+ ((b2 & 0xFF) << (2*8)) | \
+ ((b3 & 0xFF) << (1*8)) | \
+ ((b4 & 0xFF) << (0*8)))
+
+
 /* Table of bitrates for MP3 files, all values in kilo.
  * Indexed by version, layer and value of bit 15-12 in header.
  */
@@ -155,13 +161,15 @@
  * Arguments: file - the MP3 file to scen for a ID3v2 tag
  * entry - the entry to set the title in
  *
- * Returns: true if a title was found and created, else false
+ * Returns: none
  */
 static void setid3v2title(int fd, struct mp3entry *entry)
 {
     unsigned int minframesize;
- int size;
- unsigned int readsize = 0, headerlen;
+ unsigned int framehdrsize;
+ int size = 0;
+ unsigned int totalsize = 0;
+ unsigned int readsize = 0, headerlen = 0;
     char *title = NULL;
     char *artist = NULL;
     char *album = NULL;
@@ -169,7 +177,10 @@
     char header[10];
     unsigned short int version;
     int titlen=0, artistn=0, albumn=0, tracknumn=0;
- char *buffer = entry->id3v2buf;
+ /* Don't want to allocate this on the stack (it's kinda big) */
+ static char buffer[ID3_V2_BUF_SIZE];
+ char* buf_offset = buffer;
+ char* entry_offset = entry->id3v2buf;
         
     /* 10 = headerlength */
     if(entry->id3v2len < 10)
@@ -182,22 +193,54 @@
 
     version = (unsigned short int)header[3];
         
+ /* Set minimun frame size according to ID3v2 version */
+ if(version > 2) {
+ minframesize = 12;
+ framehdrsize = 10;
+ } else {
+ minframesize = 8;
+ framehdrsize = 6;
+ }
+
     /* Read all frames in the tag */
- size = entry->id3v2len - 10;
+ totalsize = entry->id3v2len - 10;
 
- if(size >= (int)sizeof(entry->id3v2buf))
- size = sizeof(entry->id3v2buf)-1;
+ while(totalsize > 0) {
+ int buf_size = ID3_V2_BUF_SIZE;
+ /* Start by adjusting entry_offset to the beginning of the
+ * buffer if we need to */
+ if(size - readsize != 0)
+ {
+ int remaining_size = size - readsize + framehdrsize;
+ int x =0;
 
- if(size != read(fd, buffer, size))
- return;
+ buf_offset = buffer + readsize - framehdrsize;
+ /* Overlapping memcpy */
+ while (x < remaining_size) {
+ *(buffer+x)=*(buf_offset++);
+ x++;
+ }
+ buf_offset = buffer+remaining_size;
+ buf_size -= remaining_size;
+ }
 
- *(buffer + size) = '\0';
+ /* Try and read the whole thing */
+ size = totalsize;
 
- /* Set minimun frame size according to ID3v2 version */
- if(version > 2)
- minframesize = 12;
- else
- minframesize = 8;
+ /* If we can't fit it in the buffer, read what we can */
+ if(size >= buf_size )
+ size = buf_size;
+
+ size = read(fd, buf_offset, size);
+ /* Don't need to check return value here, will be caught
+ * later... (look at the next while loop) */
+
+ /* Take off what we've read from the count */
+ totalsize -= size;
+
+ /* init size and readsize */
+ readsize = 0;
+ size = (buf_offset - buffer) + size;
 
     /*
      * We must have at least minframesize bytes left for the
@@ -209,61 +252,112 @@
         if(version > 2) {
             memcpy(header, (buffer + readsize), 10);
             readsize += 10;
+ if (version > 3) {
             headerlen = UNSYNC(header[4], header[5],
                                header[6], header[7]);
         } else {
+ /* version .3 files don't use synchsafe ints for
+ * size */
+ headerlen = BYTES_TO_INT(header[4], header[5],
+ header[6], header[7]);
+ }
+ } else {
             memcpy(header, (buffer + readsize), 6);
             readsize += 6;
             headerlen = (header[3] << 16) +
                 (header[4] << 8) +
                 (header[5]);
         }
- if(headerlen < 1)
+ /* If we get a 0 headerlen, we're into the padding at the
+ * end of many v2 tags. No need to go through the rest of
+ * the stuff */
+ if(headerlen < 1){
+ /* We don't need to read any more of the v2 tag */
+ totalsize=0;
+ /* Our current buffer is also done */
+ readsize=size;
             continue;
+ }
+
+ /* See if we have the entire frame in the buffer. If
+ * we do, good, keep going. Otherwise, break out of
+ * the loop, set the tags we know, and read in the
+ * next set of info. */
+ if(headerlen > (size - readsize)) {
+ /* This is the last tag in the buffer. We're probably
+ * going to read in some more data on our next time
+ * through. But first we need to sanity check to see
+ * if this frame will *EVER* fit in our buffer (it may
+ * be bigger than our buffer size). In that case, just
+ * skip it*/
+ if (headerlen >= ID3_V2_BUF_SIZE &&
+ headerlen < totalsize) {
+ /* Seek past this XXL frame and adjust all our
+ * counters accordingly */
+ int offset = headerlen - (size - readsize);
+ lseek(fd,offset,SEEK_CUR);
+ totalsize -= offset;
+ readsize=size;
+ }
+ break;
+ }
+
+
         
         /* Check for certain frame headers */
- if(!strncmp(header, "TPE1", strlen("TPE1")) ||
- !strncmp(header, "TP1", strlen("TP1"))) {
+ if(!artist && (
+ !strncmp(header, "TPE1", strlen("TPE1")) ||
+ !strncmp(header, "TP1", strlen("TP1")))) {
             readsize++;
             headerlen--;
- if(headerlen > (size - readsize))
- headerlen = (size - readsize);
- artist = buffer + readsize;
+ memcpy(entry_offset,buffer + readsize,headerlen);
+ artist = entry_offset;
             artistn = headerlen;
             readsize += headerlen;
- }
- else if(!strncmp(header, "TIT2", strlen("TIT2")) ||
- !strncmp(header, "TT2", strlen("TT2"))) {
+ /* Need to pad out headerlen so we can NULL terminate
+ * the string later */
+ entry_offset += headerlen+1;
+ }
+ else if(!title && (
+ !strncmp(header, "TIT2", strlen("TIT2")) ||
+ !strncmp(header, "TT2", strlen("TT2")))) {
             readsize++;
             headerlen--;
- if(headerlen > (size - readsize))
- headerlen = (size - readsize);
- title = buffer + readsize;
+ memcpy(entry_offset,buffer + readsize,headerlen);
+ title = entry_offset;
             titlen = headerlen;
             readsize += headerlen;
+ /* Need to pad out headerlen so we can NULL terminate
+ * the string later */
+ entry_offset += headerlen+1;
         }
- else if(!strncmp(header, "TALB", strlen("TALB"))) {
+ else if(!album &&
+ !strncmp(header, "TALB", strlen("TALB"))) {
             readsize++;
             headerlen--;
- if(headerlen > (size - readsize))
- headerlen = (size - readsize);
- album = buffer + readsize;
+ memcpy(entry_offset,buffer + readsize,headerlen);
+ album = entry_offset;
             albumn = headerlen;
             readsize += headerlen;
+ /* Need to pad out headerlen so we can NULL terminate
+ * the string later */
+ entry_offset += headerlen+1;
         }
- else if(!strncmp(header, "TRCK", strlen("TRCK"))) {
+ else if(!tracknum && !strncmp(header, "TRCK", strlen("TRCK"))) {
             readsize++;
             headerlen--;
- if(headerlen > (size - readsize))
- headerlen = (size - readsize);
- tracknum = buffer + readsize;
+ memcpy(entry_offset,buffer + readsize,headerlen);
+ tracknum = entry_offset;
             tracknumn = headerlen;
             readsize += headerlen;
+ /* Need to pad out headerlen so we can NULL terminate
+ * the string later */
+ entry_offset += headerlen+1;
         } else {
             readsize += headerlen;
         }
     }
-
+ }
     if(artist) {
         entry->artist = artist;
         artist[artistn]=0;
@@ -621,7 +715,7 @@
     entry->id3v2len = getid3v2len(fd);
     entry->tracknum = 0;
 
- if ( entry->id3v2len && entry->id3v2len <= sizeof( entry->id3v2buf ) )
+ if ( entry->id3v2len )
         setid3v2title(fd, entry);
     entry->length = getsonglength(fd, entry);
-------- End Patch --------

-- 
(defun my-sig()(interactive)(defun c(l)(if(cdddr l)(concat(concat(car l)\" \")
(c(cdr l)))(concat(car l)(cadr l)(caddr l))))(message (c (list \"Just\"
\"another\" emacs-program-name \"hacker\" \"-\" \"napier\" \"@\" \"pobox.com\"))))
(my-sig)



Page was last modified "Jan 10 2012" The Rockbox Crew
aaa