forked from len0rd/rockbox
ID3v2.3 treats the global unsynch flag in a silly way, so we have to unsynch the whole tag before we can parse the individual frames.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4188 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
32c66315c8
commit
219d52a86f
1 changed files with 79 additions and 26 deletions
105
firmware/id3.c
105
firmware/id3.c
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include "id3.h"
|
||||
#include "mp3data.h"
|
||||
#include "system.h"
|
||||
|
||||
#define UNSYNC(b0,b1,b2,b3) (((b0 & 0x7F) << (3*7)) | \
|
||||
((b1 & 0x7F) << (2*7)) | \
|
||||
|
|
@ -108,12 +109,13 @@ struct tag_resolver {
|
|||
int (*ppFunc)(struct mp3entry*, char* tag, int bufferpos);
|
||||
};
|
||||
|
||||
static int unsynchronize(char* tag, int len)
|
||||
static bool global_ff_found = false;
|
||||
|
||||
static int unsynchronize(char* tag, int len, bool *ff_found)
|
||||
{
|
||||
int i;
|
||||
unsigned char c;
|
||||
unsigned char *rp, *wp;
|
||||
bool ff_found = false;
|
||||
|
||||
wp = rp = tag;
|
||||
|
||||
|
|
@ -123,20 +125,76 @@ static int unsynchronize(char* tag, int len)
|
|||
write pointer */
|
||||
c = *rp++;
|
||||
*wp = c;
|
||||
if(ff_found) {
|
||||
if(*ff_found) {
|
||||
/* Increment the write pointer if it isn't an unsynch pattern */
|
||||
if(c != 0)
|
||||
wp++;
|
||||
ff_found = false;
|
||||
*ff_found = false;
|
||||
} else {
|
||||
if(c == 0xff)
|
||||
ff_found = true;
|
||||
*ff_found = true;
|
||||
wp++;
|
||||
}
|
||||
}
|
||||
return (int)wp - (int)tag;
|
||||
}
|
||||
|
||||
static int unsynchronize_frame(char* tag, int len)
|
||||
{
|
||||
bool ff_found = false;
|
||||
|
||||
return unsynchronize(tag, len, &ff_found);
|
||||
}
|
||||
|
||||
static int read_unsynched(int fd, void *buf, int len, bool reset)
|
||||
{
|
||||
int i;
|
||||
int rc;
|
||||
int remaining = len;
|
||||
char *wp;
|
||||
char *rp;
|
||||
|
||||
if(reset)
|
||||
global_ff_found = false;
|
||||
|
||||
wp = buf;
|
||||
|
||||
while(remaining) {
|
||||
rp = wp;
|
||||
rc = read(fd, rp, remaining);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
i = unsynchronize(wp, remaining, &global_ff_found);
|
||||
remaining -= i;
|
||||
wp += i;
|
||||
}
|
||||
|
||||
return len;
|
||||
};
|
||||
|
||||
static int skip_unsynched(int fd, int len, bool reset)
|
||||
{
|
||||
int rc;
|
||||
int remaining = len;
|
||||
int rlen;
|
||||
char buf[32];
|
||||
|
||||
if(reset)
|
||||
global_ff_found = false;
|
||||
|
||||
while(remaining) {
|
||||
rlen = MIN(sizeof(buf), (unsigned int)remaining);
|
||||
rc = read(fd, buf, rlen);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
|
||||
remaining -= unsynchronize(buf, rlen, &global_ff_found);
|
||||
}
|
||||
|
||||
return len;
|
||||
};
|
||||
|
||||
/* parse numeric value from string */
|
||||
static int parsetracknum( struct mp3entry* entry, char* tag, int bufferpos )
|
||||
{
|
||||
|
|
@ -365,6 +423,7 @@ static void setid3v2title(int fd, struct mp3entry *entry)
|
|||
bool unsynch = false;
|
||||
int data_length_ind;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
/* Bail out if the tag is shorter than 10 bytes */
|
||||
if(entry->id3v2len < 10)
|
||||
|
|
@ -433,7 +492,11 @@ static void setid3v2title(int fd, struct mp3entry *entry)
|
|||
|
||||
/* Read frame header and check length */
|
||||
if(version >= ID3_VER_2_3) {
|
||||
if(10 != read(fd, header, 10))
|
||||
if(global_unsynch && version <= ID3_VER_2_3)
|
||||
rc = read_unsynched(fd, header, 10, false);
|
||||
else
|
||||
rc = read(fd, header, 10);
|
||||
if(rc != 10)
|
||||
return;
|
||||
/* Adjust for the 10 bytes we read */
|
||||
size -= 10;
|
||||
|
|
@ -531,15 +594,20 @@ static void setid3v2title(int fd, struct mp3entry *entry)
|
|||
if( !*ptag && !memcmp( header, tr->tag, tr->tag_length ) ) {
|
||||
|
||||
/* found a tag matching one in tagList, and not yet filled */
|
||||
bytesread = read(fd, buffer + bufferpos, framelen);
|
||||
if(global_unsynch && version <= ID3_VER_2_3)
|
||||
bytesread = read_unsynched(fd, buffer + bufferpos,
|
||||
framelen, false);
|
||||
else
|
||||
bytesread = read(fd, buffer + bufferpos, framelen);
|
||||
|
||||
if( bytesread != framelen )
|
||||
return;
|
||||
|
||||
size -= bytesread;
|
||||
*ptag = buffer + bufferpos;
|
||||
|
||||
if(global_unsynch || unsynch)
|
||||
bytesread = unsynchronize(*ptag, bytesread);
|
||||
if(unsynch || (global_unsynch && version >= ID3_VER_2_4))
|
||||
bytesread = unsynchronize_frame(*ptag, bytesread);
|
||||
|
||||
unicode_munge( ptag, &bytesread );
|
||||
tag = *ptag;
|
||||
|
|
@ -555,23 +623,8 @@ static void setid3v2title(int fd, struct mp3entry *entry)
|
|||
/* no tag in tagList was found, or it was a repeat.
|
||||
skip it using the total size */
|
||||
|
||||
/* We may need to compensate for the unsynchronization scheme */
|
||||
if(global_unsynch && !data_length_ind) {
|
||||
bool ff_found = false;
|
||||
|
||||
for(i = 0;i < totframelen;i++) {
|
||||
unsigned char c;
|
||||
bytesread = read(fd, &c, 1);
|
||||
if(ff_found) {
|
||||
if(c == 0)
|
||||
/* Found an unsynch pattern, counting it */
|
||||
totframelen++;
|
||||
ff_found = false;
|
||||
} else {
|
||||
if(c == 0xff)
|
||||
ff_found = true;
|
||||
}
|
||||
}
|
||||
if(global_unsynch && version <= ID3_VER_2_3) {
|
||||
skip_unsynched(fd, totframelen, false);
|
||||
} else {
|
||||
if(data_length_ind)
|
||||
totframelen = data_length_ind;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue