comparison src/xspf/urlencode.c @ 95:b5a1b762f586 trunk

[svn] - xspf now uses url encoding for location entry.
author yaz
date Fri, 20 Oct 2006 00:59:45 -0700
parents
children 1983383db0f5
comparison
equal deleted inserted replaced
94:230d8b49db8b 95:b5a1b762f586
1 /* the original code was taken from wget-1.10.2 */
2
3 #include <stdio.h>
4 #include <string.h>
5 #include <glib.h>
6 #include <ctype.h>
7 #include "urlencode.h"
8
9 enum {
10 /* rfc1738 reserved chars + "$" and ",". */
11 urlchr_reserved = 1,
12
13 /* rfc1738 unsafe chars, plus non-printables. */
14 urlchr_unsafe = 2
15 };
16
17 #define urlchr_test(c, mask) (urlchr_table[(unsigned char)(c)] & (mask))
18 #define URL_RESERVED_CHAR(c) urlchr_test(c, urlchr_reserved)
19 #define URL_UNSAFE_CHAR(c) urlchr_test(c, urlchr_unsafe)
20 #define XNUM_TO_DIGIT(x) ("0123456789ABCDEF"[x] + 0)
21 #define ISXDIGIT(x) (isxdigit((unsigned char)(x)))
22 #define X2DIGITS_TO_NUM(h1, h2) ((XDIGIT_TO_NUM (h1) << 4) + XDIGIT_TO_NUM (h2))
23 #define XDIGIT_TO_NUM(h) ((h) < 'A' ? (h) - '0' : toupper (h) - 'A' + 10)
24
25 /* Shorthands for the table: */
26 #define R urlchr_reserved
27 #define U urlchr_unsafe
28 #define RU R|U
29
30 static const unsigned char urlchr_table[256] =
31 {
32 U, U, U, U, U, U, U, U, /* NUL SOH STX ETX EOT ENQ ACK BEL */
33 U, U, U, U, U, U, U, U, /* BS HT LF VT FF CR SO SI */
34 U, U, U, U, U, U, U, U, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
35 U, U, U, U, U, U, U, U, /* CAN EM SUB ESC FS GS RS US */
36 U, 0, U, RU, R, U, R, 0, /* SP ! " # $ % & ' */
37 0, 0, 0, R, R, 0, 0, R, /* ( ) * + , - . / */
38 0, 0, 0, 0, 0, 0, 0, 0, /* 0 1 2 3 4 5 6 7 */
39 0, 0, RU, R, U, R, U, R, /* 8 9 : ; < = > ? */
40 RU, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
41 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
42 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
43 0, 0, 0, RU, U, RU, U, 0, /* X Y Z [ \ ] ^ _ */
44 U, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
45 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
46 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
47 0, 0, 0, U, U, U, 0, U, /* x y z { | } ~ DEL */
48
49 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
50 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
51 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
52 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
53
54 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
55 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
56 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
57 U, U, U, U, U, U, U, U, U, U, U, U, U, U, U, U,
58 };
59 #undef R
60 #undef U
61 #undef RU
62
63 /* URL-unescape the string S.
64
65 This is done by transforming the sequences "%HH" to the character
66 represented by the hexadecimal digits HH. If % is not followed by
67 two hexadecimal digits, it is inserted literally.
68
69 The transformation is done in place. If you need the original
70 string intact, make a copy before calling this function. */
71
72 char *
73 xspf_url_decode (const char *s)
74 {
75 char *copy = strdup(s);
76 char *t = copy; /* t - tortoise */
77 char *h = copy; /* h - hare */
78
79 for (; *h; h++, t++)
80 {
81 if (*h != '%')
82 {
83 copychar:
84 *t = *h;
85 }
86 else
87 {
88 char c;
89 /* Do nothing if '%' is not followed by two hex digits. */
90 if (!h[1] || !h[2] || !(ISXDIGIT (h[1]) && ISXDIGIT (h[2])))
91 goto copychar;
92 c = X2DIGITS_TO_NUM (h[1], h[2]);
93 /* Don't unescape %00 because there is no way to insert it
94 into a C string without effectively truncating it. */
95 if (c == '\0')
96 goto copychar;
97 *t = c;
98 h += 2;
99 }
100 }
101 *t = '\0';
102 return copy;
103 }
104
105 /* The core of url_escape_* functions. Escapes the characters that
106 match the provided mask in urlchr_table.
107
108 If ALLOW_PASSTHROUGH is non-zero, a string with no unsafe chars
109 will be returned unchanged. If ALLOW_PASSTHROUGH is zero, a
110 freshly allocated string will be returned in all cases. */
111
112 static char *
113 url_escape_1 (const char *s, unsigned char mask, int allow_passthrough)
114 {
115 const char *p1;
116 char *p2, *newstr;
117 int newlen;
118 int addition = 0;
119
120 for (p1 = s; *p1; p1++)
121 if (urlchr_test (*p1, mask))
122 addition += 2; /* Two more characters (hex digits) */
123
124 if (!addition)
125 return allow_passthrough ? (char *)s : strdup (s);
126
127 newlen = (p1 - s) + addition;
128 newstr = (char *)malloc (newlen + 1);
129
130 p1 = s;
131 p2 = newstr;
132 while (*p1)
133 {
134 /* Quote the characters that match the test mask. */
135 if (urlchr_test (*p1, mask))
136 {
137 unsigned char c = *p1++;
138 *p2++ = '%';
139 *p2++ = XNUM_TO_DIGIT (c >> 4);
140 *p2++ = XNUM_TO_DIGIT (c & 0xf);
141 }
142 else
143 *p2++ = *p1++;
144 }
145 g_return_if_fail (p2 - newstr == newlen);
146 *p2 = '\0';
147
148 return newstr;
149 }
150
151 /* URL-escape the unsafe characters (see urlchr_table) in a given
152 string, returning a freshly allocated string. */
153
154 char *
155 xspf_url_encode (const char *s)
156 {
157 return url_escape_1 (s, urlchr_unsafe, 0);
158 }