⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 id3.c

📁 在linux环境下的MP3播放软件
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdlib.h>#include "config.h"#include "debug.h"#include "mpg123.h"#include "common.h"#include "stringbuf.h"#include "genre.h"#include "id3.h"struct taginfo{	unsigned char version; /* 1, 2 */	struct stringbuf title;	struct stringbuf artist;	struct stringbuf album;	struct stringbuf year; /* be ready for 20570! */	struct stringbuf comment;	struct stringbuf genre;};struct taginfo id3;void init_id3(){	id3.version = 0; /* nothing there */	init_stringbuf(&id3.title);	init_stringbuf(&id3.artist);	init_stringbuf(&id3.album);	init_stringbuf(&id3.year);	init_stringbuf(&id3.comment);	init_stringbuf(&id3.genre);}void exit_id3(){	free_stringbuf(&id3.title);	free_stringbuf(&id3.artist);	free_stringbuf(&id3.album);	free_stringbuf(&id3.year);	free_stringbuf(&id3.comment);	free_stringbuf(&id3.genre);}void reset_id3(){	id3.version = 0;	id3.title.fill = 0;	id3.artist.fill = 0;	id3.album.fill = 0;	id3.year.fill = 0;	id3.comment.fill = 0;	id3.genre.fill = 0;}void store_id3_text(struct stringbuf* sb, char* source, size_t source_size){	size_t pos = 1; /* skipping the encoding */	if(! source_size) return;	if(!(source[0] == 0 || source[0] == 3))	{		warning("Not ISO8859-1 or UTF8 encoding of text - I will probably screw a bit up!");	}	/*		first byte: Text encoding          $xx		Text fields store a list of strings terminated by null, whatever that is for the encoding.		That's not funny. Trying to work that by joining them into one string separated by line breaks...		...and assume a series of \0 being the separator for any encoding	*/	while(pos < source_size)	{		/* determine length of string, 0 will be stored, too */		size_t l = strlen(source+pos)+1;		if(pos+l > source_size) l = source_size - pos + 1; /* not null-terminated... */		if((sb->size >= sb->fill+l) || resize_stringbuf(sb, sb->fill+l))		{			/* append with line break */			if(sb->fill) sb->p[sb->fill-1] = '\n';			/* do not copy the ending 0 since it may not be there */			memcpy(sb->p+sb->fill, source+pos, l-1);			sb->fill += l;			sb->p[sb->fill-1] = 0;			/* advance to beginning of next string */			pos += l;			while(pos < source_size && source[pos] == 0)			{				/* an additonal null could mean that we are dealing with unicode... */				++pos;			}		}		else break;	}}/*	* trying to parse ID3v2.3 and ID3v2.4 tags... actually, for a start only v2.4 RVA2 frames	*	* returns:  0 = read-error	*          -1 = illegal ID3 header; maybe extended to mean unparseable (to new) header in future	*           1 = somehow ok...	*/int parse_new_id3(unsigned long first4bytes, struct reader *rds){	#define UNSYNC_FLAG 128	#define EXTHEAD_FLAG 64	#define EXP_FLAG 32	#define FOOTER_FLAG 16	#define UNKNOWN_FLAGS 15 /* 00001111*/	unsigned char buf[6];	unsigned long length=0;	unsigned char flags = 0;	int ret = 1;	unsigned char* tagdata = NULL;	unsigned char major = first4bytes & 0xff;	debug1("ID3v2: major tag version: %i", major);	if(major == 0xff) return -1;	if(!rds->read_frame_body(rds,buf,6))       /* read more header information */	return 0;	if(buf[0] == 0xff) /* major version, will never be 0xff */	return -1;	debug1("ID3v2: revision %i", buf[0]);	/* second new byte are some nice flags, if these are invalid skip the whole thing */	flags = buf[1];	debug1("ID3v2: flags 0x%08x", flags);	/* use 4 bytes from buf to construct 28bit uint value and return 1; return 0 if bytes are not syncsafe */	#define syncsafe_to_long(buf,res) \	( \		(((buf)[0]|(buf)[1]|(buf)[2]|(buf)[3]) & 0x80) ? 0 : \		(res =  (((unsigned long) (buf)[0]) << 27) \		     | (((unsigned long) (buf)[1]) << 14) \		     | (((unsigned long) (buf)[2]) << 7) \		     |  ((unsigned long) (buf)[3]) \		,1) \	)	/* length-10 or length-20 (footer present); 4 synchsafe integers == 28 bit number  */	/* we have already read 10 bytes, so left are length or length+10 bytes belonging to tag */	if(!syncsafe_to_long(buf+2,length)) return -1;	debug1("ID3v2: tag data length %lu", length);	/* skip if unknown version/scary flags, parse otherwise */	if((flags & UNKNOWN_FLAGS) || (major > 4))	{		/* going to skip because there are unknown flags set */		warning2("ID3v2: Won't parse the ID3v2 tag with major version %u and flags 0x%xu - some extra code may be needed", major, flags);		if(!rds->skip_bytes(rds,length)) /* will not store data in backbuff! */		ret = 0;	}	else	{		id3.version = major;		/* try to interpret that beast */		if((tagdata = (unsigned char*) malloc(length+1)) != NULL)		{			if(param.verbose > 1) fprintf(stderr, "ID3v2: analysing frames...\n");			if(rds->read_frame_body(rds,tagdata,length))			{				unsigned long tagpos = 0;				debug1("ID3v2: have read at all %lu bytes for the tag now", (unsigned long)length+6);				/* going to apply strlen for strings inside frames, make sure that it doesn't overflow! */				tagdata[length] = 0;				if(flags & EXTHEAD_FLAG)				{					if(param.verbose > 1) fprintf(stderr, "ID3v2: skipping extended header\n");					if(!syncsafe_to_long(tagdata, tagpos)) ret = -1;				}				if(ret >= 0)				{					char id[5];					unsigned long framesize;					unsigned long fflags; /* need 16 bits, actually */					id[4] = 0;					/* pos now advanced after ext head, now a frame has to follow */					while(tagpos < length-10) /* I want to read at least a full header */					{						int i = 0;						unsigned long pos = tagpos;						/* level 1,2,3 - 0 is info from lame/info tag! */						/* rva tags with ascending significance, then general frames */						#define KNOWN_FRAMES 8						const char frame_type[KNOWN_FRAMES][5] = { "COMM", "TXXX", "RVA2", "TPE1", "TALB", "TIT2", "TYER", "TCON" };						enum { egal = -1, comment, extra, rva2, artist, album, title, year, genre } tt = egal;						/* we may have entered the padding zone or any other strangeness: check if we have valid frame id characters */						for(; i< 4; ++i) if( !( ((tagdata[tagpos+i] > 47) && (tagdata[tagpos+i] < 58))						                     || ((tagdata[tagpos+i] > 64) && (tagdata[tagpos+i] < 91)) ) )						{							debug5("ID3v2: real tag data apparently ended after %lu bytes with 0x%02x%02x%02x%02x", tagpos, tagdata[tagpos], tagdata[tagpos+1], tagdata[tagpos+2], tagdata[tagpos+3]);							ret = -1;							break;						}						if(ret >= 0)						{							/* 4 bytes id */							strncpy(id, (char*) tagdata+pos, 4);							pos += 4;							/* size as 32 syncsafe bits */							if(!syncsafe_to_long(tagdata+pos, framesize))							{								ret = -1;								error("ID3v2: non-syncsafe frame size, aborting");								break;							}							if(param.verbose > 1) fprintf(stderr, "ID3v2: %s frame of size %lu\n", id, framesize);							tagpos += 10 + framesize; /* the important advancement in whole tag */							pos += 4;							fflags = (((unsigned long) tagdata[pos]) << 8) | ((unsigned long) tagdata[pos+1]);							pos += 2;							/* for sanity, after full parsing tagpos should be == pos */							/* debug4("ID3v2: found %s frame, size %lu (as bytes: 0x%08lx), flags 0x%016lx", id, framesize, framesize, fflags); */							/* %0abc0000 %0h00kmnp */							#define BAD_FFLAGS (unsigned long) 36784							#define PRES_TAG_FFLAG 16384							#define PRES_FILE_FFLAG 8192							#define READ_ONLY_FFLAG 4096							#define GROUP_FFLAG 64							#define COMPR_FFLAG 8							#define ENCR_FFLAG 4							#define UNSYNC_FFLAG 2							#define DATLEN_FFLAG 1							/* shall not or want not handle these */							if(fflags & (BAD_FFLAGS | COMPR_FFLAG | ENCR_FFLAG))							{								warning("ID3v2: skipping invalid/unsupported frame");								continue;							}														for(i = 0; i < KNOWN_FRAMES; ++i)							if(!strncmp(frame_type[i], id, 4)){ tt = i; break; }														if(tt != egal)							{								int rva_mode = -1; /* mix / album */								unsigned long realsize = framesize;								unsigned char* realdata = tagdata+pos;								if((flags & UNSYNC_FLAG) || (fflags & UNSYNC_FFLAG))								{									unsigned long ipos = 0;									unsigned long opos = 0;									debug("Id3v2: going to de-unsync the frame data");									/* de-unsync: FF00 -> FF; real FF00 is simply represented as FF0000 ... */									/* damn, that means I have to delete bytes from withing the data block... thus need temporal storage */									/* standard mandates that de-unsync should always be safe if flag is set */									realdata = (unsigned char*) malloc(framesize); /* will need <= bytes */									if(realdata == NULL)									{										error("ID3v2: unable to allocate working buffer for de-unsync");										continue;									}									/* now going byte per byte through the data... */									realdata[0] = tagdata[pos];									opos = 1;									for(ipos = pos+1; ipos < pos+framesize; ++ipos)									{										if(!((tagdata[ipos] == 0) && (tagdata[ipos-1] == 0xff)))										{											realdata[opos++] = tagdata[ipos];										}									}									realsize = opos;									debug2("ID3v2: de-unsync made %lu out of %lu bytes", realsize, framesize);								}								pos = 0; /* now at the beginning again... */								switch(tt)								{									case comment: /* a comment that perhaps is a RVA / RVA_ALBUM/AUDIOPHILE / RVA_MIX/RADIO one */									{										/* Text encoding          $xx */										/* Language               $xx xx xx */										/* policy about encodings: do not care for now here */										/* if(realdata[0] == 0)  */										{											/* don't care about language */											pos = 4;											if(   !strcasecmp((char*)realdata+pos, "rva")											   || !strcasecmp((char*)realdata+pos, "rva_mix")											   || !strcasecmp((char*)realdata+pos, "rva_radio"))											rva_mode = 0;											else if(   !strcasecmp((char*)realdata+pos, "rva_album")											        || !strcasecmp((char*)realdata+pos, "rva_audiophile")											        || !strcasecmp((char*)realdata+pos, "rva_user"))											rva_mode = 1;											if((rva_mode > -1) && (rva_level[rva_mode] <= tt+1))											{												char* comstr;												size_t comsize = realsize-4-(strlen((char*)realdata+pos)+1);												if(param.verbose > 1) fprintf(stderr, "ID3v2: evaluating %s data for RVA\n", realdata+pos);												if((comstr = (char*) malloc(comsize+1)) != NULL)												{													memcpy(comstr,realdata+realsize-comsize, comsize);													comstr[comsize] = 0;													rva_gain[rva_mode] = atof(comstr);													if(param.verbose > 1) fprintf(stderr, "ID3v2: RVA value %fdB\n", rva_gain[rva_mode]);													rva_peak[rva_mode] = 0;													rva_level[rva_mode] = tt+1;													free(comstr);												}												else error("could not allocate memory for rva comment interpretation");											}											else											{												if(!strcasecmp((char*)realdata+pos, ""))												{													/* only add general comments */													realdata[pos] = realdata[pos-4]; /* the encoding field copied */													store_id3_text(&id3.comment, (char*)realdata+pos, realsize-4);												}											}										}									}									break;									case extra: /* perhaps foobar2000's work */									{										/* Text encoding          $xx */										/* unicode would hurt in string comparison... */										if(realdata[0] == 0)										{											int is_peak = 0;											pos = 1;																						if(!strncasecmp((char*)realdata+pos, "replaygain_track_",17))											{												if(param.verbose > 1) fprintf(stderr, "ID3v2: track gain/peak\n");												rva_mode = 0;												if(!strcasecmp((char*)realdata+pos, "replaygain_track_peak")) is_peak = 1;												else if(strcasecmp((char*)realdata+pos, "replaygain_track_gain")) rva_mode = -1;											}											else											if(!strncasecmp((char*)realdata+pos, "replaygain_album_",17))											{												if(param.verbose > 1) fprintf(stderr, "ID3v2: album gain/peak\n");												rva_mode = 1;												if(!strcasecmp((char*)realdata+pos, "replaygain_album_peak")) is_peak = 1;												else if(strcasecmp((char*)realdata+pos, "replaygain_album_gain")) rva_mode = -1;											}											if((rva_mode > -1) && (rva_level[rva_mode] <= tt+1))											{												char* comstr;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -