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

📄 id3.c

📁 mips上编译过的mpg 运行正常 环境:AU12
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	id3: ID3v2.3 and ID3v2.4 parsing (a relevant subset)	copyright 2006-2008 by the mpg123 project - free software under the terms of the LGPL 2.1	see COPYING and AUTHORS files in distribution or http://mpg123.org	initially written by Thomas Orgis*/#include "mpg123lib_intern.h"#include "id3.h"#include "debug.h"/* UTF support definitions */typedef void (*text_converter)(mpg123_string *sb, unsigned char* source, size_t len);static void convert_latin1  (mpg123_string *sb, unsigned char* source, size_t len);static void convert_utf16   (mpg123_string *sb, unsigned char* source, size_t len, int str_be);static void convert_utf16bom(mpg123_string *sb, unsigned char* source, size_t len);static void convert_utf16be (mpg123_string *sb, unsigned char* source, size_t len);static void convert_utf8    (mpg123_string *sb, unsigned char* source, size_t len);static const text_converter text_converters[4] = {	convert_latin1,	convert_utf16bom,	convert_utf16be,	convert_utf8};const int encoding_widths[4] = { 1, 2, 2, 1 };/* the code starts here... */static void null_id3_links(mpg123_handle *fr){	fr->id3v2.title  = NULL;	fr->id3v2.artist = NULL;	fr->id3v2.album  = NULL;	fr->id3v2.year   = NULL;	fr->id3v2.genre  = NULL;	fr->id3v2.comment = NULL;}void init_id3(mpg123_handle *fr){	fr->id3v2.version = 0; /* nothing there */	null_id3_links(fr);	fr->id3v2.comments     = 0;	fr->id3v2.comment_list = NULL;	fr->id3v2.texts    = 0;	fr->id3v2.text     = NULL;	fr->id3v2.extras   = 0;	fr->id3v2.extra    = NULL;}/* Managing of the text, comment and extra lists. *//* Initialize one element. */static void init_mpg123_text(mpg123_text *txt){	mpg123_init_string(&txt->text);	mpg123_init_string(&txt->description);	txt->id[0] = 0;	txt->id[1] = 0;	txt->id[2] = 0;	txt->id[3] = 0;	txt->lang[0] = 0;	txt->lang[1] = 0;	txt->lang[2] = 0;}/* Free memory of one element. */static void free_mpg123_text(mpg123_text *txt){	mpg123_free_string(&txt->text);	mpg123_free_string(&txt->description);}/* Free memory of whole list. */#define free_comment(mh) free_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))#define free_text(mh)    free_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))#define free_extra(mh)   free_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))static void free_id3_text(mpg123_text **list, size_t *size){	size_t i;	for(i=0; i<*size; ++i) free_mpg123_text(&((*list)[i]));	free(*list);	*list = NULL;	*size = 0;}/* Add items to the list. */#define add_comment(mh) add_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))#define add_text(mh)    add_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))#define add_extra(mh)   add_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))static mpg123_text *add_id3_text(mpg123_text **list, size_t *size){	mpg123_text *x = safe_realloc(*list, sizeof(mpg123_text)*(*size+1));	if(x == NULL) return NULL; /* bad */	*list  = x;	*size += 1;	init_mpg123_text(&((*list)[*size-1]));	return &((*list)[*size-1]); /* Return pointer to the added text. */}/* Remove the last item. */#define pop_comment(mh) pop_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))#define pop_text(mh)    pop_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))#define pop_extra(mh)   pop_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))static void pop_id3_text(mpg123_text **list, size_t *size){	mpg123_text *x;	if(*size < 1) return;	free_mpg123_text(&((*list)[*size-1]));	if(*size > 1)	{		x = safe_realloc(*list, sizeof(mpg123_text)*(*size-1));		if(x != NULL){ *list  = x; *size -= 1; }	}	else	{		free(*list);		*list = NULL;		*size = 0;	}}/* OK, back t the higher level functions. */void exit_id3(mpg123_handle *fr){	free_comment(fr);	free_extra(fr);	free_text(fr);}void reset_id3(mpg123_handle *fr){	exit_id3(fr);	init_id3(fr);}/* Set the id3v2.artist id3v2.title ... links to elements of the array. */void id3_link(mpg123_handle *fr){	size_t i;	mpg123_id3v2 *v2 = &fr->id3v2;	debug("linking ID3v2");	null_id3_links(fr);	for(i=0; i<v2->texts; ++i)	{		mpg123_text *entry = &v2->text[i];		if     (!strncmp("TIT2", entry->id, 4)) v2->title  = &entry->text;		else if(!strncmp("TALB", entry->id, 4)) v2->album  = &entry->text;		else if(!strncmp("TPE1", entry->id, 4)) v2->artist = &entry->text;		else if(!strncmp("TYER", entry->id, 4)) v2->year   = &entry->text;		else if(!strncmp("TCON", entry->id, 4)) v2->genre  = &entry->text;	}	for(i=0; i<v2->comments; ++i)	{		mpg123_text *entry = &v2->comment_list[i];		if(entry->description.fill == 0 || entry->description.p[0] == 0)		v2->comment = &entry->text;	}	/* When no generic comment found, use the last non-generic one. */	if(v2->comment == NULL && v2->comments > 0)	v2->comment = &v2->comment_list[v2->comments-1].text;}/*	Store any text in UTF8 encoding; preserve the zero string separator (I don't need strlen for the total size).	ID3v2 standard says that there should be one text frame of specific type per tag, and subsequent tags overwrite old values.	So, I always replace the text that may be stored already (perhaps with a list of zero-separated strings, though).*/void store_id3_text(mpg123_string *sb, char *source, size_t source_size, const int noquiet){	int encoding;	int bwidth;	if(!source_size)	{		debug("Empty id3 data!");		return;	}	encoding = source[0];	++source;	--source_size;	debug1("encoding: %i", encoding);	/* A note: ID3v2.3 uses UCS-2 non-variable 16bit encoding, v2.4 uses UTF16.	   UTF-16 uses a reserved/private range in UCS-2 to add the magic, so we just always treat it as UTF. */	if(encoding > 3)	{		if(noquiet) warning1("Unknown text encoding %d, assuming ISO8859-1 - I will probably screw a bit up!", encoding);		encoding = 0;	}	bwidth = encoding_widths[encoding];	/* Hack! I've seen a stray zero byte before BOM. Is that supposed to happen? */	while(source_size > bwidth && source[0] == 0)	{		--source_size;		++source;		debug("skipped leading zero");	}	if(source_size % bwidth)	{		/* When we need two bytes for a character, it's strange to have an uneven bytestream length. */		if(noquiet) warning2("Weird tag size %d for encoding %d - I will probably trim too early or something but I think the MP3 is broken.", (int)source_size, encoding);		source_size -= source_size % bwidth;	}	text_converters[encoding](sb, (unsigned char*)source, source_size);	if(sb->size) debug1("UTF-8 string (the first one): %s", sb->p);	else if(noquiet) error("unable to convert string to UTF-8 (out of memory, junk input?)!");}char *next_text(char* prev, int encoding, size_t limit){	char *text = prev;	unsigned long neednull = encoding_widths[encoding];	/* So I go lengths to find zero or double zero... */	while(text-prev < limit)	{		if(text[0] == 0)		{			if(neednull <= limit-(text-prev))			{				unsigned long i = 1;				for(; i<neednull; ++i) if(text[i] != 0) break;				if(i == neednull) /* found a null wide enough! */				{					text += neednull;					break;				}			}			else{ text = NULL; break; }		}		++text;	}	if(text-prev == limit) text = NULL;	return text;}static const char *enc_name(int enc){	switch(enc)	{		case 0:  return "Latin 1";		case 1:  return "UTF-16 BOM";		case 2:  return "UTF-16 BE";		case 3:  return "UTF-8";		default: return "unknown!";	}}static void process_text(mpg123_handle *fr, char *realdata, size_t realsize, char *id){	/* Text encoding          $xx */	/* The text (encoded) ... */	mpg123_text *t = add_text(fr);	if(VERBOSE4) fprintf(stderr, "Note: Storing text from %s encoding\n", enc_name(realdata[0]));	if(t == NULL)	{		if(NOQUIET) error("Unable to attach new text!");		return;	}	memcpy(t->id, id, 4);	store_id3_text(&t->text, realdata, realsize, NOQUIET);	if(VERBOSE4) fprintf(stderr, "Note: ID3v2 %c%c%c%c text frame: %s\n", id[0], id[1], id[2], id[3], t->text.p);}/* Store a new comment that perhaps is a RVA / RVA_ALBUM/AUDIOPHILE / RVA_MIX/RADIO one */static void process_comment(mpg123_handle *fr, char *realdata, size_t realsize, int rva_level, char *id){	/* Text encoding          $xx */	/* Language               $xx xx xx */	/* Short description (encoded!)      <text> $00 (00) */	/* Then the comment text (encoded) ... */	char  encoding = realdata[0];	char *lang    = realdata+1; /* I'll only use the 3 bytes! */	char *descr   = realdata+4;	char *text = NULL;	mpg123_text *xcom = NULL;	if(realsize < descr-realdata)	{		if(NOQUIET) error1("Invalid frame size of %lu (too small for anything).", (unsigned long)realsize);		return;	}	xcom = add_comment(fr);	if(VERBOSE4) fprintf(stderr, "Note: Storing comment from %s encoding\n", enc_name(realdata[0]));	if(xcom == NULL)	{		if(NOQUIET) error("Unable to attach new comment!");		return;	}	memcpy(xcom->lang, lang, 3);	memcpy(xcom->id, id, 4);	xcom->lang[3] = 0;	/* Now I can abuse a byte from lang for the encoding. */	descr[-1] = encoding;	/* Be careful with finding the end of description, I have to honor encoding here. */	text = next_text(descr, encoding, realsize-(descr-realdata));	if(text == NULL)	{		if(NOQUIET) error("No comment text / valid description?");		pop_comment(fr);		return;	}	store_id3_text(&xcom->description, descr-1, text-descr+1, NOQUIET);	text[-1] = encoding;	store_id3_text(&xcom->text, text-1, realsize+1-(text-realdata), NOQUIET);	if(VERBOSE4)	{		fprintf(stderr, "Note: ID3 comment desc: %s\n", xcom->description.fill > 0 ? xcom->description.p : "");		fprintf(stderr, "Note: ID3 comment text: %s\n", xcom->text.fill > 0 ? xcom->text.p : "");	}	if(xcom->description.fill > 0 && xcom->text.fill > 0)	{		int rva_mode = -1; /* mix / album */		if(   !strcasecmp(xcom->description.p, "rva")			 || !strcasecmp(xcom->description.p, "rva_mix")			 || !strcasecmp(xcom->description.p, "rva_track")			 || !strcasecmp(xcom->description.p, "rva_radio"))		rva_mode = 0;		else if(   !strcasecmp(xcom->description.p, "rva_album")						|| !strcasecmp(xcom->description.p, "rva_audiophile")						|| !strcasecmp(xcom->description.p, "rva_user"))		rva_mode = 1;		if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level))		{			fr->rva.gain[rva_mode] = atof(xcom->text.p);			if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]);			fr->rva.peak[rva_mode] = 0;			fr->rva.level[rva_mode] = rva_level;		}	}}void process_extra(mpg123_handle *fr, char* realdata, size_t realsize, int rva_level, char *id){	/* Text encoding          $xx */	/* Description        ... $00 (00) */	/* Text ... */	char encoding = realdata[0];	char *descr  = realdata+1; /* remember, the encoding is descr[-1] */	char *text;	mpg123_text *xex;	if(realsize < descr-realdata)	{		if(NOQUIET) error1("Invalid frame size of %lu (too small for anything).", (unsigned long)realsize);		return;	}	text = next_text(descr, encoding, realsize-(descr-realdata));	if(VERBOSE4) fprintf(stderr, "Note: Storing extra from %s encoding\n", enc_name(realdata[0]));	if(text == NULL)	{		if(NOQUIET) error("No extra frame text / valid description?");		return;	}	xex = add_extra(fr);	if(xex == NULL)	{		if(NOQUIET) error("Unable to attach new extra text!");		return;	}	memcpy(xex->id, id, 4);	store_id3_text(&xex->description, descr-1, text-descr+1, NOQUIET);	text[-1] = encoding;	store_id3_text(&xex->text, text-1, realsize-(text-realdata)+1, NOQUIET);	if(xex->description.fill > 0)	{		int is_peak = 0;		int rva_mode = -1; /* mix / album */		if(!strncasecmp(xex->description.p, "replaygain_track_",17))		{			debug("ID3v2: track gain/peak");			rva_mode = 0;			if(!strcasecmp(xex->description.p, "replaygain_track_peak")) is_peak = 1;			else if(strcasecmp(xex->description.p, "replaygain_track_gain")) rva_mode = -1;		}		else		if(!strncasecmp(xex->description.p, "replaygain_album_",17))		{			debug("ID3v2: album gain/peak");			rva_mode = 1;			if(!strcasecmp(xex->description.p, "replaygain_album_peak")) is_peak = 1;			else if(strcasecmp(xex->description.p, "replaygain_album_gain")) rva_mode = -1;		}		if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level))		{			if(xex->text.fill > 0)			{				if(is_peak)				{					fr->rva.peak[rva_mode] = atof(xex->text.p);					if(VERBOSE3) fprintf(stderr, "Note: RVA peak %fdB\n", fr->rva.peak[rva_mode]);				}				else				{					fr->rva.gain[rva_mode] = atof(xex->text.p);					if(VERBOSE3) fprintf(stderr, "Note: RVA gain %fdB\n", fr->rva.gain[rva_mode]);				}				fr->rva.level[rva_mode] = rva_level;			}		}	}}/* Make a ID3v2.3+ 4-byte ID from a ID3v2.2 3-byte ID   Note that not all frames survived to 2.4; the mapping goes to 2.3 .   A notable miss is the old RVA frame, which is very unspecific anyway.   This function returns -1 when a not known 3 char ID was encountered, 0 otherwise. */int promote_framename(mpg123_handle *fr, char *id) /* fr because of VERBOSE macros */{	size_t i;	char *old[] =	{		"COM",  "TAL",  "TBP",  "TCM",  "TCO",  "TCR",  "TDA",  "TDY",  "TEN",  "TFT",		"TIM",  "TKE",  "TLA",  "TLE",  "TMT",  "TOA",  "TOF",  "TOL",  "TOR",  "TOT",		"TP1",  "TP2",  "TP3",  "TP4",  "TPA",  "TPB",  "TRC",  "TDA",  "TRK",  "TSI",		"TSS",  "TT1",  "TT2",  "TT3",  "TXT",  "TXX",  "TYE"	};	char *new[] =	{		"COMM", "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDAT", "TDLY", "TENC", "TFLT",		"TIME", "TKEY", "TLAN", "TLEN", "TMED", "TOPE", "TOFN", "TOLY", "TORY", "TOAL",		"TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TSRC", "TRDA", "TRCK", "TSIZ",		"TSSE", "TIT1", "TIT2", "TIT3", "TEXT", "TXXX", "TYER"	};	for(i=0; i<sizeof(old)/sizeof(char*); ++i)	{		if(!strncmp(id, old[i], 3))		{			memcpy(id, new[i], 4);			if(VERBOSE3) fprintf(stderr, "Translated ID3v2.2 frame %s to %s\n", old[i], new[i]);			return 0;		}	}

⌨️ 快捷键说明

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