Blame src/libmpg123/id3.c

Packit c32a2d
/*
Packit c32a2d
	id3: ID3v2.3 and ID3v2.4 parsing (a relevant subset)
Packit c32a2d
Packit c32a2d
	copyright 2006-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Thomas Orgis
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "mpg123lib_intern.h"
Packit c32a2d
#include "id3.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
#ifndef NO_ID3V2 /* Only the main parsing routine will always be there. */
Packit c32a2d
Packit c32a2d
/* We know the usual text frames plus some specifics. */
Packit c32a2d
#define KNOWN_FRAMES 5
Packit c32a2d
static const char frame_type[KNOWN_FRAMES][5] = { "COMM", "TXXX", "RVA2", "USLT", "APIC" };
Packit c32a2d
enum frame_types { unknown = -2, text = -1, comment, extra, rva2, uslt, picture };
Packit c32a2d
Packit c32a2d
/* UTF support definitions */
Packit c32a2d
Packit c32a2d
typedef void (*text_converter)(mpg123_string *sb, const unsigned char* source, size_t len, const int noquiet);
Packit c32a2d
Packit c32a2d
static void convert_latin1  (mpg123_string *sb, const unsigned char* source, size_t len, const int noquiet);
Packit c32a2d
static void convert_utf16bom(mpg123_string *sb, const unsigned char* source, size_t len, const int noquiet);
Packit c32a2d
static void convert_utf8    (mpg123_string *sb, const unsigned char* source, size_t len, const int noquiet);
Packit c32a2d
Packit c32a2d
static const text_converter text_converters[4] =
Packit c32a2d
{
Packit c32a2d
	convert_latin1,
Packit c32a2d
	/* We always check for (multiple) BOM in 16bit unicode. Without BOM, UTF16 BE is the default.
Packit c32a2d
	   Errors in encoding are detected anyway. */
Packit c32a2d
	convert_utf16bom,
Packit c32a2d
	convert_utf16bom,
Packit c32a2d
	convert_utf8
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
static const unsigned int encoding_widths[4] = { 1, 2, 2, 1 };
Packit c32a2d
Packit c32a2d
/* the code starts here... */
Packit c32a2d
Packit c32a2d
static void null_id3_links(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	fr->id3v2.title  = NULL;
Packit c32a2d
	fr->id3v2.artist = NULL;
Packit c32a2d
	fr->id3v2.album  = NULL;
Packit c32a2d
	fr->id3v2.year   = NULL;
Packit c32a2d
	fr->id3v2.genre  = NULL;
Packit c32a2d
	fr->id3v2.comment = NULL;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void init_id3(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	fr->id3v2.version = 0; /* nothing there */
Packit c32a2d
	null_id3_links(fr);
Packit c32a2d
	fr->id3v2.comments     = 0;
Packit c32a2d
	fr->id3v2.comment_list = NULL;
Packit c32a2d
	fr->id3v2.texts    = 0;
Packit c32a2d
	fr->id3v2.text     = NULL;
Packit c32a2d
	fr->id3v2.extras   = 0;
Packit c32a2d
	fr->id3v2.extra    = NULL;
Packit c32a2d
	fr->id3v2.pictures   = 0;
Packit c32a2d
	fr->id3v2.picture    = NULL;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Managing of the text, comment and extra lists. */
Packit c32a2d
Packit c32a2d
/* Initialize one element. */
Packit c32a2d
static void init_mpg123_text(mpg123_text *txt)
Packit c32a2d
{
Packit c32a2d
	mpg123_init_string(&txt->text);
Packit c32a2d
	mpg123_init_string(&txt->description);
Packit c32a2d
	txt->id[0] = 0;
Packit c32a2d
	txt->id[1] = 0;
Packit c32a2d
	txt->id[2] = 0;
Packit c32a2d
	txt->id[3] = 0;
Packit c32a2d
	txt->lang[0] = 0;
Packit c32a2d
	txt->lang[1] = 0;
Packit c32a2d
	txt->lang[2] = 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void init_mpg123_picture(mpg123_picture *pic)
Packit c32a2d
{
Packit c32a2d
	mpg123_init_string(&pic->mime_type);
Packit c32a2d
	mpg123_init_string(&pic->description);
Packit c32a2d
	pic->type = 0;
Packit c32a2d
	pic->size = 0;
Packit c32a2d
	pic->data = NULL;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Free memory of one element. */
Packit c32a2d
static void free_mpg123_text(mpg123_text *txt)
Packit c32a2d
{
Packit c32a2d
	mpg123_free_string(&txt->text);
Packit c32a2d
	mpg123_free_string(&txt->description);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void free_mpg123_picture(mpg123_picture * pic)
Packit c32a2d
{
Packit c32a2d
	mpg123_free_string(&pic->mime_type);
Packit c32a2d
	mpg123_free_string(&pic->description);
Packit c32a2d
	if (pic->data != NULL)
Packit c32a2d
		free(pic->data);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Free memory of whole list. */
Packit c32a2d
#define free_comment(mh) free_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))
Packit c32a2d
#define free_text(mh)    free_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))
Packit c32a2d
#define free_extra(mh)   free_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))
Packit c32a2d
#define free_picture(mh) free_id3_picture(&((mh)->id3v2.picture),   &((mh)->id3v2.pictures))
Packit c32a2d
static void free_id3_text(mpg123_text **list, size_t *size)
Packit c32a2d
{
Packit c32a2d
	size_t i;
Packit c32a2d
	for(i=0; i<*size; ++i) free_mpg123_text(&((*list)[i]));
Packit c32a2d
Packit c32a2d
	free(*list);
Packit c32a2d
	*list = NULL;
Packit c32a2d
	*size = 0;
Packit c32a2d
}
Packit c32a2d
static void free_id3_picture(mpg123_picture **list, size_t *size)
Packit c32a2d
{
Packit c32a2d
	size_t i;
Packit c32a2d
	for(i=0; i<*size; ++i) free_mpg123_picture(&((*list)[i]));
Packit c32a2d
Packit c32a2d
	free(*list);
Packit c32a2d
	*list = NULL;
Packit c32a2d
	*size = 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Add items to the list. */
Packit c32a2d
#define add_comment(mh) add_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))
Packit c32a2d
#define add_text(mh)    add_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))
Packit c32a2d
#define add_extra(mh)   add_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))
Packit c32a2d
#define add_picture(mh)   add_id3_picture(&((mh)->id3v2.picture),       &((mh)->id3v2.pictures))
Packit c32a2d
static mpg123_text *add_id3_text(mpg123_text **list, size_t *size)
Packit c32a2d
{
Packit c32a2d
	mpg123_text *x = safe_realloc(*list, sizeof(mpg123_text)*(*size+1));
Packit c32a2d
	if(x == NULL) return NULL; /* bad */
Packit c32a2d
Packit c32a2d
	*list  = x;
Packit c32a2d
	*size += 1;
Packit c32a2d
	init_mpg123_text(&((*list)[*size-1]));
Packit c32a2d
Packit c32a2d
	return &((*list)[*size-1]); /* Return pointer to the added text. */
Packit c32a2d
}
Packit c32a2d
static mpg123_picture *add_id3_picture(mpg123_picture **list, size_t *size)
Packit c32a2d
{
Packit c32a2d
	mpg123_picture *x = safe_realloc(*list, sizeof(mpg123_picture)*(*size+1));
Packit c32a2d
	if(x == NULL) return NULL; /* bad */
Packit c32a2d
Packit c32a2d
	*list  = x;
Packit c32a2d
	*size += 1;
Packit c32a2d
	init_mpg123_picture(&((*list)[*size-1]));
Packit c32a2d
Packit c32a2d
	return &((*list)[*size-1]); /* Return pointer to the added picture. */
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* Remove the last item. */
Packit c32a2d
#define pop_comment(mh) pop_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))
Packit c32a2d
#define pop_text(mh)    pop_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))
Packit c32a2d
#define pop_extra(mh)   pop_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))
Packit c32a2d
#define pop_picture(mh)   pop_id3_picture(&((mh)->id3v2.picture),       &((mh)->id3v2.pictures))
Packit c32a2d
static void pop_id3_text(mpg123_text **list, size_t *size)
Packit c32a2d
{
Packit c32a2d
	mpg123_text *x;
Packit c32a2d
	if(*size < 1) return;
Packit c32a2d
Packit c32a2d
	free_mpg123_text(&((*list)[*size-1]));
Packit c32a2d
	if(*size > 1)
Packit c32a2d
	{
Packit c32a2d
		x = safe_realloc(*list, sizeof(mpg123_text)*(*size-1));
Packit c32a2d
		if(x != NULL){ *list  = x; *size -= 1; }
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		free(*list);
Packit c32a2d
		*list = NULL;
Packit c32a2d
		*size = 0;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
static void pop_id3_picture(mpg123_picture **list, size_t *size)
Packit c32a2d
{
Packit c32a2d
	mpg123_picture *x;
Packit c32a2d
	if(*size < 1) return;
Packit c32a2d
Packit c32a2d
	free_mpg123_picture(&((*list)[*size-1]));
Packit c32a2d
	if(*size > 1)
Packit c32a2d
	{
Packit c32a2d
		x = safe_realloc(*list, sizeof(mpg123_picture)*(*size-1));
Packit c32a2d
		if(x != NULL){ *list  = x; *size -= 1; }
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		free(*list);
Packit c32a2d
		*list = NULL;
Packit c32a2d
		*size = 0;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* OK, back to the higher level functions. */
Packit c32a2d
Packit c32a2d
void exit_id3(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	free_picture(fr);
Packit c32a2d
	free_comment(fr);
Packit c32a2d
	free_extra(fr);
Packit c32a2d
	free_text(fr);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void reset_id3(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	exit_id3(fr);
Packit c32a2d
	init_id3(fr);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Set the id3v2.artist id3v2.title ... links to elements of the array. */
Packit c32a2d
void id3_link(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	size_t i;
Packit c32a2d
	mpg123_id3v2 *v2 = &fr->id3v2;
Packit c32a2d
	debug("linking ID3v2");
Packit c32a2d
	null_id3_links(fr);
Packit c32a2d
	for(i=0; i<v2->texts; ++i)
Packit c32a2d
	{
Packit c32a2d
		mpg123_text *entry = &v2->text[i];
Packit c32a2d
		if     (!strncmp("TIT2", entry->id, 4)) v2->title  = &entry->text;
Packit c32a2d
		else if(!strncmp("TALB", entry->id, 4)) v2->album  = &entry->text;
Packit c32a2d
		else if(!strncmp("TPE1", entry->id, 4)) v2->artist = &entry->text;
Packit c32a2d
		else if(!strncmp("TYER", entry->id, 4)) v2->year   = &entry->text;
Packit c32a2d
		else if(!strncmp("TCON", entry->id, 4)) v2->genre  = &entry->text;
Packit c32a2d
	}
Packit c32a2d
	for(i=0; i<v2->comments; ++i)
Packit c32a2d
	{
Packit c32a2d
		mpg123_text *entry = &v2->comment_list[i];
Packit c32a2d
		if(entry->description.fill == 0 || entry->description.p[0] == 0)
Packit c32a2d
		v2->comment = &entry->text;
Packit c32a2d
	}
Packit c32a2d
	/* When no generic comment found, use the last non-generic one. */
Packit c32a2d
	if(v2->comment == NULL && v2->comments > 0)
Packit c32a2d
	v2->comment = &v2->comment_list[v2->comments-1].text;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	Store ID3 text data in an mpg123_string; either verbatim copy or everything translated to UTF-8 encoding.
Packit c32a2d
	Preserve the zero string separator (I don't need strlen for the total size).
Packit c32a2d
Packit c32a2d
	ID3v2 standard says that there should be one text frame of specific type per tag, and subsequent tags overwrite old values.
Packit c32a2d
	So, I always replace the text that may be stored already (perhaps with a list of zero-separated strings, though).
Packit c32a2d
*/
Packit c32a2d
static void store_id3_text(mpg123_string *sb, unsigned char *source, size_t source_size, const int noquiet, const int notranslate)
Packit c32a2d
{
Packit c32a2d
	unsigned char encoding;
Packit c32a2d
	if(!source_size)
Packit c32a2d
	{
Packit c32a2d
		debug("Empty id3 data!");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* We shall just copy the data. Client wants to decode itself. */
Packit c32a2d
	if(notranslate)
Packit c32a2d
	{
Packit c32a2d
		/* Future: Add a path for ID3 errors. */
Packit c32a2d
		if(!mpg123_resize_string(sb, source_size))
Packit c32a2d
		{
Packit c32a2d
			if(noquiet) error("Cannot resize target string, out of memory?");
Packit c32a2d
			return;
Packit c32a2d
		}
Packit c32a2d
		memcpy(sb->p, source, source_size);
Packit c32a2d
		sb->fill = source_size;
Packit c32a2d
		debug1("stored undecoded ID3 text of size %"SIZE_P, (size_p)source_size);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	encoding = source[0];
Packit c32a2d
	if(encoding > mpg123_id3_enc_max)
Packit c32a2d
	{
Packit c32a2d
		if(noquiet)
Packit c32a2d
			error1("Unknown text encoding %u, I take no chances, sorry!", encoding);
Packit c32a2d
Packit c32a2d
		mpg123_free_string(sb);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	id3_to_utf8(sb, encoding, source+1, source_size-1, noquiet);
Packit c32a2d
Packit c32a2d
	if(sb->fill) debug1("UTF-8 string (the first one): %s", sb->p);
Packit c32a2d
	else if(noquiet) error("unable to convert string to UTF-8 (out of memory, junk input?)!");
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* On error, sb->size is 0. */
Packit c32a2d
/* Also, encoding has been checked already! */
Packit c32a2d
void id3_to_utf8(mpg123_string *sb, unsigned char encoding, const unsigned char *source, size_t source_size, int noquiet)
Packit c32a2d
{
Packit c32a2d
	unsigned int bwidth;
Packit c32a2d
	debug1("encoding: %u", encoding);
Packit c32a2d
	/* A note: ID3v2.3 uses UCS-2 non-variable 16bit encoding, v2.4 uses UTF16.
Packit c32a2d
	   UTF-16 uses a reserved/private range in UCS-2 to add the magic, so we just always treat it as UTF. */
Packit c32a2d
	bwidth = encoding_widths[encoding];
Packit c32a2d
	/* Hack! I've seen a stray zero byte before BOM. Is that supposed to happen? */
Packit c32a2d
	if(encoding != mpg123_id3_utf16be) /* UTF16be _can_ beging with a null byte! */
Packit c32a2d
	while(source_size > bwidth && source[0] == 0)
Packit c32a2d
	{
Packit c32a2d
		--source_size;
Packit c32a2d
		++source;
Packit c32a2d
		debug("skipped leading zero");
Packit c32a2d
	}
Packit c32a2d
	if(source_size % bwidth)
Packit c32a2d
	{
Packit c32a2d
		/* When we need two bytes for a character, it's strange to have an uneven bytestream length. */
Packit c32a2d
		if(noquiet) warning2("Weird tag size %d for encoding %u - I will probably trim too early or something but I think the MP3 is broken.", (int)source_size, encoding);
Packit c32a2d
		source_size -= source_size % bwidth;
Packit c32a2d
	}
Packit c32a2d
	text_converters[encoding](sb, source, source_size, noquiet);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* You have checked encoding to be in the range already. */
Packit c32a2d
static unsigned char *next_text(unsigned char* prev, unsigned char encoding, size_t limit)
Packit c32a2d
{
Packit c32a2d
	unsigned char *text = prev;
Packit c32a2d
	size_t width = encoding_widths[encoding];
Packit c32a2d
Packit c32a2d
	/* So I go lengths to find zero or double zero...
Packit c32a2d
	   Remember bug 2834636: Only check for aligned NULLs! */
Packit c32a2d
	while(text-prev < (ssize_t)limit)
Packit c32a2d
	{
Packit c32a2d
		if(text[0] == 0)
Packit c32a2d
		{
Packit c32a2d
			if(width <= limit-(text-prev))
Packit c32a2d
			{
Packit c32a2d
				size_t i = 1;
Packit c32a2d
				for(; i
Packit c32a2d
Packit c32a2d
				if(i == width) /* found a null wide enough! */
Packit c32a2d
				{
Packit c32a2d
					text += width;
Packit c32a2d
					break;
Packit c32a2d
				}
Packit c32a2d
			}
Packit c32a2d
			else return NULL; /* No full character left? This text is broken */
Packit c32a2d
		}
Packit c32a2d
Packit c32a2d
		text += width;
Packit c32a2d
	}
Packit c32a2d
	if((size_t)(text-prev) >= limit) text = NULL;
Packit c32a2d
Packit c32a2d
	return text;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static const char *enc_name(unsigned char enc)
Packit c32a2d
{
Packit c32a2d
	switch(enc)
Packit c32a2d
	{
Packit c32a2d
		case 0:  return "Latin 1";
Packit c32a2d
		case 1:  return "UTF-16 BOM";
Packit c32a2d
		case 2:  return "UTF-16 BE";
Packit c32a2d
		case 3:  return "UTF-8";
Packit c32a2d
		default: return "unknown!";
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void process_text(mpg123_handle *fr, unsigned char *realdata, size_t realsize, char *id)
Packit c32a2d
{
Packit c32a2d
	/* Text encoding          $xx */
Packit c32a2d
	/* The text (encoded) ... */
Packit c32a2d
	mpg123_text *t = add_text(fr);
Packit c32a2d
	if(VERBOSE4) fprintf(stderr, "Note: Storing text from %s encoding\n", enc_name(realdata[0]));
Packit c32a2d
	if(t == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("Unable to attach new text!");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	memcpy(t->id, id, 4);
Packit c32a2d
	store_id3_text(&t->text, realdata, realsize, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
Packit c32a2d
	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);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void process_picture(mpg123_handle *fr, unsigned char *realdata, size_t realsize)
Packit c32a2d
{
Packit c32a2d
	unsigned char encoding = realdata[0];
Packit c32a2d
	mpg123_picture *i = NULL;
Packit c32a2d
	unsigned char* workpoint;
Packit c32a2d
	if(realsize == 0)
Packit c32a2d
	{
Packit c32a2d
		debug("Empty id3 data!");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	if(encoding > mpg123_id3_enc_max)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET)
Packit c32a2d
			error1("Unknown text encoding %u, I take no chances, sorry!", encoding);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	if(VERBOSE4) fprintf(stderr, "Note: Storing picture from APIC frame.\n");
Packit c32a2d
	/* decompose realdata accordingly */
Packit c32a2d
	i = add_picture(fr);
Packit c32a2d
	if(i == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("Unable to attach new picture!");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	realdata++; realsize--;
Packit c32a2d
	/* get mime type (encoding is always latin-1) */
Packit c32a2d
	workpoint = next_text(realdata, 0, realsize);
Packit c32a2d
	if (workpoint == NULL) {
Packit c32a2d
		pop_picture(fr);
Packit c32a2d
		if (NOQUIET) error("Unable to get mime type for picture; skipping picture.");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	id3_to_utf8(&i->mime_type, 0, realdata, workpoint - realdata, NOQUIET);
Packit c32a2d
	realsize -= workpoint - realdata;
Packit c32a2d
	realdata = workpoint;
Packit c32a2d
	/* get picture type */
Packit c32a2d
	i->type = realdata[0];
Packit c32a2d
	realdata++; realsize--;
Packit c32a2d
	/* get description (encoding is encoding) */
Packit c32a2d
	workpoint = next_text(realdata, encoding, realsize);
Packit c32a2d
	if (workpoint == NULL) {
Packit c32a2d
		if (NOQUIET) error("Unable to get description for picture; skipping picture.");
Packit c32a2d
		pop_picture(fr);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	id3_to_utf8(&i->description, encoding, realdata, workpoint - realdata, NOQUIET);
Packit c32a2d
	realsize -= workpoint - realdata;
Packit c32a2d
	if (realsize == 0) {
Packit c32a2d
		if (NOQUIET) error("No picture data defined; skipping picture.");
Packit c32a2d
		pop_picture(fr);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	/* store_id3_picture(i, picture, realsize, NOQUIET)) */
Packit c32a2d
	i->data = (unsigned char*)malloc(realsize);
Packit c32a2d
	if (i->data == NULL) {
Packit c32a2d
		if (NOQUIET) error("Unable to allocate memory for picture; skipping picture");
Packit c32a2d
		pop_picture(fr);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	memcpy(i->data, workpoint, realsize);
Packit c32a2d
	i->size = realsize;
Packit c32a2d
	if(VERBOSE4) fprintf(stderr, "Note: ID3v2 APIC picture frame of type: %d\n", i->type);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Store a new comment that perhaps is a RVA / RVA_ALBUM/AUDIOPHILE / RVA_MIX/RADIO one
Packit c32a2d
   Special gimmik: It also stores USLT to the texts. Stucture is the same as for comments. */
Packit c32a2d
static void process_comment(mpg123_handle *fr, enum frame_types tt, unsigned char *realdata, size_t realsize, int rva_level, char *id)
Packit c32a2d
{
Packit c32a2d
	/* Text encoding          $xx */
Packit c32a2d
	/* Language               $xx xx xx */
Packit c32a2d
	/* Short description (encoded!)      <text> $00 (00) */
Packit c32a2d
	/* Then the comment text (encoded) ... */
Packit c32a2d
	unsigned char  encoding = realdata[0];
Packit c32a2d
	unsigned char *lang     = realdata+1; /* I'll only use the 3 bytes! */
Packit c32a2d
	unsigned char *descr    = realdata+4;
Packit c32a2d
	unsigned char *text     = NULL;
Packit c32a2d
	mpg123_text *xcom = NULL;
Packit c32a2d
	mpg123_text localcom; /* UTF-8 variant for local processing. */
Packit c32a2d
Packit c32a2d
	if(realsize < (size_t)(descr-realdata))
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error1("Invalid frame size of %"SIZE_P" (too small for anything).", (size_p)realsize);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	if(encoding > mpg123_id3_enc_max)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET)
Packit c32a2d
			error1("Unknown text encoding %u, I take no chances, sorry!", encoding);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	xcom = (tt == uslt ? add_text(fr) : add_comment(fr));
Packit c32a2d
	if(VERBOSE4) fprintf(stderr, "Note: Storing comment from %s encoding\n", enc_name(realdata[0]));
Packit c32a2d
	if(xcom == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("Unable to attach new comment!");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	memcpy(xcom->lang, lang, 3);
Packit c32a2d
	memcpy(xcom->id, id, 4);
Packit c32a2d
	/* Now I can abuse a byte from lang for the encoding. */
Packit c32a2d
	descr[-1] = encoding;
Packit c32a2d
	/* Be careful with finding the end of description, I have to honor encoding here. */
Packit c32a2d
	text = next_text(descr, encoding, realsize-(descr-realdata));
Packit c32a2d
	if(text == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("No comment text / valid description?");
Packit c32a2d
		pop_comment(fr);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	init_mpg123_text(&localcom);
Packit c32a2d
	/* Store the text, without translation to UTF-8, but for comments always a local copy in UTF-8.
Packit c32a2d
	   Reminder: No bailing out from here on without freeing the local comment data! */
Packit c32a2d
	store_id3_text(&xcom->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
Packit c32a2d
	if(tt == comment)
Packit c32a2d
	store_id3_text(&localcom.description, descr-1, text-descr+1, NOQUIET, 0);
Packit c32a2d
Packit c32a2d
	text[-1] = encoding; /* Byte abusal for encoding... */
Packit c32a2d
	store_id3_text(&xcom->text, text-1, realsize+1-(text-realdata), NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
Packit c32a2d
	/* Remember: I will probably decode the above (again) for rva comment checking. So no messing around, please. */
Packit c32a2d
Packit c32a2d
	if(VERBOSE4) /* Do _not_ print the verbatim text: The encoding might be funny! */
Packit c32a2d
	{
Packit c32a2d
		fprintf(stderr, "Note: ID3 comm/uslt desc of length %"SIZE_P".\n", (size_p)xcom->description.fill);
Packit c32a2d
		fprintf(stderr, "Note: ID3 comm/uslt text of length %"SIZE_P".\n", (size_p)xcom->text.fill);
Packit c32a2d
	}
Packit c32a2d
	/* Look out for RVA info only when we really deal with a straight comment. */
Packit c32a2d
	if(tt == comment && localcom.description.fill > 0)
Packit c32a2d
	{
Packit c32a2d
		int rva_mode = -1; /* mix / album */
Packit c32a2d
		if(    !strcasecmp(localcom.description.p, "rva")
Packit c32a2d
			 || !strcasecmp(localcom.description.p, "rva_mix")
Packit c32a2d
			 || !strcasecmp(localcom.description.p, "rva_track")
Packit c32a2d
			 || !strcasecmp(localcom.description.p, "rva_radio") )
Packit c32a2d
		rva_mode = 0;
Packit c32a2d
		else if(    !strcasecmp(localcom.description.p, "rva_album")
Packit c32a2d
		         || !strcasecmp(localcom.description.p, "rva_audiophile")
Packit c32a2d
		         || !strcasecmp(localcom.description.p, "rva_user") )
Packit c32a2d
		rva_mode = 1;
Packit c32a2d
		if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level))
Packit c32a2d
		{
Packit c32a2d
			/* Only translate the contents in here where we really need them. */
Packit c32a2d
			store_id3_text(&localcom.text, text-1, realsize+1-(text-realdata), NOQUIET, 0);
Packit c32a2d
			if(localcom.text.fill > 0)
Packit c32a2d
			{
Packit c32a2d
				fr->rva.gain[rva_mode] = (float) atof(localcom.text.p);
Packit c32a2d
				if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]);
Packit c32a2d
				fr->rva.peak[rva_mode] = 0;
Packit c32a2d
				fr->rva.level[rva_mode] = rva_level;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	/* Make sure to free the local memory... */
Packit c32a2d
	free_mpg123_text(&localcom);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void process_extra(mpg123_handle *fr, unsigned char* realdata, size_t realsize, int rva_level, char *id)
Packit c32a2d
{
Packit c32a2d
	/* Text encoding          $xx */
Packit c32a2d
	/* Description        ... $00 (00) */
Packit c32a2d
	/* Text ... */
Packit c32a2d
	unsigned char encoding = realdata[0];
Packit c32a2d
	unsigned char *descr   = realdata+1; /* remember, the encoding is descr[-1] */
Packit c32a2d
	unsigned char *text;
Packit c32a2d
	mpg123_text *xex;
Packit c32a2d
	mpg123_text localex;
Packit c32a2d
Packit c32a2d
	if((int)realsize < descr-realdata)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error1("Invalid frame size of %lu (too small for anything).", (unsigned long)realsize);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	if(encoding > mpg123_id3_enc_max)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET)
Packit c32a2d
			error1("Unknown text encoding %u, I take no chances, sorry!", encoding);
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	text = next_text(descr, encoding, realsize-(descr-realdata));
Packit c32a2d
	if(VERBOSE4) fprintf(stderr, "Note: Storing extra from %s encoding\n", enc_name(realdata[0]));
Packit c32a2d
	if(text == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("No extra frame text / valid description?");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	xex = add_extra(fr);
Packit c32a2d
	if(xex == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error("Unable to attach new extra text!");
Packit c32a2d
		return;
Packit c32a2d
	}
Packit c32a2d
	memcpy(xex->id, id, 4);
Packit c32a2d
	init_mpg123_text(&localex); /* For our local copy. */
Packit c32a2d
Packit c32a2d
	/* The outside storage gets reencoded to UTF-8 only if not requested otherwise.
Packit c32a2d
	   Remember that we really need the -1 here to hand in the encoding byte!*/
Packit c32a2d
	store_id3_text(&xex->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
Packit c32a2d
	/* Our local copy is always stored in UTF-8! */
Packit c32a2d
	store_id3_text(&localex.description, descr-1, text-descr+1, NOQUIET, 0);
Packit c32a2d
	/* At first, only store the outside copy of the payload. We may not need the local copy. */
Packit c32a2d
	text[-1] = encoding;
Packit c32a2d
	store_id3_text(&xex->text, text-1, realsize-(text-realdata)+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
Packit c32a2d
Packit c32a2d
	/* Now check if we would like to interpret this extra info for RVA. */
Packit c32a2d
	if(localex.description.fill > 0)
Packit c32a2d
	{
Packit c32a2d
		int is_peak = 0;
Packit c32a2d
		int rva_mode = -1; /* mix / album */
Packit c32a2d
Packit c32a2d
		if(!strncasecmp(localex.description.p, "replaygain_track_",17))
Packit c32a2d
		{
Packit c32a2d
			if(VERBOSE3) fprintf(stderr, "Note: RVA ReplayGain track gain/peak\n");
Packit c32a2d
Packit c32a2d
			rva_mode = 0;
Packit c32a2d
			if(!strcasecmp(localex.description.p, "replaygain_track_peak")) is_peak = 1;
Packit c32a2d
			else if(strcasecmp(localex.description.p, "replaygain_track_gain")) rva_mode = -1;
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		if(!strncasecmp(localex.description.p, "replaygain_album_",17))
Packit c32a2d
		{
Packit c32a2d
			if(VERBOSE3) fprintf(stderr, "Note: RVA ReplayGain album gain/peak\n");
Packit c32a2d
Packit c32a2d
			rva_mode = 1;
Packit c32a2d
			if(!strcasecmp(localex.description.p, "replaygain_album_peak")) is_peak = 1;
Packit c32a2d
			else if(strcasecmp(localex.description.p, "replaygain_album_gain")) rva_mode = -1;
Packit c32a2d
		}
Packit c32a2d
		if((rva_mode > -1) && (fr->rva.level[rva_mode] <= rva_level))
Packit c32a2d
		{
Packit c32a2d
			/* Now we need the translated copy of the data. */
Packit c32a2d
			store_id3_text(&localex.text, text-1, realsize-(text-realdata)+1, NOQUIET, 0);
Packit c32a2d
			if(localex.text.fill > 0)
Packit c32a2d
			{
Packit c32a2d
				if(is_peak)
Packit c32a2d
				{
Packit c32a2d
					fr->rva.peak[rva_mode] = (float) atof(localex.text.p);
Packit c32a2d
					if(VERBOSE3) fprintf(stderr, "Note: RVA peak %f\n", fr->rva.peak[rva_mode]);
Packit c32a2d
				}
Packit c32a2d
				else
Packit c32a2d
				{
Packit c32a2d
					fr->rva.gain[rva_mode] = (float) atof(localex.text.p);
Packit c32a2d
					if(VERBOSE3) fprintf(stderr, "Note: RVA gain %fdB\n", fr->rva.gain[rva_mode]);
Packit c32a2d
				}
Packit c32a2d
				fr->rva.level[rva_mode] = rva_level;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	free_mpg123_text(&localex);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Make a ID3v2.3+ 4-byte ID from a ID3v2.2 3-byte ID
Packit c32a2d
   Note that not all frames survived to 2.4; the mapping goes to 2.3 .
Packit c32a2d
   A notable miss is the old RVA frame, which is very unspecific anyway.
Packit c32a2d
   This function returns -1 when a not known 3 char ID was encountered, 0 otherwise. */
Packit c32a2d
static int promote_framename(mpg123_handle *fr, char *id) /* fr because of VERBOSE macros */
Packit c32a2d
{
Packit c32a2d
	size_t i;
Packit c32a2d
	char *old[] =
Packit c32a2d
	{
Packit c32a2d
		"COM",  "TAL",  "TBP",  "TCM",  "TCO",  "TCR",  "TDA",  "TDY",  "TEN",  "TFT",
Packit c32a2d
		"TIM",  "TKE",  "TLA",  "TLE",  "TMT",  "TOA",  "TOF",  "TOL",  "TOR",  "TOT",
Packit c32a2d
		"TP1",  "TP2",  "TP3",  "TP4",  "TPA",  "TPB",  "TRC",  "TDA",  "TRK",  "TSI",
Packit c32a2d
		"TSS",  "TT1",  "TT2",  "TT3",  "TXT",  "TXX",  "TYE"
Packit c32a2d
	};
Packit c32a2d
	char *new[] =
Packit c32a2d
	{
Packit c32a2d
		"COMM", "TALB", "TBPM", "TCOM", "TCON", "TCOP", "TDAT", "TDLY", "TENC", "TFLT",
Packit c32a2d
		"TIME", "TKEY", "TLAN", "TLEN", "TMED", "TOPE", "TOFN", "TOLY", "TORY", "TOAL",
Packit c32a2d
		"TPE1", "TPE2", "TPE3", "TPE4", "TPOS", "TPUB", "TSRC", "TRDA", "TRCK", "TSIZ",
Packit c32a2d
		"TSSE", "TIT1", "TIT2", "TIT3", "TEXT", "TXXX", "TYER"
Packit c32a2d
	};
Packit c32a2d
	for(i=0; i
Packit c32a2d
	{
Packit c32a2d
		if(!strncmp(id, old[i], 3))
Packit c32a2d
		{
Packit c32a2d
			memcpy(id, new[i], 4);
Packit c32a2d
			if(VERBOSE3) fprintf(stderr, "Translated ID3v2.2 frame %s to %s\n", old[i], new[i]);
Packit c32a2d
			return 0;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	if(VERBOSE3) fprintf(stderr, "Ignoring untranslated ID3v2.2 frame %c%c%c\n", id[0], id[1], id[2]);
Packit c32a2d
	return -1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif /* NO_ID3V2 */
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	trying to parse ID3v2.3 and ID3v2.4 tags...
Packit c32a2d
Packit c32a2d
	returns:  0: bad or just unparseable tag
Packit c32a2d
	          1: good, (possibly) new tag info
Packit c32a2d
	         <0: reader error (may need more data feed, try again)
Packit c32a2d
*/
Packit c32a2d
int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
Packit c32a2d
{
Packit c32a2d
	#define UNSYNC_FLAG 128
Packit c32a2d
	#define EXTHEAD_FLAG 64
Packit c32a2d
	#define EXP_FLAG 32
Packit c32a2d
	#define FOOTER_FLAG 16
Packit c32a2d
	#define UNKNOWN_FLAGS 15 /* 00001111*/
Packit c32a2d
	unsigned char buf[6];
Packit c32a2d
	unsigned long length=0;
Packit c32a2d
	unsigned char flags = 0;
Packit c32a2d
	int ret = 1;
Packit c32a2d
	int ret2;
Packit c32a2d
#ifndef NO_ID3V2
Packit c32a2d
	int skiptag = 0;
Packit c32a2d
#endif
Packit c32a2d
	unsigned char major = first4bytes & 0xff;
Packit c32a2d
	debug1("ID3v2: major tag version: %i", major);
Packit c32a2d
	if(major == 0xff) return 0; /* Invalid... */
Packit c32a2d
	if((ret2 = fr->rd->read_frame_body(fr, buf, 6)) < 0) /* read more header information */
Packit c32a2d
	return ret2;
Packit c32a2d
Packit c32a2d
	if(buf[0] == 0xff) return 0; /* Revision, will never be 0xff. */
Packit c32a2d
Packit c32a2d
	/* second new byte are some nice flags, if these are invalid skip the whole thing */
Packit c32a2d
	flags = buf[1];
Packit c32a2d
	debug1("ID3v2: flags 0x%08x", flags);
Packit c32a2d
	/* use 4 bytes from buf to construct 28bit uint value and return 1; return 0 if bytes are not synchsafe */
Packit c32a2d
	#define synchsafe_to_long(buf,res) \
Packit c32a2d
	( \
Packit c32a2d
		(((buf)[0]|(buf)[1]|(buf)[2]|(buf)[3]) & 0x80) ? 0 : \
Packit c32a2d
		(res =  (((unsigned long) (buf)[0]) << 21) \
Packit c32a2d
		     | (((unsigned long) (buf)[1]) << 14) \
Packit c32a2d
		     | (((unsigned long) (buf)[2]) << 7) \
Packit c32a2d
		     |  ((unsigned long) (buf)[3]) \
Packit c32a2d
		,1) \
Packit c32a2d
	)
Packit c32a2d
	/* id3v2.3 does not store synchsafe frame sizes, but synchsafe tag size - doh! */
Packit c32a2d
	/* Remember: bytes_to_long() can yield ULONG_MAX on 32 bit platforms! */
Packit c32a2d
	#define bytes_to_long(buf,res) \
Packit c32a2d
	( \
Packit c32a2d
		major == 3 ? \
Packit c32a2d
		(res =  (((unsigned long) (buf)[0]) << 24) \
Packit c32a2d
		     | (((unsigned long) (buf)[1]) << 16) \
Packit c32a2d
		     | (((unsigned long) (buf)[2]) << 8) \
Packit c32a2d
		     |  ((unsigned long) (buf)[3]) \
Packit c32a2d
		,1) : synchsafe_to_long(buf,res) \
Packit c32a2d
	)
Packit c32a2d
	/* for id3v2.2 only */
Packit c32a2d
	#define threebytes_to_long(buf,res) \
Packit c32a2d
	( \
Packit c32a2d
		res =  (((unsigned long) (buf)[0]) << 16) \
Packit c32a2d
		     | (((unsigned long) (buf)[1]) << 8) \
Packit c32a2d
		     |  ((unsigned long) (buf)[2]) \
Packit c32a2d
	)
Packit c32a2d
Packit c32a2d
	/* length-10 or length-20 (footer present); 4 synchsafe integers == 28 bit number  */
Packit c32a2d
	/* we have already read 10 bytes, so left are length or length+10 bytes belonging to tag */
Packit c32a2d
	/* Note: This is an 28 bit value in 32 bit storage, plenty of space for */
Packit c32a2d
	/* length+x for reasonable x. */
Packit c32a2d
	if(!synchsafe_to_long(buf+2,length))
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error4("Bad tag length (not synchsafe): 0x%02x%02x%02x%02x; You got a bad ID3 tag here.", buf[2],buf[3],buf[4],buf[5]);
Packit c32a2d
		return 0;
Packit c32a2d
	}
Packit c32a2d
	debug1("ID3v2: tag data length %lu", length);
Packit c32a2d
#ifndef NO_ID3V2
Packit c32a2d
	if(VERBOSE2) fprintf(stderr,"Note: ID3v2.%i rev %i tag of %lu bytes\n", major, buf[0], length);
Packit c32a2d
	/* skip if unknown version/scary flags, parse otherwise */
Packit c32a2d
	if(fr->p.flags & MPG123_SKIP_ID3V2)
Packit c32a2d
	{
Packit c32a2d
		if(VERBOSE3)
Packit c32a2d
			fprintf(stderr, "Note: Skipping ID3v2 tag per user request.\n");
Packit c32a2d
		skiptag = 1;
Packit c32a2d
	}
Packit c32a2d
	if((flags & UNKNOWN_FLAGS) || (major > 4) || (major < 2))
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET)
Packit c32a2d
			warning2( "ID3v2: Won't parse the ID3v2 tag with major version"
Packit c32a2d
				" %u and flags 0x%xu - some extra code may be needed"
Packit c32a2d
			,	major, flags );
Packit c32a2d
		skiptag = 1;
Packit c32a2d
	}
Packit c32a2d
	if(length < 10)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET)
Packit c32a2d
			warning1("ID3v2: unrealistic small tag lengh %lu, skipping", length);
Packit c32a2d
		skiptag = 1;
Packit c32a2d
	}
Packit c32a2d
	if(skiptag)
Packit c32a2d
	{
Packit c32a2d
#endif
Packit c32a2d
		if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) /* will not store data in backbuff! */
Packit c32a2d
		ret = ret2;
Packit c32a2d
#ifndef NO_ID3V2
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		unsigned char* tagdata = NULL;
Packit c32a2d
		fr->id3v2.version = major;
Packit c32a2d
		/* try to interpret that beast */
Packit c32a2d
		if((tagdata = (unsigned char*) malloc(length+1)) != NULL)
Packit c32a2d
		{
Packit c32a2d
			debug("ID3v2: analysing frames...");
Packit c32a2d
			if((ret2 = fr->rd->read_frame_body(fr,tagdata,length)) > 0)
Packit c32a2d
			{
Packit c32a2d
				unsigned long tagpos = 0;
Packit c32a2d
				/* bytes of frame title and of framesize value */
Packit c32a2d
				unsigned int head_part = fr->id3v2.version > 2 ? 4 : 3;
Packit c32a2d
				unsigned int flag_part = fr->id3v2.version > 2 ? 2 : 0;
Packit c32a2d
				/* The amount of bytes that are unconditionally read for each frame: */
Packit c32a2d
				/* ID, size, flags. */
Packit c32a2d
				unsigned int framebegin = head_part+head_part+flag_part;
Packit c32a2d
				debug1("ID3v2: have read at all %lu bytes for the tag now", (unsigned long)length+6);
Packit c32a2d
				/* going to apply strlen for strings inside frames, make sure that it doesn't overflow! */
Packit c32a2d
				tagdata[length] = 0;
Packit c32a2d
				if(flags & EXTHEAD_FLAG)
Packit c32a2d
				{
Packit c32a2d
					debug("ID3v2: skipping extended header");
Packit c32a2d
					if(!bytes_to_long(tagdata, tagpos) || tagpos >= length)
Packit c32a2d
					{
Packit c32a2d
						ret = 0;
Packit c32a2d
						if(NOQUIET)
Packit c32a2d
							error4( "Bad (non-synchsafe/too large) tag offset:"
Packit c32a2d
								"0x%02x%02x%02x%02x"
Packit c32a2d
							,	tagdata[0], tagdata[1], tagdata[2], tagdata[3] );
Packit c32a2d
					}
Packit c32a2d
				}
Packit c32a2d
				if(ret > 0)
Packit c32a2d
				{
Packit c32a2d
					char id[5];
Packit c32a2d
					unsigned long framesize;
Packit c32a2d
					unsigned long fflags; /* need 16 bits, actually */
Packit c32a2d
					id[4] = 0;
Packit c32a2d
					/* Pos now advanced after ext head, now a frame has to follow. */
Packit c32a2d
					/* Note: tagpos <= length, which is 28 bit integer, so both */
Packit c32a2d
					/* far away from overflow for adding known small values. */
Packit c32a2d
					/* I want to read at least one full header now. */
Packit c32a2d
					while(length >= tagpos+framebegin)
Packit c32a2d
					{
Packit c32a2d
						int i = 0;
Packit c32a2d
						unsigned long pos = tagpos;
Packit c32a2d
						/* level 1,2,3 - 0 is info from lame/info tag! */
Packit c32a2d
						/* rva tags with ascending significance, then general frames */
Packit c32a2d
						enum frame_types tt = unknown;
Packit c32a2d
						/* we may have entered the padding zone or any other strangeness: check if we have valid frame id characters */
Packit c32a2d
						for(i=0; i< head_part; ++i)
Packit c32a2d
						if( !( ((tagdata[tagpos+i] > 47) && (tagdata[tagpos+i] < 58))
Packit c32a2d
						    || ((tagdata[tagpos+i] > 64) && (tagdata[tagpos+i] < 91)) ) )
Packit c32a2d
						{
Packit c32a2d
							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]);
Packit c32a2d
							/* This is no hard error... let's just hope that we got something meaningful already (ret==1 in that case). */
Packit c32a2d
							goto tagparse_cleanup; /* Need to escape two loops here. */
Packit c32a2d
						}
Packit c32a2d
						if(ret > 0)
Packit c32a2d
						{
Packit c32a2d
							/* 4 or 3 bytes id */
Packit c32a2d
							strncpy(id, (char*) tagdata+pos, head_part);
Packit c32a2d
							id[head_part] = 0; /* terminate for 3 or 4 bytes */
Packit c32a2d
							pos += head_part;
Packit c32a2d
							tagpos += head_part;
Packit c32a2d
							/* size as 32 bits or 28 bits */
Packit c32a2d
							if(fr->id3v2.version == 2) threebytes_to_long(tagdata+pos, framesize);
Packit c32a2d
							else
Packit c32a2d
							if(!bytes_to_long(tagdata+pos, framesize))
Packit c32a2d
							{
Packit c32a2d
								/* Just assume that up to now there was some good data. */
Packit c32a2d
								if(NOQUIET) error1("ID3v2: non-syncsafe size of %s frame, skipping the remainder of tag", id);
Packit c32a2d
								break;
Packit c32a2d
							}
Packit c32a2d
							if(VERBOSE3) fprintf(stderr, "Note: ID3v2 %s frame of size %lu\n", id, framesize);
Packit c32a2d
							tagpos += head_part;
Packit c32a2d
							pos += head_part;
Packit c32a2d
							if(fr->id3v2.version > 2)
Packit c32a2d
							{
Packit c32a2d
								fflags  = (((unsigned long) tagdata[pos]) << 8) | ((unsigned long) tagdata[pos+1]);
Packit c32a2d
								pos    += 2;
Packit c32a2d
								tagpos += 2;
Packit c32a2d
							}
Packit c32a2d
							else fflags = 0;
Packit c32a2d
Packit c32a2d
							if(length - tagpos < framesize)
Packit c32a2d
							{
Packit c32a2d
								if(NOQUIET) error("Whoa! ID3v2 frame claims to be larger than the whole rest of the tag.");
Packit c32a2d
								break;
Packit c32a2d
							}
Packit c32a2d
							tagpos += framesize; /* the important advancement in whole tag */
Packit c32a2d
							/* for sanity, after full parsing tagpos should be == pos */
Packit c32a2d
							/* debug4("ID3v2: found %s frame, size %lu (as bytes: 0x%08lx), flags 0x%016lx", id, framesize, framesize, fflags); */
Packit c32a2d
							/* %0abc0000 %0h00kmnp */
Packit c32a2d
							#define BAD_FFLAGS (unsigned long) 36784
Packit c32a2d
							#define PRES_TAG_FFLAG 16384
Packit c32a2d
							#define PRES_FILE_FFLAG 8192
Packit c32a2d
							#define READ_ONLY_FFLAG 4096
Packit c32a2d
							#define GROUP_FFLAG 64
Packit c32a2d
							#define COMPR_FFLAG 8
Packit c32a2d
							#define ENCR_FFLAG 4
Packit c32a2d
							#define UNSYNC_FFLAG 2
Packit c32a2d
							#define DATLEN_FFLAG 1
Packit c32a2d
							if(head_part < 4 && promote_framename(fr, id) != 0) continue;
Packit c32a2d
Packit c32a2d
							/* shall not or want not handle these */
Packit c32a2d
							if(fflags & (BAD_FFLAGS | COMPR_FFLAG | ENCR_FFLAG))
Packit c32a2d
							{
Packit c32a2d
								if(NOQUIET) warning("ID3v2: skipping invalid/unsupported frame");
Packit c32a2d
								continue;
Packit c32a2d
							}
Packit c32a2d
Packit c32a2d
							for(i = 0; i < KNOWN_FRAMES; ++i)
Packit c32a2d
							if(!strncmp(frame_type[i], id, 4)){ tt = i; break; }
Packit c32a2d
Packit c32a2d
							if(id[0] == 'T' && tt != extra) tt = text;
Packit c32a2d
Packit c32a2d
							if(tt != unknown)
Packit c32a2d
							{
Packit c32a2d
								int rva_mode = -1; /* mix / album */
Packit c32a2d
								unsigned long realsize = framesize;
Packit c32a2d
								unsigned char* realdata = tagdata+pos;
Packit c32a2d
								if((flags & UNSYNC_FLAG) || (fflags & UNSYNC_FFLAG))
Packit c32a2d
								{
Packit c32a2d
									unsigned long ipos = 0;
Packit c32a2d
									unsigned long opos = 0;
Packit c32a2d
									debug("Id3v2: going to de-unsync the frame data");
Packit c32a2d
									/* de-unsync: FF00 -> FF; real FF00 is simply represented as FF0000 ... */
Packit c32a2d
									/* damn, that means I have to delete bytes from withing the data block... thus need temporal storage */
Packit c32a2d
									/* standard mandates that de-unsync should always be safe if flag is set */
Packit c32a2d
									realdata = (unsigned char*) malloc(framesize); /* will need <= bytes */
Packit c32a2d
									if(realdata == NULL)
Packit c32a2d
									{
Packit c32a2d
										if(NOQUIET) error("ID3v2: unable to allocate working buffer for de-unsync");
Packit c32a2d
										continue;
Packit c32a2d
									}
Packit c32a2d
									/* now going byte per byte through the data... */
Packit c32a2d
									realdata[0] = tagdata[pos];
Packit c32a2d
									opos = 1;
Packit c32a2d
									for(ipos = pos+1; ipos < pos+framesize; ++ipos)
Packit c32a2d
									{
Packit c32a2d
										if(!((tagdata[ipos] == 0) && (tagdata[ipos-1] == 0xff)))
Packit c32a2d
										{
Packit c32a2d
											realdata[opos++] = tagdata[ipos];
Packit c32a2d
										}
Packit c32a2d
									}
Packit c32a2d
									realsize = opos;
Packit c32a2d
									debug2("ID3v2: de-unsync made %lu out of %lu bytes", realsize, framesize);
Packit c32a2d
								}
Packit c32a2d
								pos = 0; /* now at the beginning again... */
Packit c32a2d
								/* Avoid reading over boundary, even if there is a */
Packit c32a2d
								/* zero byte of padding for safety. */
Packit c32a2d
								if(realsize) switch(tt)
Packit c32a2d
								{
Packit c32a2d
									case comment:
Packit c32a2d
									case uslt:
Packit c32a2d
										process_comment(fr, tt, realdata, realsize, comment+1, id);
Packit c32a2d
									break;
Packit c32a2d
									case extra: /* perhaps foobar2000's work */
Packit c32a2d
										process_extra(fr, realdata, realsize, extra+1, id);
Packit c32a2d
									break;
Packit c32a2d
									case rva2: /* "the" RVA tag */
Packit c32a2d
									{
Packit c32a2d
										/* starts with null-terminated identification */
Packit c32a2d
										if(VERBOSE3) fprintf(stderr, "Note: RVA2 identification \"%s\"\n", realdata);
Packit c32a2d
										/* default: some individual value, mix mode */
Packit c32a2d
										rva_mode = 0;
Packit c32a2d
										if( !strncasecmp((char*)realdata, "album", 5)
Packit c32a2d
										    || !strncasecmp((char*)realdata, "audiophile", 10)
Packit c32a2d
										    || !strncasecmp((char*)realdata, "user", 4))
Packit c32a2d
										rva_mode = 1;
Packit c32a2d
										if(fr->rva.level[rva_mode] <= rva2+1)
Packit c32a2d
										{
Packit c32a2d
											pos += strlen((char*) realdata) + 1;
Packit c32a2d
											if(realdata[pos] == 1)
Packit c32a2d
											{
Packit c32a2d
												++pos;
Packit c32a2d
												/* only handle master channel */
Packit c32a2d
												debug("ID3v2: it is for the master channel");
Packit c32a2d
												/* two bytes adjustment, one byte for bits representing peak - n bytes, eh bits, for peak */
Packit c32a2d
												/* 16 bit signed integer = dB * 512  ... the double cast is needed to preserve the sign of negative values! */
Packit c32a2d
												fr->rva.gain[rva_mode] = (float) ( (((short)((signed char)realdata[pos])) << 8) | realdata[pos+1] ) / 512;
Packit c32a2d
												pos += 2;
Packit c32a2d
												if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]);
Packit c32a2d
												/* heh, the peak value is represented by a number of bits - but in what manner? Skipping that part */
Packit c32a2d
												fr->rva.peak[rva_mode] = 0;
Packit c32a2d
												fr->rva.level[rva_mode] = rva2+1;
Packit c32a2d
											}
Packit c32a2d
										}
Packit c32a2d
									}
Packit c32a2d
									break;
Packit c32a2d
									/* non-rva metainfo, simply store... */
Packit c32a2d
									case text:
Packit c32a2d
										process_text(fr, realdata, realsize, id);
Packit c32a2d
									break;
Packit c32a2d
									case picture:
Packit c32a2d
										if (fr->p.flags & MPG123_PICTURE)
Packit c32a2d
										process_picture(fr, realdata, realsize);
Packit c32a2d
Packit c32a2d
										break;
Packit c32a2d
									default: if(NOQUIET) error1("ID3v2: unknown frame type %i", tt);
Packit c32a2d
								}
Packit c32a2d
								if((flags & UNSYNC_FLAG) || (fflags & UNSYNC_FFLAG)) free(realdata);
Packit c32a2d
							}
Packit c32a2d
							#undef BAD_FFLAGS
Packit c32a2d
							#undef PRES_TAG_FFLAG
Packit c32a2d
							#undef PRES_FILE_FFLAG
Packit c32a2d
							#undef READ_ONLY_FFLAG
Packit c32a2d
							#undef GROUP_FFLAG
Packit c32a2d
							#undef COMPR_FFLAG
Packit c32a2d
							#undef ENCR_FFLAG
Packit c32a2d
							#undef UNSYNC_FFLAG
Packit c32a2d
							#undef DATLEN_FFLAG
Packit c32a2d
						}
Packit c32a2d
						else break;
Packit c32a2d
						#undef KNOWN_FRAMES
Packit c32a2d
					}
Packit c32a2d
				}
Packit c32a2d
			}
Packit c32a2d
			else
Packit c32a2d
			{
Packit c32a2d
				/* There are tags with zero length. Strictly not an error, then. */
Packit c32a2d
				if(length > 0 && NOQUIET && ret2 != MPG123_NEED_MORE) error("ID3v2: Duh, not able to read ID3v2 tag data.");
Packit c32a2d
				ret = ret2;
Packit c32a2d
			}
Packit c32a2d
tagparse_cleanup:
Packit c32a2d
			free(tagdata);
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		{
Packit c32a2d
			if(NOQUIET) error1("ID3v2: Arrg! Unable to allocate %lu bytes for interpreting ID3v2 data - trying to skip instead.", length);
Packit c32a2d
			if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) ret = ret2; /* will not store data in backbuff! */
Packit c32a2d
			else ret = 0;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
#endif /* NO_ID3V2 */
Packit c32a2d
	/* skip footer if present */
Packit c32a2d
	if((ret > 0) && (flags & FOOTER_FLAG) && ((ret2 = fr->rd->skip_bytes(fr,length)) < 0)) ret = ret2;
Packit c32a2d
Packit c32a2d
	return ret;
Packit c32a2d
	#undef UNSYNC_FLAG
Packit c32a2d
	#undef EXTHEAD_FLAG
Packit c32a2d
	#undef EXP_FLAG
Packit c32a2d
	#undef FOOTER_FLAG
Packit c32a2d
	#undef UNKOWN_FLAGS
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifndef NO_ID3V2 /* Disabling all the rest... */
Packit c32a2d
Packit c32a2d
static void convert_latin1(mpg123_string *sb, const unsigned char* s, size_t l, const int noquiet)
Packit c32a2d
{
Packit c32a2d
	size_t length = l;
Packit c32a2d
	size_t i;
Packit c32a2d
	unsigned char *p;
Packit c32a2d
	/* determine real length, a latin1 character can at most take 2  in UTF8 */
Packit c32a2d
	for(i=0; i
Packit c32a2d
	if(s[i] >= 0x80) ++length;
Packit c32a2d
Packit c32a2d
	debug1("UTF-8 length: %lu", (unsigned long)length);
Packit c32a2d
	/* one extra zero byte for paranoia */
Packit c32a2d
	if(!mpg123_resize_string(sb, length+1)){ mpg123_free_string(sb); return ; }
Packit c32a2d
Packit c32a2d
	p = (unsigned char*) sb->p; /* Signedness doesn't matter but it shows I thought about the non-issue */
Packit c32a2d
	for(i=0; i
Packit c32a2d
	if(s[i] < 0x80){ *p = s[i]; ++p; }
Packit c32a2d
	else /* two-byte encoding */
Packit c32a2d
	{
Packit c32a2d
		*p     = 0xc0 | (s[i]>>6);
Packit c32a2d
		*(p+1) = 0x80 | (s[i] & 0x3f);
Packit c32a2d
		p+=2;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	sb->p[length] = 0;
Packit c32a2d
	sb->fill = length+1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	Check if we have a byte oder mark(s) there, return:
Packit c32a2d
	-1: little endian
Packit c32a2d
	 0: no BOM
Packit c32a2d
	 1: big endian
Packit c32a2d
Packit c32a2d
	This modifies source and len to indicate the data _after_ the BOM(s).
Packit c32a2d
	Note on nasty data: The last encountered BOM determines the endianness.
Packit c32a2d
	I have seen data with multiple BOMS, namely from "the" id3v2 program.
Packit c32a2d
	Not nice, but what should I do?
Packit c32a2d
*/
Packit c32a2d
static int check_bom(const unsigned char** source, size_t *len)
Packit c32a2d
{
Packit c32a2d
	int this_bom    = 0;
Packit c32a2d
	int further_bom = 0;
Packit c32a2d
Packit c32a2d
	if(*len < 2) return 0;
Packit c32a2d
Packit c32a2d
	if((*source)[0] == 0xff && (*source)[1] == 0xfe)
Packit c32a2d
	this_bom = -1;
Packit c32a2d
Packit c32a2d
	if((*source)[0] == 0xfe && (*source)[1] == 0xff)
Packit c32a2d
	this_bom = 1;
Packit c32a2d
Packit c32a2d
	/* Skip the detected BOM. */
Packit c32a2d
	if(this_bom != 0)
Packit c32a2d
	{
Packit c32a2d
		*source += 2;
Packit c32a2d
		*len    -= 2;
Packit c32a2d
		/* Check for following BOMs. The last one wins! */
Packit c32a2d
		further_bom = check_bom(source, len);
Packit c32a2d
		if(further_bom == 0) return this_bom; /* End of the recursion. */
Packit c32a2d
		else                 return further_bom;
Packit c32a2d
	}
Packit c32a2d
	else return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#define FULLPOINT(f,s) ( (((f)&0x3ff)<<10) + ((s)&0x3ff) + 0x10000 )
Packit c32a2d
/* Remember: There's a limit at 0x1ffff. */
Packit c32a2d
#define UTF8LEN(x) ( (x)<0x80 ? 1 : ((x)<0x800 ? 2 : ((x)<0x10000 ? 3 : 4)))
Packit c32a2d
static void convert_utf16bom(mpg123_string *sb, const unsigned char* s, size_t l, const int noquiet)
Packit c32a2d
{
Packit c32a2d
	size_t i;
Packit c32a2d
	size_t n; /* number bytes that make up full pairs */
Packit c32a2d
	unsigned char *p;
Packit c32a2d
	size_t length = 0; /* the resulting UTF-8 length */
Packit c32a2d
	/* Determine real length... extreme case can be more than utf-16 length. */
Packit c32a2d
	size_t high = 0;
Packit c32a2d
	size_t low  = 1;
Packit c32a2d
	int bom_endian;
Packit c32a2d
Packit c32a2d
	debug1("convert_utf16 with length %lu", (unsigned long)l);
Packit c32a2d
Packit c32a2d
	bom_endian = check_bom(&s, &l);
Packit c32a2d
	debug1("UTF16 endianness check: %i", bom_endian);
Packit c32a2d
Packit c32a2d
	if(bom_endian == -1) /* little-endian */
Packit c32a2d
	{
Packit c32a2d
		high = 1; /* The second byte is the high byte. */
Packit c32a2d
		low  = 0; /* The first byte is the low byte. */
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	n = (l/2)*2; /* number bytes that make up full pairs */
Packit c32a2d
Packit c32a2d
	/* first: get length, check for errors -- stop at first one */
Packit c32a2d
	for(i=0; i < n; i+=2)
Packit c32a2d
	{
Packit c32a2d
		unsigned long point = ((unsigned long) s[i+high]<<8) + s[i+low];
Packit c32a2d
		if((point & 0xfc00) == 0xd800) /* lead surrogate */
Packit c32a2d
		{
Packit c32a2d
			unsigned short second = (i+3 < l) ? (s[i+2+high]<<8) + s[i+2+low] : 0;
Packit c32a2d
			if((second & 0xfc00) == 0xdc00) /* good... */
Packit c32a2d
			{
Packit c32a2d
				point = FULLPOINT(point,second);
Packit c32a2d
				length += UTF8LEN(point); /* possibly 4 bytes */
Packit c32a2d
				i+=2; /* We overstepped one word. */
Packit c32a2d
			}
Packit c32a2d
			else /* if no valid pair, break here */
Packit c32a2d
			{
Packit c32a2d
				if(noquiet) error2("Invalid UTF16 surrogate pair at %li (0x%04lx).", (unsigned long)i, point);
Packit c32a2d
				n = i; /* Forget the half pair, END! */
Packit c32a2d
				break;
Packit c32a2d
			}
Packit c32a2d
		}
Packit c32a2d
		else length += UTF8LEN(point); /* 1,2 or 3 bytes */
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(!mpg123_resize_string(sb, length+1)){ mpg123_free_string(sb); return ; }
Packit c32a2d
Packit c32a2d
	/* Now really convert, skip checks as these have been done just before. */
Packit c32a2d
	p = (unsigned char*) sb->p; /* Signedness doesn't matter but it shows I thought about the non-issue */
Packit c32a2d
	for(i=0; i < n; i+=2)
Packit c32a2d
	{
Packit c32a2d
		unsigned long codepoint = ((unsigned long) s[i+high]<<8) + s[i+low];
Packit c32a2d
		if((codepoint & 0xfc00) == 0xd800) /* lead surrogate */
Packit c32a2d
		{
Packit c32a2d
			unsigned short second = (s[i+2+high]<<8) + s[i+2+low];
Packit c32a2d
			codepoint = FULLPOINT(codepoint,second);
Packit c32a2d
			i+=2; /* We overstepped one word. */
Packit c32a2d
		}
Packit c32a2d
		if(codepoint < 0x80) *p++ = (unsigned char) codepoint;
Packit c32a2d
		else if(codepoint < 0x800)
Packit c32a2d
		{
Packit c32a2d
			*p++ = (unsigned char) (0xc0 | (codepoint>>6));
Packit c32a2d
			*p++ = (unsigned char) (0x80 | (codepoint & 0x3f));
Packit c32a2d
		}
Packit c32a2d
		else if(codepoint < 0x10000)
Packit c32a2d
		{
Packit c32a2d
			*p++ = (unsigned char) (0xe0 | (codepoint>>12));
Packit c32a2d
			*p++ = 0x80 | ((codepoint>>6) & 0x3f);
Packit c32a2d
			*p++ = 0x80 | (codepoint & 0x3f);
Packit c32a2d
		}
Packit c32a2d
		else if (codepoint < 0x200000)
Packit c32a2d
		{
Packit c32a2d
			*p++ = (unsigned char) (0xf0 | codepoint>>18);
Packit c32a2d
			*p++ = (unsigned char) (0x80 | ((codepoint>>12) & 0x3f));
Packit c32a2d
			*p++ = (unsigned char) (0x80 | ((codepoint>>6) & 0x3f));
Packit c32a2d
			*p++ = (unsigned char) (0x80 | (codepoint & 0x3f));
Packit c32a2d
		} /* ignore bigger ones (that are not possible here anyway) */
Packit c32a2d
	}
Packit c32a2d
	sb->p[sb->size-1] = 0; /* paranoia... */
Packit c32a2d
	sb->fill = sb->size;
Packit c32a2d
}
Packit c32a2d
#undef UTF8LEN
Packit c32a2d
#undef FULLPOINT
Packit c32a2d
Packit c32a2d
static void convert_utf8(mpg123_string *sb, const unsigned char* source, size_t len, const int noquiet)
Packit c32a2d
{
Packit c32a2d
	if(mpg123_resize_string(sb, len+1))
Packit c32a2d
	{
Packit c32a2d
		memcpy(sb->p, source, len);
Packit c32a2d
		sb->p[len] = 0;
Packit c32a2d
		sb->fill = len+1;
Packit c32a2d
	}
Packit c32a2d
	else mpg123_free_string(sb);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif