📄 id3.c
字号:
static void setid3v2title( int fd, struct id3info *id3 )
{
int minframesize;
int size;
long bufferpos = 0, totframelen, framelen;
char header[10];
char tmp[4];
unsigned char version;
char *buffer = id3->id3v2buf;
int bytesread = 0;
int buffersize = sizeof(id3->id3v2buf);
unsigned char global_flags;
int flags;
int skip;
bool global_unsynch = false;
bool unsynch = false;
int data_length_ind;
int i;
int rc;
global_ff_found = false;
/* Bail out if the tag is shorter than 10 bytes */
if(id3->id3v2len < 10)
return;
/* Read the ID3 tag version from the header */
ide_lseek(fd, 0, SEEK_SET);
if(10 != ide_read(fd, header, 10))
return;
/* Get the total ID3 tag size */
size = id3->id3v2len - 10;
version = header[3];
switch ( version ) {
case 2:
version = ID3_VER_2_2;
minframesize = 8;
break;
case 3:
version = ID3_VER_2_3;
minframesize = 12;
break;
case 4:
version = ID3_VER_2_4;
minframesize = 12;
break;
default:
/* unsupported id3 version */
return;
}
id3->id3version = version;
id3->tracknum = id3->year = 0;
id3->genre = 0xff;
id3->title = id3->artist = id3->album = NULL;
global_flags = header[5];
/* Skip the extended header if it is present */
if(global_flags & 0x40) {
if(version == ID3_VER_2_3) {
if(10 != ide_read(fd, header, 10))
return;
/* The 2.3 extended header size doesn't include the following
data, so we have to find out the size by checking the flags.
Also, it is not unsynched. */
framelen = BYTES2INT(header[0], header[1], header[2], header[3]) +
BYTES2INT(header[6], header[7], header[8], header[9]);
flags = BYTES2INT(0, 0, header[4], header[5]);
if(flags & 0x8000)
framelen += 4; /* CRC */
ide_lseek(fd, framelen - 10, SEEK_CUR);
}
if(version >= ID3_VER_2_4) {
if(4 != ide_read(fd, header, 4))
return;
/* The 2.4 extended header size does include the entire header,
so here we can just skip it. This header is unsynched. */
framelen = UNSYNC(header[0], header[1],
header[2], header[3]);
ide_lseek(fd, framelen - 4, SEEK_CUR);
}
}
/* Is unsynchronization applied? */
if(global_flags & 0x80) {
global_unsynch = true;
}
/*
* We must have at least minframesize bytes left for the
* remaining frames to be interesting
*/
while (size >= minframesize && bufferpos < buffersize - 1) {
flags = 0;
/* Read frame header and check length */
if(version >= ID3_VER_2_3) {
if(global_unsynch && version <= ID3_VER_2_3)
rc = read_unsynched(fd, header, 10);
else
rc = ide_read(fd, header, 10);
if(rc != 10)
return;
/* Adjust for the 10 bytes we read */
size -= 10;
flags = BYTES2INT(0, 0, header[8], header[9]);
if (version >= ID3_VER_2_4) {
framelen = UNSYNC(header[4], header[5],
header[6], header[7]);
} else {
/* version .3 files don't use synchsafe ints for
* size */
framelen = BYTES2INT(header[4], header[5],
header[6], header[7]);
}
} else {
if(6 != ide_read(fd, header, 6))
return;
/* Adjust for the 6 bytes we read */
size -= 6;
framelen = BYTES2INT(0, header[3], header[4], header[5]);
}
/* Keep track of the total size */
totframelen = framelen;
DEBUGF("framelen = %d\n", framelen);
if(framelen == 0){
if (header[0] == 0 && header[1] == 0 && header[2] == 0)
return;
else
continue;
}
unsynch = false;
data_length_ind = 0;
if(flags)
{
skip = 0;
if (version >= ID3_VER_2_4) {
if(flags & 0x0040) { /* Grouping identity */
ide_lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
framelen--;
}
} else {
if(flags & 0x0020) { /* Grouping identity */
ide_lseek(fd, 1, SEEK_CUR); /* Skip 1 byte */
framelen--;
}
}
if(flags & 0x000c) /* Compression or encryption */
{
/* Skip it using the total size in case
it was truncated */
size -= totframelen;
ide_lseek(fd, totframelen, SEEK_CUR);
continue;
}
if(flags & 0x0002) /* Unsynchronization */
unsynch = true;
if (version >= ID3_VER_2_4) {
if(flags & 0x0001) { /* Data length indicator */
if(4 != ide_read(fd, tmp, 4))
return;
data_length_ind = UNSYNC(tmp[0], tmp[1], tmp[2], tmp[3]);
framelen -= 4;
}
}
}
/* If the frame is larger than the remaining buffer space we try
to read as much as would fit in the buffer */
if(framelen >= buffersize - bufferpos)
framelen = buffersize - bufferpos - 1;
DEBUGF("id3v2 frame: %.4s\n", header);
/* Check for certain frame headers
'size' is the amount of frame bytes remaining. We decrement it by
the amount of bytes we read. If we fail to read as many bytes as
we expect, we assume that we can't read from this file, and bail
out.
For each frame. we will iterate over the list of supported tags,
and read the tag into entry's buffer. All tags will be kept as
strings, for cases where a number won't do, e.g., YEAR: "circa
1765", "1790/1977" (composed/performed), "28 Feb 1969" TRACK:
"1/12", "1 of 12", GENRE: "Freeform genre name" Text is more
flexible, and as the main use of id3 data is to display it,
converting it to an int just means reconverting to display it, at a
runtime cost.
For tags that the current code does convert to ints, a post
processing function will be called via a pointer to function. */
for (i=0; i<TAGLIST_SIZE; i++) {
const struct tag_resolver* tr = &taglist[i];
// char** ptag = tr->offset ? (char**) (((char*)id3) + tr->offset)
// : NULL;
char** ptag = (char**) (((char*)id3) + tr->offset);
char* tag;
/* Only ID3_VER_2_2 uses frames with three-character names. */
if (((version == ID3_VER_2_2) && (tr->tag_length != 3))
|| ((version > ID3_VER_2_2) && (tr->tag_length != 4))) {
continue;
}
/* Note that parser functions sometimes set *ptag to NULL, so
* the "!*ptag" check here doesn't always have the desired
* effect. Should the parser functions (parsegenre in
* particular) be updated to handle the case of being called
* multiple times, or should the "*ptag" check be removed?
*/
if( (!ptag || !*ptag) && !memcmp( header, tr->tag, tr->tag_length ) ) {
/* found a tag matching one in tagList, and not yet filled */
tag = buffer + bufferpos;
if(global_unsynch && version <= ID3_VER_2_3)
bytesread = read_unsynched(fd, tag, framelen);
else
bytesread = ide_read(fd, tag, framelen);
if( bytesread != framelen )
return;
size -= bytesread;
if(unsynch || (global_unsynch && version >= ID3_VER_2_4))
bytesread = unsynchronize_frame(tag, bytesread);
unicode_munge( tag, &bytesread );
if (ptag)
*ptag = tag;
/* remove trailing spaces */
while ( bytesread > 0 && isspace(tag[bytesread-1]))
bytesread--;
tag[bytesread] = 0;
bufferpos += bytesread + 1;
if( tr->ppFunc )
bufferpos = tr->ppFunc(id3, tag, bufferpos);
break;
}
}
if( i == TAGLIST_SIZE ) {
/* no tag in tagList was found, or it was a repeat.
skip it using the total size */
if(global_unsynch && version <= ID3_VER_2_3) {
size -= skip_unsynched(fd, totframelen);
} else {
if(data_length_ind)
totframelen = data_length_ind;
size -= totframelen;
if( ide_lseek(fd, totframelen, SEEK_CUR) == -1 )
return;
}
}
}
}
int getid3info( int fd, struct id3info *id3 )
{
// int fd;
int v1found = false;
// fd = open(filename, O_RDONLY);
// if(-1 == fd)
// return true;
memset(id3, 0, sizeof(struct id3info));
id3->title = NULL;
id3->filesize = ide_filesize( fd );
id3->id3v2len = getid3v2len( fd );
id3->tracknum = 0;
id3->genre = 0xff;
// if(v1first)
// v1found = setid3v1title(fd, entry);
if (!v1found && id3->id3v2len)
setid3v2title(fd, id3);
// entry->length = getsonglength(fd, entry);
/* Subtract the meta information from the file size to get
the true size of the MP3 stream */
// entry->filesize -= entry->first_frame_offset;
/* only seek to end of file if no id3v2 tags were found,
and we already haven't looked for a v1 tag */
// if (!v1first && !entry->id3v2len) {
// setid3v1title(fd, entry);
// }
// close(fd);
// if(!entry->length || (entry->filesize < 8 ))
/* no song length or less than 8 bytes is hereby considered to be an
invalid mp3 and won't be played by us! */
// return true;
return id3->id3v2len;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -