Re: [PATCH] - improved decoding of URL special characters

Andrew Sveikauskas <[email protected]> Wed, 19 Oct 2005 16:23:36 -0400
Newsgroups gmane.comp.multimedia.xmms.devel
Message-ID <[email protected]>
Hi,

Why is text in urldecodestr a char ** and not char *?  It never sets *text to
anything, so there's no point in making it char **, unless I'm not seeing
something.

My humble opinion is that a better urldecodestr()-type function would look
like this.  Notably, let the libc do the hex conversion.  This also does
less copies if the string consists of more than one %xx sequence.

But.  This is just my opinion.

#include <stdio.h>	/* for sscanf */
#include <ctype.h>	/* for isxdigit */

/*
 * Modify the buffer buf to convert %xx into the appropriate character.
 */
int urldecodestr( char *buf )
{
	const char *r = buf;
	while( *r )
		switch( *r )
		{
		  case '%':
			/* Is this really a 2-digit hex string? */
			if( isxdigit(r[1]) && isxdigit(r[2]) )
			{
				char hex[3];
				int i;
				hex[0] = *++r;
				hex[1] = *++r;
				hex[2] = 0;
				++r;
				sscanf( hex, "%x", &i );
				*buf++ = i; 
				break;
			}
			/* No, follow through. */
		  default:
			*buf++ = *r++;
		}
	*buf = 0;
}

On Wed, Oct 19, 2005 at 01:19:54PM -0500, Dustin Kirkland wrote:
> Hi-
> 
> I've attached a small patch that improves the decoding of URL special
> characters.  XMMS has long supported converting "%20" into a blank
> space.  However, other multibyte characters (apostrophes, parentheses,
> etc) are not converted in the same manner.
> 
> I first reported this problem 2002-10-24 in a bugzilla, with a
> suggested fix, but not a completed patch:
> http://bugs.xmms.org/show_bug.cgi?id=1068
> 
> I later reworked the patch as below, which has worked very well for me
> for several years now.  I would like to see this accepted in the
> upstream XMMS.
> 
> There are two helper functions that are added by this patch, axtoi()
> and urldecodestr() in urldecode.c.
> 
> The first, axtoi() takes a string pointer as input and returns an
> integer.  It will calculate the decimal integer value of a 2-character
> hexadecimal string, such as "20" -> 32, or "2A" -> 42.
> 
> The second, urldecodestr(), takes a pointer to a string pointer, and
> searches through the string for the % character.  When this is found,
> the location is passed to the axtoi() function, which will attempt to
> convert the following two characters to an integer.  If it is able to
> do so, the "%XX" three characters in the string are replaced with the
> appropriate character that was url-encoded.  The string passed in is
> modified (rather than mallocing a new pointer).
> 
> Finally, the few places in the code where the %20-to-whitespace
> conversion happened were replaced with a call to urldecodestr().
> 
> This provides support for several characters that are frequently found
> in mp3 filenames besides the blank space, such as: the apostrophe,
> comma, tilda, parentheses, brackets, braces, etc.
> 
> For example...
> 
> http://localhost/Bob%20Dylan/Biograph%20%28Disc%203%20of%203%29/15%20-%20Knockin%27%20On%20Heaven%27s%20Door.mp3]
> 
> now translates to the following in the playlist window (with parens
> and tick marks correctly placed)...
> 
> Bob Dylan/Biograph (Disc 3 of 3)/15 - Knockin' On Heaven's Door.mp3
> 
> Comments are welcome.  I would very much like to see this included in
> the next release.
> 
> :-Dustin
> 
> 
> diff -uprN xmms-1.2.10/xmms/playlist.c xmms-1.2.10-hex_to_char/xmms/playlist.c
> --- xmms-1.2.10/xmms/playlist.c	2004-02-23 14:31:43.000000000 -0600
> +++ xmms-1.2.10-hex_to_char/xmms/playlist.c	2005-10-19 04:47:52.000000000 -0500
> @@ -983,16 +983,7 @@ char *playlist_get_info_text(void)
>  		while ((tmp = strchr(text, '_')) != NULL)
>  			*tmp = ' ';
>  	if (cfg.convert_twenty)
> -		while ((tmp = strstr(text, "%20")) != NULL)
> -		{
> -			char *tmp2;
> -			tmp2 = tmp + 3;
> -			*(tmp++) = ' ';
> -			while (*tmp2)
> -				*(tmp++) = *(tmp2++);
> -			*tmp = '\0';
> -		}
> -	
> +		urldecodestr(&text);
>  	return text;
>  }
> 
> diff -uprN xmms-1.2.10/xmms/playlist_list.c
> xmms-1.2.10-hex_to_char/xmms/playlist_list.c
> --- xmms-1.2.10/xmms/playlist_list.c	2003-06-11 13:44:17.000000000 -0500
> +++ xmms-1.2.10-hex_to_char/xmms/playlist_list.c	2005-10-19
> 04:58:47.000000000 -0500
> @@ -314,18 +314,7 @@ void playlist_list_draw_string_wc(PlayLi
>  	}
> 
>  	if (cfg.convert_twenty && len > 2)
> -	{
> -		GdkWChar *wtmp;
> -		while ((wtmp = find_in_wstr(wtext, "%20")) != NULL)
> -		{
> -			GdkWChar *wtmp2 = wtmp + 3;
> -			*(wtmp++) = L' ';
> -			while (*wtmp2)
> -				*(wtmp++) = *(wtmp2++);
> -			*wtmp = L'\0';
> -			len -= 2;
> -		}
> -	}
> +		urldecodestr(&wtext);
>  		
>  	newlen = len + 2;
> 
> @@ -366,14 +355,8 @@ void playlist_list_draw_string(PlayList_
>  		while ((tmp = strchr(text, '_')) != NULL)
>  			*tmp = ' ';
>  	if (cfg.convert_twenty)
> -		while ((tmp = strstr(text, "%20")) != NULL)
> -		{
> -			char *tmp2 = tmp + 3;
> -			*(tmp++) = ' ';
> -			while (*tmp2)
> -				*(tmp++) = *(tmp2++);
> -			*tmp = '\0';
> -		}
> +		urldecodestr(&text);
>  	len = strlen(text);
>  	while (gdk_text_width(font, text, len) > width && len > 4)
>  	{
> diff -uprN xmms-1.2.10/xmms/urldecode.c xmms-1.2.10-hex_to_char/xmms/urldecode.c
> --- xmms-1.2.10/xmms/urldecode.c	2003-05-19 16:22:08.000000000 -0500
> +++ xmms-1.2.10-hex_to_char/xmms/urldecode.c	2005-10-19 04:46:07.000000000 -0500
> @@ -61,3 +61,47 @@ char *xmms_urldecode_path(char *encoded_
>  	
>  	return encoded_path;
>  }
> +
> +
> +/* take a 2-character hex string and return the integer value */
> +int axtoi(char *hexstr) {
> +	int i = 0;
> +	int hexint[2];
> +	hexint[0] = hexint[1] = 0;
> +	while (i < 2) {
> +		if (hexstr[i]=='\0')
> +			break;
> +		else if (hexstr[i] >= '0' && hexstr[i] <= '9' )
> +			hexint[i] = hexstr[i] - '0';
> +		else if (hexstr[i] >='A' && hexstr[i] <= 'F')
> +			hexint[i] = 10 + (hexstr[i] - 'A');
> +		else if (hexstr[i] >='a' && hexstr[i] <= 'f')
> +			hexint[i] = 10 + (hexstr[i] - 'a');
> +		else break;
> +		i++;
> +	}
> +	return hexint[0]*16 + hexint[1];
> +}
> +
> +
> +/* for each "%" found in string, attempt to decode following two bytes and
> +   replace with URL special character */
> +int urldecodestr(char **text) {
> +	char *str, *tmp, *hexstr, *cur;
> +	int i;
> +	str = cur = *text;
> +	while ((hexstr = strchr(str, '%')) != NULL) {
> +		cur = hexstr + 1;
> +		i = axtoi(cur);
> +		if (i > 0) {
> +			tmp = hexstr + 3;
> +			*(hexstr++) = (char)i;
> +			while (*tmp)
> +				*(hexstr++) = *(tmp++);
> +			*hexstr = '\0';
> +		}
> +		str = cur;
> +	}
> +	return 0;
> +}
> +
> diff -uprN xmms-1.2.10/xmms/urldecode.h xmms-1.2.10-hex_to_char/xmms/urldecode.h
> --- xmms-1.2.10/xmms/urldecode.h	2000-05-31 21:56:20.000000000 -0500
> +++ xmms-1.2.10-hex_to_char/xmms/urldecode.h	2005-10-19 04:46:41.000000000 -0500
> @@ -17,3 +17,5 @@
>   */
> 
>  char *xmms_urldecode_path(char *);
> +int axtoi(char *hexstr);
> +int urldecodestr(char **text);
> 
> _______________________________________________
> xmms-devel mailing list
> [email protected]
> http://lists.xmms.org/mailman/listinfo/xmms-devel
>