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

📄 id3.c

📁 mpg123 是 MPEG 1.0/2.0/2.5 的实时播放软件
💻 C
📖 第 1 页 / 共 2 页
字号:
												/* two bytes adjustment, one byte for bits representing peak - n bytes for peak */												/* 16 bit signed integer = dB * 512 */												/* we already assume short being 16 bit */												rva_gain[rva_mode] = (float) ((((short) realdata[pos]) << 8) | ((short) realdata[pos+1])) / 512;												pos += 2;												if(param.verbose > 2) fprintf(stderr, "Note: RVA value %fdB\n", rva_gain[rva_mode]);												/* heh, the peak value is represented by a number of bits - but in what manner? Skipping that part */												rva_peak[rva_mode] = 0;												rva_level[rva_mode] = tt+1;											}										}										#else										warning("ID3v2: Cannot parse RVA2 value because I don't have a guaranteed 16 bit signed integer type");										#endif									}									break;									/* non-rva metainfo, simply store... */									case artist:										debug("ID3v2: parsing artist info");										store_id3_text(&id3.artist, (char*) realdata, realsize);									break;									case album:										debug("ID3v2: parsing album info");										store_id3_text(&id3.album, (char*) realdata, realsize);									break;									case title:										debug("ID3v2: parsing title info");										store_id3_text(&id3.title, (char*) realdata, realsize);									break;									case year:										debug("ID3v2: parsing year info");										store_id3_text(&id3.year, (char*) realdata, realsize);									break;									case genre:										debug("ID3v2: parsing genre info");										store_id3_text(&id3.genre, (char*) realdata, realsize);									break;									default: error1("ID3v2: unknown frame type %i", tt);								}								if((flags & UNSYNC_FLAG) || (fflags & UNSYNC_FFLAG)) free(realdata);							}							#undef BAD_FFLAGS							#undef PRES_TAG_FFLAG							#undef PRES_FILE_FFLAG							#undef READ_ONLY_FFLAG							#undef GROUP_FFLAG							#undef COMPR_FFLAG							#undef ENCR_FFLAG							#undef UNSYNC_FFLAG							#undef DATLEN_FFLAG						}						else break;						#undef KNOWN_FRAMES					}				}			}			else			{				error("ID3v2: Duh, not able to read ID3v2 tag data.");				ret = 0;			}			free(tagdata);		}		else		{			error1("ID3v2Arrg! Unable to allocate %lu bytes for interpreting ID3v2 data - trying to skip instead.", length);			if(!rds->skip_bytes(rds,length)) /* will not store data in backbuff! */			ret = 0;		}	}	/* skip footer if present */	if((flags & FOOTER_FLAG) && (!rds->skip_bytes(rds,length))) ret = 0;	return ret;	#undef UNSYNC_FLAG	#undef EXTHEAD_FLAG	#undef EXP_FLAG	#undef FOOTER_FLAG	#undef UNKOWN_FLAGS}void print_id3_tag(unsigned char *id3v1buf){	char genre_from_v1 = 0;	if(!(id3.version || id3v1buf)) return;	if(id3v1buf != NULL)	{		/* fill gaps in id3v2 info with id3v1 info */		struct id3tag {			char tag[3];			char title[30];			char artist[30];			char album[30];			char year[4];			char comment[30];			unsigned char genre;		};		struct id3tag *tag = (struct id3tag *) id3v1buf;		/* I _could_ skip the recalculation of fill ... */		if(!id3.title.fill)		{			if(id3.title.size >= 31 || resize_stringbuf(&id3.title, 31))			{				strncpy(id3.title.p,tag->title,30);				id3.title.p[30] = 0;				id3.title.fill = strlen(id3.title.p) + 1;			}		}		if(!id3.artist.fill)		{			if(id3.artist.size >= 31 || resize_stringbuf(&id3.artist,31))			{				strncpy(id3.artist.p,tag->artist,30);				id3.artist.p[30] = 0;				id3.artist.fill = strlen(id3.artist.p) + 1;			}		}		if(!id3.album.fill)		{			if(id3.album.size >= 31 || resize_stringbuf(&id3.album,31))			{				strncpy(id3.album.p,tag->album,30);				id3.album.p[30] = 0;				id3.album.fill = strlen(id3.album.p) + 1;			}		}		if(!id3.comment.fill)		{			if(id3.comment.size >= 31 || resize_stringbuf(&id3.comment,31))			{				strncpy(id3.comment.p,tag->comment,30);				id3.comment.p[30] = 0;				id3.comment.fill = strlen(id3.comment.p) + 1;			}		}		if(!id3.year.fill)		{			if(id3.year.size >= 5 || resize_stringbuf(&id3.year,5))			{				strncpy(id3.year.p,tag->year,4);				id3.year.p[4] = 0;				id3.year.fill = strlen(id3.year.p) + 1;			}		}		/*			genre is special... tag->genre holds an index, id3v2 genre may contain indices in textual form and raw textual genres...		*/		if(!id3.genre.fill)		{			if(id3.genre.size >= 31 || resize_stringbuf(&id3.genre,31))			{				if (tag->genre <= genre_count)				{					strncpy(id3.genre.p, genre_table[tag->genre], 30);				}				else				{					strncpy(id3.genre.p,"Unknown",30);				}				id3.genre.p[30] = 0;				id3.genre.fill = strlen(id3.genre.p) + 1;				genre_from_v1 = 1;			}		}	}		if(id3.genre.fill && !genre_from_v1)	{		/*			id3v2.3 says (id)(id)blabla and in case you want ot have (blabla) write ((blabla)			also, there is			(RX) Remix			(CR) Cover			id3v2.4 says			"one or several of the ID3v1 types as numerical strings"			or define your own (write strings), RX and CR 			Now I am very sure that I'll encounter hellishly mixed up id3v2 frames, so try to parse both at once.	 */		struct stringbuf tmp;		init_stringbuf(&tmp);		debug1("interpreting genre: %s\n", id3.genre.p);		if(copy_stringbuf(&id3.genre, &tmp))		{			size_t num = 0;			size_t nonum = 0;			size_t i;			enum { nothing, number, outtahere } state = nothing;			id3.genre.fill = 0; /* going to be refilled */			/* number\n -> id3v1 genre */			/* (number) -> id3v1 genre */			/* (( -> ( */			for(i = 0; i < tmp.fill; ++i)			{				debug1("i=%lu", (unsigned long) i);				switch(state)				{					case nothing:						nonum = i;						if(tmp.p[i] == '(')						{							num = i+1; /* number starting as next? */							state = number;							debug1("( before number at %lu?", (unsigned long) num);						}						/* you know an encoding where this doesn't work? */						else if(tmp.p[i] >= '0' && tmp.p[i] <= '9')						{							num = i;							state = number;							debug1("direct number at %lu", (unsigned long) num);						}						else state = outtahere;					break;					case number:						/* fake number alert: (( -> ( */						if(tmp.p[i] == '(')						{							nonum = i;							state = outtahere;							debug("no, it was ((");						}						else if(tmp.p[i] == ')' || tmp.p[i] == '\n' || tmp.p[i] == 0)						{							if(i-num > 0)							{								/* we really have a number */								int gid;								char* genre = "Unknown";								tmp.p[i] = 0;								gid = atoi(tmp.p+num);								/* get that genre */								if (gid >= 0 && gid <= genre_count) genre = genre_table[gid];								debug1("found genre: %s", genre);								if(id3.genre.fill) add_to_stringbuf(&id3.genre, ", ");								add_to_stringbuf(&id3.genre, genre);								nonum = i+1; /* next possible stuff */								state = nothing;								debug1("had a number: %i", gid);							}							else							{								/* wasn't a number, nonum is set */								state = outtahere;								debug("no (num) thing...");							}						}						else if(!(tmp.p[i] >= '0' && tmp.p[i] <= '9'))						{							/* no number at last... */							state = outtahere;							debug("nothing numeric here");						}						else						{							debug("still number...");						}					break;					default: break;				}				if(state == outtahere) break;			}			if(nonum < tmp.fill-1)			{				if(id3.genre.fill) add_to_stringbuf(&id3.genre, ", ");				add_to_stringbuf(&id3.genre, tmp.p+nonum);			}		}		free_stringbuf(&tmp);	}	if(param.long_id3)	{		fprintf(stderr,"\n");		/* print id3v2 */		/* dammed, I use pointers as bool again! It's so convenient... */		fprintf(stderr,"\tTitle:   %s\n", id3.title.fill ? id3.title.p : "");		fprintf(stderr,"\tArtist:  %s\n", id3.artist.fill ? id3.artist.p : "");		fprintf(stderr,"\tAlbum:   %s\n", id3.album.fill ? id3.album.p : "");		fprintf(stderr,"\tYear:    %s\n", id3.year.fill ? id3.year.p : "");		fprintf(stderr,"\tGenre:   %s\n", id3.genre.fill ? id3.genre.p : "");		fprintf(stderr,"\tComment: %s\n", id3.comment.fill ? id3.comment.p : "");		fprintf(stderr,"\n");	}	else	{		/* We are trying to be smart here and conserve vertical space.		   So we will skip tags not set, and try to show them in two parallel columns if they are short, which is by far the	most common case. */		/* one _could_ circumvent the strlen calls... */		if(id3.title.fill && id3.artist.fill && strlen(id3.title.p) <= 30 && strlen(id3.title.p) <= 30)		{			fprintf(stderr,"Title:   %-30s  Artist: %s\n",id3.title.p,id3.artist.p);		}		else		{			if(id3.title.fill) fprintf(stderr,"Title:   %s\n", id3.title.p);			if(id3.artist.fill) fprintf(stderr,"Artist:  %s\n", id3.artist.p);		}		if (id3.comment.fill && id3.album.fill && strlen(id3.comment.p) <= 30 && strlen(id3.album.p) <= 30)		{			fprintf(stderr,"Comment: %-30s  Album:  %s\n",id3.comment.p,id3.album.p);		}		else		{			if (id3.comment.fill)				fprintf(stderr,"Comment: %s\n", id3.comment.p);			if (id3.album.fill)				fprintf(stderr,"Album:   %s\n", id3.album.p);		}		if (id3.year.fill && id3.genre.fill && strlen(id3.year.p) <= 30 && strlen(id3.genre.p) <= 30)		{			fprintf(stderr,"Year:    %-30s  Genre:  %s\n",id3.year.p,id3.genre.p);		}		else		{			if (id3.year.fill)				fprintf(stderr,"Year:    %s\n", id3.year.p);			if (id3.genre.fill)				fprintf(stderr,"Genre:   %s\n", id3.genre.p);		}	}}/*	Preliminary UTF support routines	Text decoder decodes the ID3 text content from whatever encoding to ISO-8859-1 or ASCII, substituting unconvertable characters with '*' and returning the final length of decoded string.	TODO: iconv() to whatever locale. But we will want to keep this code anyway for systems w/o iconv(). But we currently assume that it is enough to allocate @len bytes in dest. That might not be true when converting to Unicode encodings.*/static int decode_il1(char* dest, unsigned char* source, size_t len){	memcpy(dest, source, len);	return len;}static int decode_utf16(char* dest, unsigned char* source, size_t len, int str_be){	int spos = 0;	int dlen = 0;	len -= len % 2;	/* Just ASCII, we take it easy. */	for (; spos < len; spos += 2)	{		unsigned short word;		if(str_be) word = source[spos] << 8 | source[spos+1];		else word = source[spos] | source[spos+1] << 8;		/* utf16 continuation byte */		if(word & 0xdc00) continue;		/* utf16 out-of-range codepoint */		else if(word > 255) dest[dlen++] = '*';		/* an old-school character */		else dest[dlen++] = word; /* would a cast be good here? */	}	return dlen;}static int decode_utf16bom(char* dest, unsigned char* source, size_t len){	if(len < 2) return 0;	if(source[0] == 0xFF && source[1] == 0xFE) /* Little-endian */	return decode_utf16(dest, source + 2, len - 2, 0);	else /* Big-endian */	return decode_utf16(dest, source + 2, len - 2, 1);}static int decode_utf16be(char* dest, unsigned char* source, size_t len){	return decode_utf16(dest, source, len, 1);}static int decode_utf8(char* dest, unsigned char* source, size_t len){	int spos = 0;	int dlen = 0;	/* Just ASCII, we take it easy. */	for(; spos < len; spos++)	{		/* utf8 continuation byte bo, lead!*/		if(source[spos] & 0xc0) continue;		/* utf8 lead byte, no, cont! */		else if(source[spos] & 0x80) dest[dlen++] = '*';		else dest[dlen++] = source[spos];	}	return dlen;}/* determine byte length of string with characters wide @width;   terminating 0 will be included, too, if there is any */int wide_bytelen(int width, char* string, size_t string_size){	size_t l = 0;	while(l < string_size)	{		int b;		for(b = 0; b < width; b++)		if(string[l + b])		break;		l += width;		if(b == width) /* terminating zero */		return l;	}	return l;}

⌨️ 快捷键说明

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