Sync with sources on updates.
[privoxy.git] / encode.c
1 const char encode_rcs[] = "$Id: encode.c,v 1.7 2002/03/24 13:25:43 swa Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/encode.c,v $
5  *
6  * Purpose     :  Functions to encode and decode URLs, and also to
7  *                encode cookies and HTML text.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
10  *                Privoxy team. http://www.privoxy.org/
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and 
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it 
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: encode.c,v $
36  *    Revision 1.7  2002/03/24 13:25:43  swa
37  *    name change related issues
38  *
39  *    Revision 1.6  2002/03/13 00:27:04  jongfoster
40  *    Killing warnings
41  *
42  *    Revision 1.5  2002/03/07 03:46:53  oes
43  *    Fixed compiler warnings etc
44  *
45  *    Revision 1.4  2002/01/22 23:28:07  jongfoster
46  *    Adding convenience function html_encode_and_free_original()
47  *    Making all functions accept NULL paramaters - in this case, they
48  *    simply return NULL.  This allows error-checking to be deferred.
49  *
50  *    Revision 1.3  2001/11/13 00:16:40  jongfoster
51  *    Replacing references to malloc.h with the standard stdlib.h
52  *    (See ANSI or K&R 2nd Ed)
53  *
54  *    Revision 1.2  2001/05/17 22:52:35  oes
55  *     - Cleaned CRLF's from the sources and related files
56  *
57  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
58  *    Initial import of version 2.9.3 source tree
59  *
60  *
61  *********************************************************************/
62 \f
63
64 #include "config.h"
65
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69
70 #include "encode.h"
71
72 const char encode_h_rcs[] = ENCODE_H_VERSION;
73
74 /* Maps special characters in a URL to their equivalent % codes. */
75 static const char * const url_code_map[256] = {
76    NULL, "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09",
77    "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13",
78    "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D",
79    "%1E", "%1F", "+",   "%21", "%22", "%23", "%24", "%25", "%26", "%27",
80    "%28", "%29", NULL,  "%2B", "%2C", NULL,  NULL,  "%2F", NULL,  NULL,
81    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  "%3A", "%3B",
82    "%3C", "%3D", "%3E", "%3F", NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
83    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
84    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
85    NULL,  "%5B", "%5C", "%5D", "%5E", NULL,  "%60", NULL,  NULL,  NULL,
86    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
87    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
88    NULL,  NULL,  NULL,  "%7B", "%7C", "%7D", "%7E", "%7F", "%80", "%81",
89    "%82", "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8A", "%8B",
90    "%8C", "%8D", "%8E", "%8F", "%90", "%91", "%92", "%93", "%94", "%95",
91    "%96", "%97", "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
92    "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", "%A8", "%A9",
93    "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", "%B0", "%B1", "%B2", "%B3",
94    "%B4", "%B5", "%B6", "%B7", "%B8", "%B9", "%BA", "%BB", "%BC", "%BD",
95    "%BE", "%BF", "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
96    "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", "%D0", "%D1",
97    "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", "%D8", "%D9", "%DA", "%DB",
98    "%DC", "%DD", "%DE", "%DF", "%E0", "%E1", "%E2", "%E3", "%E4", "%E5",
99    "%E6", "%E7", "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
100    "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", "%F8", "%F9",
101    "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
102 };
103
104 /* Maps special characters in HTML to their equivalent entites. */
105 static const char * const html_code_map[256] = {
106    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
107    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
108    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
109    NULL, NULL, NULL, NULL,"&quot;",NULL,NULL,NULL,"&amp;",NULL,
110    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
111    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
112    "&lt;",NULL,"&gt;",NULL,NULL, NULL, NULL, NULL, NULL, NULL,
113    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
114    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
115    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
116    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
117    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
118    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
119    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
120    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
121    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
122    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
123    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
124    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
125    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
126    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
127    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
128    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
129    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
130    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
131    NULL, NULL, NULL, NULL, NULL, NULL
132 };
133
134 /* Maps special characters in a cookie to their equivalent % codes. */
135 static const char * const cookie_code_map[256] = {
136    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
137    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
138    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
139    NULL, NULL, "+",  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
140    NULL, NULL, NULL, NULL, "%2C",NULL, NULL, NULL, NULL, NULL,
141    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "%3B",
142    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
143    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
144    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
145    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
146    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
147    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
148    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
149    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
150    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
151    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
152    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
153    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
154    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
155    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
156    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
157    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
158    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
159    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
160    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
161    NULL, NULL, NULL, NULL, NULL, NULL
162 };
163
164
165 /*********************************************************************
166  *
167  * Function    :  html_encode
168  *
169  * Description :  Encodes a string so it's not interpreted as
170  *                containing HTML tags or entities.
171  *                Replaces <, >, &, and " with the appropriate HTML
172  *                entities.
173  *
174  * Parameters  :
175  *          1  :  s = String to encode.  Null-terminated.
176  *
177  * Returns     :  Encoded string, newly allocated on the heap. 
178  *                Caller is responsible for freeing it with free().
179  *                If s is NULL, or on out-of memory, returns NULL.
180  *
181  *********************************************************************/
182 char * html_encode(const char *s)
183 {
184    char * buf;
185    
186    if (s == NULL)
187    {
188       return NULL;
189    }
190
191    /* each input char can expand to at most 6 chars */
192    buf = (char *) malloc((strlen(s) * 6) + 1);
193
194    if (buf)
195    {
196       char c;
197       char * p = buf;
198       while ( (c = *s++) != '\0')
199       {
200          const char * replace_with = html_code_map[(unsigned char) c];
201          if(replace_with != NULL)
202          {
203             strcpy(p, replace_with);
204             p += strlen(replace_with);
205          }
206          else
207          {
208             *p++ = c;
209          }
210       }
211
212       *p = '\0';
213    }
214
215    return(buf);
216 }
217
218
219 /*********************************************************************
220  *
221  * Function    :  html_encode_and_free_original
222  *
223  * Description :  Encodes a string so it's not interpreted as
224  *                containing HTML tags or entities.
225  *                Replaces <, >, &, and " with the appropriate HTML
226  *                entities.  Free()s original string.
227  *                If original string is NULL, simply returns NULL.
228  *
229  * Parameters  :
230  *          1  :  s = String to encode.  Null-terminated.
231  *
232  * Returns     :  Encoded string, newly allocated on the heap. 
233  *                Caller is responsible for freeing it with free().
234  *                If s is NULL, or on out-of memory, returns NULL.
235  *
236  *********************************************************************/
237 char * html_encode_and_free_original(char *s)
238 {
239    char * result;
240    
241    if (s == NULL)
242    {
243       return NULL;
244    }
245
246    result = html_encode(s);
247    free(s);
248
249    return result;
250 }
251
252
253 /*********************************************************************
254  *
255  * Function    :  cookie_encode
256  *
257  * Description :  Encodes a string so it can be used in a cookie.
258  *                Replaces " ", ",", and ";" with the appropriate
259  *                codes.
260  *
261  * Parameters  :
262  *          1  :  s = String to encode.  Null-terminated.
263  *
264  * Returns     :  Encoded string, newly allocated on the heap. 
265  *                Caller is responsible for freeing it with free().
266  *                If s is NULL, or on out-of memory, returns NULL.
267  *
268  *********************************************************************/
269 char * cookie_encode(const char *s)
270 {
271    char * buf;
272
273    if (s == NULL)
274    {
275       return NULL;
276    }
277
278    /* each input char can expand to at most 3 chars */
279    buf = (char *) malloc((strlen(s) * 3) + 1);
280
281    if (buf)
282    {
283       char c;
284       char * p = buf;
285       while ( (c = *s++) != '\0')
286       {
287          const char * replace_with = cookie_code_map[(unsigned char) c];
288          if (replace_with != NULL)
289          {
290             strcpy(p, replace_with);
291             p += strlen(replace_with);
292          }
293          else
294          {
295             *p++ = c;
296          }
297       }
298
299       *p = '\0';
300    }
301
302    return(buf);
303 }
304
305 /*********************************************************************
306  *
307  * Function    :  url_encode
308  *
309  * Description :  Encodes a string so it can be used in a URL
310  *                query string.  Replaces special characters with
311  *                the appropriate %xx codes.
312  *
313  * Parameters  :
314  *          1  :  s = String to encode.  Null-terminated.
315  *
316  * Returns     :  Encoded string, newly allocated on the heap. 
317  *                Caller is responsible for freeing it with free().
318  *                If s is NULL, or on out-of memory, returns NULL.
319  *
320  *********************************************************************/
321 char * url_encode(const char *s)
322 {
323    char * buf;
324
325    if (s == NULL)
326    {
327       return NULL;
328    }
329
330    /* each input char can expand to at most 3 chars */
331    buf = (char *) malloc((strlen(s) * 3) + 1);
332
333    if (buf)
334    {
335       char c;
336       char * p = buf;
337       while( (c = *s++) != '\0')
338       {
339          const char * replace_with = url_code_map[(unsigned char) c];
340          if (replace_with != NULL)
341          {
342             strcpy(p, replace_with);
343             p += strlen(replace_with);
344          }
345          else
346          {
347             *p++ = c;
348          }
349       }
350
351       *p = '\0';
352
353    }
354
355    return(buf);
356 }
357
358
359 /*********************************************************************
360  *
361  * Function    :  xdtoi
362  *
363  * Description :  Converts a single hex digit to an integer.
364  *
365  * Parameters  :
366  *          1  :  d = in the range of ['0'..'9', 'A'..'F', 'a'..'f']
367  *
368  * Returns     :  The integer value, or -1 for non-hex characters.
369  *
370  *********************************************************************/
371 static int xdtoi(const int d)
372 {
373    if ((d >= '0') && (d <= '9'))
374    {
375       return(d - '0');
376    }
377    else if ((d >= 'a') && (d <= 'f')) 
378    {
379       return(d - 'a' + 10);
380    }
381    else if ((d >= 'A') && (d <= 'F'))
382    {
383       return(d - 'A' + 10);
384    }
385    else
386    {
387       return(-1);
388    }
389 }
390
391
392 /*********************************************************************
393  *
394  * Function    :  xtoi
395  *
396  * Description :  Hex string to integer conversion.
397  *
398  * Parameters  :
399  *          1  :  s = a 2 digit hex string (e.g. "1f").  Only the
400  *                    first two characters will be looked at.
401  *
402  * Returns     :  The integer value, or 0 for non-hex strings.
403  *
404  *********************************************************************/
405 static int xtoi(const char *s)
406 {
407    int d1, d2;
408
409    d1 = xdtoi(*s);
410    if(d1 >= 0)
411    {
412       d2 = xdtoi(*(s+1));
413       if(d2 >= 0)
414       {
415          return (d1 << 4) + d2;
416       }
417    }
418
419    return 0;
420 }
421
422
423 /*********************************************************************
424  *
425  * Function    :  url_decode
426  *
427  * Description :  Decodes a URL query string, replacing %xx codes
428  *                with their decoded form.
429  *
430  * Parameters  :
431  *          1  :  s = String to decode.  Null-terminated.
432  *
433  * Returns     :  Decoded string, newly allocated on the heap. 
434  *                Caller is responsible for freeing it with free().
435  *
436  *********************************************************************/
437 char *url_decode(const char * s)
438 {
439    char *buf = malloc(strlen(s) + 1);
440    char *q = buf;
441
442    if (buf)
443    {
444       while (*s)
445       {
446          switch (*s)
447          {
448             case '+':
449                s++;
450                *q++ = ' ';
451                break;
452
453             case '%':
454                if ((*q = xtoi(s + 1)) != '\0')
455                {
456                   s += 3;
457                   q++;
458                }
459                else
460                {
461                   /* malformed, just use it */
462                   *q++ = *s++;
463                }
464                break;
465
466             default:
467                *q++ = *s++;
468                break;
469          }
470       }
471       *q = '\0';
472    }
473
474    return(buf);
475
476 }
477
478
479 /*
480   Local Variables:
481   tab-width: 3
482   end:
483 */